summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc4
-rw-r--r--sql/event_parse_data.cc2
-rw-r--r--sql/events.cc23
-rw-r--r--sql/field.cc1114
-rw-r--r--sql/field.h364
-rw-r--r--sql/field_conv.cc4
-rw-r--r--sql/filesort.cc29
-rw-r--r--sql/ha_partition.cc4
-rw-r--r--sql/handler.cc19
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc1092
-rw-r--r--sql/item.h1178
-rw-r--r--sql/item_buff.cc25
-rw-r--r--sql/item_cmpfunc.cc415
-rw-r--r--sql/item_cmpfunc.h67
-rw-r--r--sql/item_create.cc110
-rw-r--r--sql/item_create.h15
-rw-r--r--sql/item_func.cc344
-rw-r--r--sql/item_func.h319
-rw-r--r--sql/item_geofunc.cc2
-rw-r--r--sql/item_geofunc.h2
-rw-r--r--sql/item_jsonfunc.cc2
-rw-r--r--sql/item_row.cc4
-rw-r--r--sql/item_row.h28
-rw-r--r--sql/item_strfunc.cc24
-rw-r--r--sql/item_strfunc.h5
-rw-r--r--sql/item_subselect.cc44
-rw-r--r--sql/item_subselect.h21
-rw-r--r--sql/item_sum.cc94
-rw-r--r--sql/item_sum.h45
-rw-r--r--sql/item_timefunc.cc495
-rw-r--r--sql/item_timefunc.h533
-rw-r--r--sql/item_windowfunc.cc9
-rw-r--r--sql/item_xmlfunc.cc129
-rw-r--r--sql/log.cc36
-rw-r--r--sql/log_event.cc16
-rw-r--r--sql/my_decimal.cc48
-rw-r--r--sql/my_decimal.h134
-rw-r--r--sql/mysqld.cc375
-rw-r--r--sql/opt_range.cc520
-rw-r--r--sql/opt_subselect.cc962
-rw-r--r--sql/opt_subselect.h11
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/opt_table_elimination.cc6
-rw-r--r--sql/procedure.h10
-rw-r--r--sql/protocol.cc10
-rw-r--r--sql/rpl_mi.cc6
-rw-r--r--sql/rpl_record.cc8
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/sp.cc2
-rw-r--r--sql/sp_head.cc34
-rw-r--r--sql/sp_head.h6
-rw-r--r--sql/sp_rcontext.cc14
-rw-r--r--sql/sql_admin.cc18
-rw-r--r--sql/sql_alter.cc4
-rw-r--r--sql/sql_analyse.cc103
-rw-r--r--sql/sql_base.cc64
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_binlog.cc2
-rw-r--r--sql/sql_cache.cc11
-rw-r--r--sql/sql_class.cc23
-rw-r--r--sql/sql_class.h70
-rw-r--r--sql/sql_cte.cc26
-rw-r--r--sql/sql_cte.h26
-rw-r--r--sql/sql_delete.cc34
-rw-r--r--sql/sql_derived.cc214
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_handler.cc2
-rw-r--r--sql/sql_help.cc11
-rw-r--r--sql/sql_insert.cc73
-rw-r--r--sql/sql_lex.cc1649
-rw-r--r--sql/sql_lex.h394
-rw-r--r--sql/sql_list.h2
-rw-r--r--sql/sql_load.cc9
-rw-r--r--sql/sql_parse.cc123
-rw-r--r--sql/sql_partition.cc16
-rw-r--r--sql/sql_partition_admin.cc4
-rw-r--r--sql/sql_prepare.cc68
-rw-r--r--sql/sql_priv.h13
-rw-r--r--sql/sql_profile.cc4
-rw-r--r--sql/sql_repl.cc3
-rw-r--r--sql/sql_select.cc732
-rw-r--r--sql/sql_select.h28
-rw-r--r--sql/sql_sequence.cc4
-rw-r--r--sql/sql_show.cc43
-rw-r--r--sql/sql_signal.cc2
-rw-r--r--sql/sql_string.cc3
-rw-r--r--sql/sql_string.h11
-rw-r--r--sql/sql_table.cc46
-rw-r--r--sql/sql_time.cc156
-rw-r--r--sql/sql_time.h56
-rw-r--r--sql/sql_trigger.cc6
-rw-r--r--sql/sql_truncate.cc2
-rw-r--r--sql/sql_tvc.cc11
-rw-r--r--sql/sql_type.cc1607
-rw-r--r--sql/sql_type.h1355
-rw-r--r--sql/sql_union.cc10
-rw-r--r--sql/sql_update.cc65
-rw-r--r--sql/sql_view.cc46
-rw-r--r--sql/sql_yacc.yy2126
-rw-r--r--sql/sql_yacc_ora.yy2035
-rw-r--r--sql/structs.h53
-rw-r--r--sql/sys_vars.cc56
-rw-r--r--sql/table.cc656
-rw-r--r--sql/table.h28
-rw-r--r--sql/table_cache.cc2
-rw-r--r--sql/threadpool_win.cc63
-rw-r--r--sql/unireg.cc47
-rw-r--r--sql/unireg.h5
-rw-r--r--sql/wsrep_mysqld.cc4
111 files changed, 12509 insertions, 8494 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 86a710f87c6..02da3c31c3e 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -758,8 +758,8 @@ bool get_next_time(const Time_zone *time_zone, my_time_t *next,
if (seconds)
{
- longlong seconds_diff;
- long microsec_diff;
+ ulonglong seconds_diff;
+ ulong microsec_diff;
bool negative= calc_time_diff(&local_now, &local_start, 1,
&seconds_diff, &microsec_diff);
if (!negative)
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc
index b2ff80626db..d20d322d864 100644
--- a/sql/event_parse_data.cc
+++ b/sql/event_parse_data.cc
@@ -472,7 +472,7 @@ Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
{
char buff[120];
String str(buff,(uint32) sizeof(buff), system_charset_info);
- String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
+ String *str2= bad_item->is_fixed() ? bad_item->val_str(&str) : NULL;
my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL");
}
diff --git a/sql/events.cc b/sql/events.cc
index fcad115c199..af020d5240e 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -401,7 +401,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
my_message_sql(ER_STARTUP,
"Event Error: An error occurred while creating query "
"string, before writing it into binary log.",
- MYF(ME_NOREFRESH));
+ MYF(ME_ERROR_LOG));
ret= true;
}
else
@@ -824,12 +824,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
- DBUG_ASSERT(thd->lex->select_lex.db.str);
- if (!is_infoschema_db(&thd->lex->select_lex.db) && // There is no events in I_S
- check_access(thd, EVENT_ACL, thd->lex->select_lex.db.str,
+ DBUG_ASSERT(thd->lex->first_select_lex()->db.str);
+ if (!is_infoschema_db(&thd->lex->first_select_lex()->db) && // There is no events in I_S
+ check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db.str,
NULL, NULL, 0, 0))
DBUG_RETURN(1);
- db= normalize_db_name(thd->lex->select_lex.db.str, db_tmp, sizeof(db_tmp));
+ db= normalize_db_name(thd->lex->first_select_lex()->db.str,
+ db_tmp, sizeof(db_tmp));
}
ret= db_repository->fill_schema_events(thd, tables, db);
@@ -924,7 +925,7 @@ Events::init(THD *thd, bool opt_noacl_or_bootstrap)
my_message(ER_STARTUP,
"Event Scheduler: An error occurred when initializing "
"system tables. Disabling the Event Scheduler.",
- MYF(ME_NOREFRESH));
+ MYF(ME_ERROR_LOG));
/* Disable the scheduler since the system tables are not up to date */
opt_event_scheduler= EVENTS_OFF;
goto end;
@@ -946,7 +947,7 @@ Events::init(THD *thd, bool opt_noacl_or_bootstrap)
{
my_message_sql(ER_STARTUP,
"Event Scheduler: Error while loading from mysql.event table.",
- MYF(ME_NOREFRESH));
+ MYF(ME_ERROR_LOG));
res= TRUE; /* fatal error: request unireg_abort */
goto end;
}
@@ -1163,7 +1164,7 @@ Events::load_events_from_db(THD *thd)
{
my_message_sql(ER_STARTUP,
"Event Scheduler: Failed to open table mysql.event",
- MYF(ME_NOREFRESH));
+ MYF(ME_ERROR_LOG));
DBUG_RETURN(TRUE);
}
@@ -1189,7 +1190,7 @@ Events::load_events_from_db(THD *thd)
"Event Scheduler: "
"Error while loading events from mysql.event. "
"The table probably contains bad data or is corrupted",
- MYF(ME_NOREFRESH));
+ MYF(ME_ERROR_LOG));
delete et;
goto end;
}
@@ -1228,9 +1229,9 @@ Events::load_events_from_db(THD *thd)
}
my_printf_error(ER_STARTUP,
"Event Scheduler: Loaded %d event%s",
- MYF(ME_NOREFRESH |
+ MYF(ME_ERROR_LOG |
(global_system_variables.log_warnings) ?
- ME_JUST_INFO: 0),
+ ME_NOTE: 0),
count, (count == 1) ? "" : "s");
ret= FALSE;
diff --git a/sql/field.cc b/sql/field.cc
index 7eb277e23d8..743f12f3cc9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -62,8 +62,12 @@ const char field_separator=',';
#define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \
((ulong) ((1LL << MY_MIN(arg, 4) * 8) - 1))
-#define ASSERT_COLUMN_MARKED_FOR_READ DBUG_ASSERT(!table || (!table->read_set || bitmap_is_set(table->read_set, field_index)))
-#define ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED DBUG_ASSERT(is_stat_field || !table || (!table->write_set || bitmap_is_set(table->write_set, field_index) || (table->vcol_set && bitmap_is_set(table->vcol_set, field_index))))
+#define ASSERT_COLUMN_MARKED_FOR_READ \
+ DBUG_ASSERT(!table || !table->read_set || \
+ bitmap_is_set(table->read_set, field_index))
+#define ASSERT_COLUMN_MARKED_FOR_WRITE \
+ DBUG_ASSERT(is_stat_field || !table || !table->write_set || \
+ bitmap_is_set(table->write_set, field_index))
#define FLAGSTR(S,F) ((S) & (F) ? #F " " : "")
@@ -80,15 +84,14 @@ const int FIELDTYPE_LAST= 254;
const int FIELDTYPE_NUM= FIELDTYPE_TEAR_FROM + (FIELDTYPE_LAST -
FIELDTYPE_TEAR_TO);
-static inline int field_type2index (enum_field_types field_type)
+static inline int merge_type2index(enum_field_types merge_type)
{
- DBUG_ASSERT(real_type_to_type(field_type) < FIELDTYPE_TEAR_FROM ||
- real_type_to_type(field_type) > FIELDTYPE_TEAR_TO);
- DBUG_ASSERT(field_type <= FIELDTYPE_LAST);
- field_type= real_type_to_type(field_type);
- if (field_type < FIELDTYPE_TEAR_FROM)
- return field_type;
- return FIELDTYPE_TEAR_FROM + (field_type - FIELDTYPE_TEAR_TO) - 1;
+ DBUG_ASSERT(merge_type < FIELDTYPE_TEAR_FROM ||
+ merge_type > FIELDTYPE_TEAR_TO);
+ DBUG_ASSERT(merge_type <= FIELDTYPE_LAST);
+ if (merge_type < FIELDTYPE_TEAR_FROM)
+ return merge_type;
+ return FIELDTYPE_TEAR_FROM + (merge_type - FIELDTYPE_TEAR_TO) - 1;
}
@@ -913,31 +916,37 @@ static enum_field_types field_types_merge_rules [FIELDTYPE_NUM][FIELDTYPE_NUM]=
}
};
-/**
- Return type of which can carry value of both given types in UNION result.
-
- @param a type for merging
- @param b type for merging
-
- @return
- type of field
-*/
-
-enum_field_types Field::field_type_merge(enum_field_types a,
- enum_field_types b)
-{
- return field_types_merge_rules[field_type2index(a)]
- [field_type2index(b)];
-}
const Type_handler *
Type_handler::aggregate_for_result_traditional(const Type_handler *a,
const Type_handler *b)
{
- enum_field_types ta= a->real_field_type();
- enum_field_types tb= b->real_field_type();
- return
- Type_handler::get_handler_by_real_type(Field::field_type_merge(ta, tb));
+ if (a == b)
+ {
+ /*
+ If two traditional handlers are equal, quickly return "a".
+ Some handlers (e.g. Type_handler_bool) pretend to be traditional,
+ but in fact they are not traditional in full extent, they are
+ only sub-types for now (and don't have a corresponding Field_xxx yet).
+ Here we preserve such handlers during aggregation.
+ As a result, COALESCE(true,true) preserves the "boolean" data type.
+
+ Need to do this conversion for deprecated data types,
+ similar to what field_type_merge_rules[][] does.
+ */
+ switch (a->field_type()) {
+ case MYSQL_TYPE_DECIMAL: return &type_handler_newdecimal;
+ case MYSQL_TYPE_DATE: return &type_handler_newdate;
+ case MYSQL_TYPE_VAR_STRING: return &type_handler_varchar;
+ default: break;
+ }
+ return a;
+ }
+ enum_field_types ta= a->traditional_merge_field_type();
+ enum_field_types tb= b->traditional_merge_field_type();
+ enum_field_types res= field_types_merge_rules[merge_type2index(ta)]
+ [merge_type2index(tb)];
+ return Type_handler::get_handler_by_real_type(res);
}
@@ -1924,14 +1933,6 @@ Field::unpack(uchar* to, const uchar *from, const uchar *from_end,
}
-my_decimal *Field::val_decimal(my_decimal *decimal)
-{
- /* This never have to be called */
- DBUG_ASSERT(0);
- return 0;
-}
-
-
void Field_num::add_zerofill_and_unsigned(String &res) const
{
if (unsigned_flag)
@@ -2033,7 +2034,7 @@ longlong Field::convert_decimal2longlong(const my_decimal *val,
int Field_int::store_decimal(const my_decimal *val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
return MY_TEST(err | store(i, unsigned_flag));
@@ -2201,7 +2202,7 @@ void Field_num::make_send_field(Send_field *field)
int Field_str::store_decimal(const my_decimal *d)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
double val;
/* TODO: use decimal2string? */
int err= warn_if_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
@@ -2273,7 +2274,7 @@ bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
int Field::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[MAX_DATE_STRING_REP_LENGTH];
uint length= (uint) my_TIME_to_str(ltime, buff, dec);
/* Avoid conversion when field character set is ASCII compatible */
@@ -2331,6 +2332,36 @@ Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
}
+/**
+ Create field for temporary table from given field.
+
+ @param thd Thread handler
+ @param table Temporary table
+ @param maybe_null_arg If the result field should be NULL-able,
+ even if the original field is NOT NULL, e.g. for:
+ - OUTER JOIN fields
+ - WITH ROLLUP fields
+ - arguments of aggregate functions, e.g. SUM(column1)
+ @retval NULL, on error
+ @retval pointer to the new field created, on success.
+*/
+
+Field *Field::create_tmp_field(MEM_ROOT *mem_root, TABLE *new_table,
+ bool maybe_null_arg)
+{
+ Field *new_field;
+
+ if ((new_field= make_new_field(mem_root, new_table, new_table == table)))
+ {
+ new_field->init_for_tmp_table(this, new_table);
+ new_field->flags|= flags & NO_DEFAULT_VALUE_FLAG;
+ if (maybe_null_arg)
+ new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
+ }
+ return new_field;
+}
+
+
/* This is used to generate a field in TABLE from TABLE_SHARE */
Field *Field::clone(MEM_ROOT *root, TABLE *new_table)
@@ -2500,7 +2531,7 @@ void Field_decimal::overflow(bool negative)
int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
const uchar *from= (uchar*) from_arg;
@@ -2866,7 +2897,7 @@ int Field_decimal::store(const char *from_arg, size_t len, CHARSET_INFO *cs)
int Field_decimal::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (unsigned_flag && nr < 0)
{
overflow(1);
@@ -2904,7 +2935,7 @@ int Field_decimal::store(double nr)
int Field_decimal::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[22];
uint length, int_part;
char fyllchar;
@@ -3131,7 +3162,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
Otherwise sets maximal number that can be stored in the field.
@param decimal_value my_decimal
- @param [OUT] native_error the error returned by my_decimal2binary().
+ @param [OUT] native_error the error returned by my_decimal::to_binary().
@retval
0 ok
@@ -3142,7 +3173,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool Field_new_decimal::store_value(const my_decimal *decimal_value,
int *native_error)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
DBUG_ENTER("Field_new_decimal::store_value");
#ifndef DBUG_OFF
@@ -3169,8 +3200,8 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value,
}
#endif
- *native_error= my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
- decimal_value, ptr, precision, dec);
+ *native_error= decimal_value->to_binary(ptr, precision, dec,
+ E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW);
if (unlikely(*native_error == E_DEC_OVERFLOW))
{
@@ -3178,7 +3209,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value,
DBUG_PRINT("info", ("overflow"));
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
set_value_on_overflow(&buff, decimal_value->sign());
- my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
+ buff.to_binary(ptr, precision, dec);
error= 1;
}
DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (uchar *) ptr,
@@ -3200,7 +3231,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
int Field_new_decimal::store(const char *from, size_t length,
CHARSET_INFO *charset_arg)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
THD *thd= get_thd();
DBUG_ENTER("Field_new_decimal::store(char*)");
@@ -3284,7 +3315,7 @@ int Field_new_decimal::store(const char *from, size_t length,
int Field_new_decimal::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
THD *thd= get_thd();
@@ -3309,7 +3340,7 @@ int Field_new_decimal::store(double nr)
int Field_new_decimal::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
my_decimal decimal_value;
int err;
@@ -3331,7 +3362,7 @@ int Field_new_decimal::store(longlong nr, bool unsigned_val)
int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
return store_value(decimal_value);
}
@@ -3343,37 +3374,6 @@ int Field_new_decimal::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
}
-double Field_new_decimal::val_real(void)
-{
- ASSERT_COLUMN_MARKED_FOR_READ;
- double dbl;
- my_decimal decimal_value;
- my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
- return dbl;
-}
-
-
-longlong Field_new_decimal::val_int(void)
-{
- ASSERT_COLUMN_MARKED_FOR_READ;
- longlong i;
- my_decimal decimal_value;
- my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
- unsigned_flag, &i);
- return i;
-}
-
-
-ulonglong Field_new_decimal::val_uint(void)
-{
- ASSERT_COLUMN_MARKED_FOR_READ;
- longlong i;
- my_decimal decimal_value;
- my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), true, &i);
- return i;
-}
-
-
my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -3386,27 +3386,6 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
}
-String *Field_new_decimal::val_str(String *val_buffer,
- String *val_ptr __attribute__((unused)))
-{
- ASSERT_COLUMN_MARKED_FOR_READ;
- my_decimal decimal_value;
- uint fixed_precision= zerofill ? precision : 0;
- my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
- fixed_precision, dec, '0', val_buffer);
- val_buffer->set_charset(&my_charset_numeric);
- return val_buffer;
-}
-
-
-bool Field_new_decimal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
-{
- my_decimal value;
- return decimal_to_datetime_with_warn(val_decimal(&value),
- ltime, fuzzydate, field_name.str);
-}
-
-
int Field_new_decimal::cmp(const uchar *a,const uchar*b)
{
return memcmp(a, b, bin_size);
@@ -3561,8 +3540,8 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx,
if (const_item->field_type() != MYSQL_TYPE_NEWDECIMAL ||
const_item->decimal_scale() != decimals())
{
- my_decimal *val, val_buffer, val_buffer2;
- if (!(val= const_item->val_decimal(&val_buffer)))
+ VDec val(const_item);
+ if (val.is_null())
{
DBUG_ASSERT(0);
return const_item;
@@ -3572,9 +3551,9 @@ Item *Field_new_decimal::get_equal_const_item(THD *thd, const Context &ctx,
See comments about truncation in the same place in
Field_time::get_equal_const_item().
*/
- my_decimal_round(E_DEC_FATAL_ERROR, val, decimals(), true, &val_buffer2);
- return new (thd->mem_root) Item_decimal(thd, field_name.str,
- &val_buffer2,
+ my_decimal tmp;
+ val.round_to(&tmp, decimals(), TRUNCATE);
+ return new (thd->mem_root) Item_decimal(thd, field_name.str, &tmp,
decimals(), field_length);
}
break;
@@ -3600,7 +3579,7 @@ int Field_int::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error;
longlong rnd;
@@ -3612,7 +3591,7 @@ int Field_tiny::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_tiny::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -3655,7 +3634,7 @@ int Field_tiny::store(double nr)
int Field_tiny::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -3760,7 +3739,7 @@ void Field_tiny::sql_type(String &res) const
int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int store_tmp;
int error;
longlong rnd;
@@ -3774,7 +3753,7 @@ int Field_short::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_short::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
nr=rint(nr);
@@ -3819,7 +3798,7 @@ int Field_short::store(double nr)
int Field_short::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int16 res;
@@ -3934,7 +3913,7 @@ void Field_short::sql_type(String &res) const
int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int store_tmp;
int error;
longlong rnd;
@@ -3948,7 +3927,7 @@ int Field_medium::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_medium::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
nr=rint(nr);
if (unsigned_flag)
@@ -3994,7 +3973,7 @@ int Field_medium::store(double nr)
int Field_medium::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unsigned_flag)
@@ -4132,7 +4111,7 @@ void Field_medium::sql_type(String &res) const
int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
long store_tmp;
int error;
longlong rnd;
@@ -4146,7 +4125,7 @@ int Field_long::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_long::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
nr=rint(nr);
@@ -4191,7 +4170,7 @@ int Field_long::store(double nr)
int Field_long::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
int32 res;
@@ -4305,7 +4284,7 @@ void Field_long::sql_type(String &res) const
int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
char *end;
ulonglong tmp;
@@ -4328,7 +4307,7 @@ int Field_longlong::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_longlong::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
Converter_double_to_longlong conv(nr, unsigned_flag);
if (unlikely(conv.error()))
@@ -4341,7 +4320,7 @@ int Field_longlong::store(double nr)
int Field_longlong::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if (unlikely(nr < 0)) // Only possible error
@@ -4452,7 +4431,7 @@ void Field_longlong::sql_type(String &res) const
void Field_longlong::set_max()
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
set_notnull();
int8store(ptr, unsigned_flag ? ULONGLONG_MAX : LONGLONG_MAX);
}
@@ -4489,7 +4468,7 @@ int Field_float::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_float::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= truncate_double(&nr, field_length,
not_fixed ? NOT_FIXED_DEC : dec,
unsigned_flag, FLT_MAX);
@@ -4668,7 +4647,7 @@ int Field_double::store(const char *from,size_t len,CHARSET_INFO *cs)
int Field_double::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= truncate_double(&nr, field_length,
not_fixed ? NOT_FIXED_DEC : dec,
unsigned_flag, DBL_MAX);
@@ -4814,13 +4793,6 @@ Converter_double_to_longlong::push_warning(THD *thd,
}
-int Field_real::store_decimal(const my_decimal *dm)
-{
- double dbl;
- my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl);
- return store(dbl);
-}
-
int Field_real::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg)
{
return store(TIME_to_double(ltime));
@@ -5048,58 +5020,55 @@ my_time_t Field_timestamp::get_timestamp(const uchar *pos,
}
-int Field_timestamp::store_TIME_with_warning(THD *thd, MYSQL_TIME *l_time,
- const ErrConv *str,
- int was_cut,
- bool have_smth_to_conv)
+int Field_timestamp::store_TIME_with_warning(THD *thd, const Datetime *dt,
+ const ErrConv *str, int was_cut)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
- uint error = 0;
- my_time_t timestamp;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ static const timeval zero= {0, (uint) 0 };
- if (MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) || !have_smth_to_conv)
- {
- error= 1;
- set_datetime_warning(WARN_DATA_TRUNCATED,
- str, MYSQL_TIMESTAMP_DATETIME, 1);
- }
- else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut))
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
{
- error= 3;
- set_datetime_warning(Sql_condition::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED,
- str, MYSQL_TIMESTAMP_DATETIME, 1);
+ set_datetime_warning(WARN_DATA_TRUNCATED, str, MYSQL_TIMESTAMP_DATETIME, 1);
+ store_TIMEVAL(zero);
+ return 1;
}
- /* Only convert a correct date (not a zero date) */
- if (have_smth_to_conv && l_time->month)
+
+ // Handle values that do not need DATETIME to TIMESTAMP conversion
+ if (!dt->get_mysql_time()->month)
{
- uint conversion_error;
- timestamp= TIME_to_timestamp(thd, l_time, &conversion_error);
- if (timestamp == 0 && l_time->second_part == 0)
- conversion_error= ER_WARN_DATA_OUT_OF_RANGE;
- if (unlikely(conversion_error))
- {
- set_datetime_warning(conversion_error,
- str, MYSQL_TIMESTAMP_DATETIME, !error);
- error= 1;
- }
+ /*
+ Zero date is allowed by the current sql_mode. Store zero timestamp.
+ Return success or a warning about non-fatal truncation, e.g.:
+ INSERT INTO t1 (ts) VALUES ('0000-00-00 00:00:00 some tail');
+ */
+ store_TIMEVAL(zero);
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATETIME);
}
- else
+
+ // Convert DATETIME to TIMESTAMP
+ uint conversion_error;
+ const MYSQL_TIME *l_time= dt->get_mysql_time();
+ my_time_t timestamp= TIME_to_timestamp(thd, l_time, &conversion_error);
+ if (timestamp == 0 && l_time->second_part == 0)
{
- timestamp= 0;
- l_time->second_part= 0;
+ set_datetime_warning(ER_WARN_DATA_OUT_OF_RANGE, str, MYSQL_TIMESTAMP_DATETIME, 1);
+ store_TIMEVAL(zero);
+ return 1; // date was fine but pointed to a DST gap
}
- store_TIME(timestamp, l_time->second_part);
- return error;
-}
+ // Adjust and store the value
+ store_TIMEVAL(Timeval(timestamp, l_time->second_part).trunc(decimals()));
-static bool
-copy_or_convert_to_datetime(THD *thd, const MYSQL_TIME *from, MYSQL_TIME *to)
-{
- if (from->time_type == MYSQL_TIMESTAMP_TIME)
- return time_to_datetime(thd, from, to);
- *to= *from;
- return false;
+ // Calculate return value and send warnings if needed
+ if (unlikely(conversion_error)) // e.g. DATETIME in the DST gap
+ {
+ set_datetime_warning(conversion_error, str, MYSQL_TIMESTAMP_DATETIME, 1);
+ return 1;
+ }
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATETIME);
}
@@ -5112,55 +5081,41 @@ sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
int Field_timestamp::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
- int unused;
+ int warn;
ErrConvTime str(ltime);
THD *thd= get_thd();
- MYSQL_TIME l_time;
- bool valid= !copy_or_convert_to_datetime(thd, ltime, &l_time) &&
- !check_date(&l_time, pack_time(&l_time) != 0,
- sql_mode_for_timestamp(thd), &unused);
- return store_TIME_with_warning(thd, &l_time, &str, false, valid);
+ Datetime dt(thd, &warn, ltime, sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, warn);
}
int Field_timestamp::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- MYSQL_TIME l_time;
- MYSQL_TIME_STATUS status;
- bool have_smth_to_conv;
ErrConvString str(from, len, cs);
THD *thd= get_thd();
-
- have_smth_to_conv= !str_to_datetime(cs, from, len, &l_time,
- sql_mode_for_timestamp(thd), &status);
- return store_TIME_with_warning(thd, &l_time, &str,
- status.warnings, have_smth_to_conv);
+ int error;
+ Datetime dt(&error, from, len, cs, sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
int Field_timestamp::store(double nr)
{
- MYSQL_TIME l_time;
int error;
ErrConvDouble str(nr);
THD *thd= get_thd();
-
- longlong tmp= double_to_datetime(nr, &l_time, sql_mode_for_timestamp(thd),
- &error);
- return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1);
+ Datetime dt(&error, nr, sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
int Field_timestamp::store(longlong nr, bool unsigned_val)
{
- MYSQL_TIME l_time;
int error;
ErrConvInteger str(nr, unsigned_val);
THD *thd= get_thd();
-
- longlong tmp= number_to_datetime(nr, 0, &l_time, sql_mode_for_timestamp(thd),
- &error);
- return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1);
+ Datetime dt(&error, nr, unsigned_val, sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
@@ -5422,10 +5377,10 @@ static longlong read_lowendian(const uchar *from, uint bytes)
}
}
-void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part)
+void Field_timestamp_hires::store_TIMEVAL(const timeval &tv)
{
- mi_int4store(ptr, timestamp);
- store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec));
+ mi_int4store(ptr, tv.tv_sec);
+ store_bigendian(sec_part_shift(tv.tv_usec, dec), ptr+4, sec_part_bytes(dec));
}
my_time_t Field_timestamp_hires::get_timestamp(const uchar *pos,
@@ -5456,23 +5411,11 @@ my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d)
int Field_timestamp::store_decimal(const my_decimal *d)
{
- ulonglong nr;
- ulong sec_part;
int error;
- MYSQL_TIME ltime;
- longlong tmp;
THD *thd= get_thd();
ErrConvDecimal str(d);
-
- if (my_decimal2seconds(d, &nr, &sec_part))
- {
- tmp= -1;
- error= 2;
- }
- else
- tmp= number_to_datetime(nr, sec_part, &ltime, sql_mode_for_timestamp(thd),
- &error);
- return store_TIME_with_warning(thd, &ltime, &str, error, tmp != -1);
+ Datetime dt(&error, d, sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
int Field_timestamp_with_dec::set_time()
@@ -5516,19 +5459,15 @@ void Field_timestamp_with_dec::make_send_field(Send_field *field)
** MySQL-5.6 compatible TIMESTAMP(N)
**************************************************************/
-void Field_timestampf::store_TIME(my_time_t timestamp, ulong sec_part)
+void Field_timestampf::store_TIMEVAL(const timeval &tm)
{
- struct timeval tm;
- tm.tv_sec= timestamp;
- tm.tv_usec= sec_part;
- my_timeval_trunc(&tm, dec);
my_timestamp_to_binary(&tm, ptr, dec);
}
void Field_timestampf::set_max()
{
DBUG_ENTER("Field_timestampf::set_max");
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
DBUG_ASSERT(dec == TIME_SECOND_PART_DIGITS);
set_notnull();
@@ -5596,107 +5535,78 @@ void Field_temporal::set_warnings(Sql_condition::enum_warning_level trunc_level,
3 Datetime value that was cut (warning level NOTE)
This is used by opt_range.cc:get_mm_leaf().
*/
-int Field_temporal_with_date::store_TIME_with_warning(MYSQL_TIME *ltime,
+int Field_temporal_with_date::store_TIME_with_warning(const Datetime *dt,
const ErrConv *str,
- int was_cut,
- int have_smth_to_conv)
+ int was_cut)
{
Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN;
- int ret= 2;
+ timestamp_type ts_type= type_handler()->mysql_timestamp_type();
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-
- if (was_cut == 0 && have_smth_to_conv == 0) // special case: zero date
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
{
- was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ static const Datetime zero;
+ store_TIME(zero.get_mysql_time());
+ if (was_cut == 0) // special case: zero date
+ {
+ set_warnings(trunc_level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type);
+ return 2;
+ }
+ set_warnings(trunc_level, str, MYSQL_TIME_WARN_TRUNCATED, ts_type);
+ return 1;
}
- else if (!have_smth_to_conv)
+ // Adjust and store the value
+ if (ts_type == MYSQL_TIMESTAMP_DATE)
{
- bzero(ltime, sizeof(*ltime));
- was_cut= MYSQL_TIME_WARN_TRUNCATED;
- ret= 1;
+ if (!dt->hhmmssff_is_zero())
+ was_cut|= MYSQL_TIME_NOTE_TRUNCATED;
+ store_TIME(dt->get_mysql_time());
}
- else if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) &&
- (MYSQL_TIME_WARN_HAVE_NOTES(was_cut) ||
- (type_handler()->mysql_timestamp_type() == MYSQL_TIMESTAMP_DATE &&
- (ltime->hour || ltime->minute || ltime->second || ltime->second_part))))
+ else if (dt->fraction_remainder(decimals()))
{
- trunc_level= Sql_condition::WARN_LEVEL_NOTE;
- was_cut|= MYSQL_TIME_WARN_TRUNCATED;
- ret= 3;
+ Datetime truncated(dt->trunc(decimals()));
+ store_TIME(truncated.get_mysql_time());
}
- set_warnings(trunc_level, str, was_cut,
- type_handler()->mysql_timestamp_type());
- store_TIME(ltime);
- return was_cut ? ret : 0;
+ else
+ store_TIME(dt->get_mysql_time());
+ // Caclulate return value and send warnings if needed
+ return store_TIME_return_code_with_warnings(was_cut, str, ts_type);
}
int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
{
- MYSQL_TIME ltime;
- MYSQL_TIME_STATUS status;
- THD *thd= get_thd();
+ int error;
ErrConvString str(from, len, cs);
- bool func_res= !str_to_datetime(cs, from, len, &ltime,
- sql_mode_for_dates(thd),
- &status);
- return store_TIME_with_warning(&ltime, &str, status.warnings, func_res);
+ Datetime dt(&error, from, len, cs, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
}
-
int Field_temporal_with_date::store(double nr)
{
- int error= 0;
- MYSQL_TIME ltime;
- THD *thd= get_thd();
+ int error;
ErrConvDouble str(nr);
-
- longlong tmp= double_to_datetime(nr, &ltime,
- (uint) sql_mode_for_dates(thd), &error);
- return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+ Datetime dt(&error, nr, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
}
int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
{
int error;
- MYSQL_TIME ltime;
- longlong tmp;
- THD *thd= get_thd();
ErrConvInteger str(nr, unsigned_val);
-
- tmp= number_to_datetime(nr, 0, &ltime, sql_mode_for_dates(thd), &error);
-
- return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+ Datetime dt(&error, nr, unsigned_val, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
}
-
int Field_temporal_with_date::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
- int error= 0, have_smth_to_conv= 1;
+ int error;
ErrConvTime str(ltime);
- MYSQL_TIME l_time;
-
- if (copy_or_convert_to_datetime(get_thd(), ltime, &l_time))
- {
- /*
- Set have_smth_to_conv and error in a way to have
- store_TIME_with_warning do bzero().
- */
- have_smth_to_conv= false;
- error= MYSQL_TIME_WARN_OUT_OF_RANGE;
- }
- else
- {
- /*
- We don't perform range checking here since values stored in TIME
- structure always fit into DATETIME range.
- */
- have_smth_to_conv= !check_date(&l_time, pack_time(&l_time) != 0,
- sql_mode_for_dates(get_thd()), &error);
- }
- return store_TIME_with_warning(&l_time, &str, error, have_smth_to_conv);
+ THD *thd= get_thd();
+ Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd));
+ return store_TIME_with_warning(&dt, &str, error);
}
@@ -5761,7 +5671,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
case ANY_SUBST:
if (!is_temporal_type_with_date(const_item->field_type()))
{
- Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES);
+ Datetime dt(thd, const_item, Datetime::comparison_flags_for_get_date());
if (!dt.is_valid_datetime())
return NULL;
return new (thd->mem_root)
@@ -5782,36 +5692,28 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
** In number context: HHMMSS
** Stored as a 3 byte unsigned int
****************************************************************************/
-int Field_time::store_TIME_with_warning(MYSQL_TIME *ltime,
- const ErrConv *str,
- int was_cut,
- int have_smth_to_conv)
+int Field_time::store_TIME_with_warning(const Time *t,
+ const ErrConv *str, int warn)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-
- if (!have_smth_to_conv)
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!t->is_valid_time())
{
- bzero(ltime, sizeof(*ltime));
- store_TIME(ltime);
+ static const Datetime zero;
+ store_TIME(zero.get_mysql_time());
set_warnings(Sql_condition::WARN_LEVEL_WARN, str, MYSQL_TIME_WARN_TRUNCATED);
return 1;
}
- if (ltime->year != 0 || ltime->month != 0)
- {
- ltime->year= ltime->month= ltime->day= 0;
- was_cut|= MYSQL_TIME_NOTE_TRUNCATED;
- }
- my_time_trunc(ltime, decimals());
- store_TIME(ltime);
- if (!MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut) &&
- MYSQL_TIME_WARN_HAVE_NOTES(was_cut))
+ // Adjust and store the value
+ if (t->fraction_remainder(decimals()))
{
- set_warnings(Sql_condition::WARN_LEVEL_NOTE, str,
- was_cut | MYSQL_TIME_WARN_TRUNCATED);
- return 3;
+ Time truncated(t->trunc(decimals()));
+ store_TIME(truncated.get_mysql_time());
}
- set_warnings(Sql_condition::WARN_LEVEL_WARN, str, was_cut);
- return was_cut ? 2 : 0;
+ else
+ store_TIME(t->get_mysql_time());
+ // Calculate return value and send warnings if needed
+ return store_TIME_return_code_with_warnings(warn, str, MYSQL_TIMESTAMP_TIME);
}
@@ -5828,88 +5730,37 @@ void Field_time::store_TIME(const MYSQL_TIME *ltime)
int Field_time::store(const char *from,size_t len,CHARSET_INFO *cs)
{
- MYSQL_TIME ltime;
- MYSQL_TIME_STATUS status;
ErrConvString str(from, len, cs);
- bool have_smth_to_conv=
- !str_to_time(cs, from, len, &ltime, sql_mode_for_dates(get_thd()),
- &status);
-
- return store_TIME_with_warning(&ltime, &str,
- status.warnings, have_smth_to_conv);
-}
-
-
-/**
- subtract a given number of days from DATETIME, return TIME
-
- optimized version of calc_time_diff()
-
- @note it might generate TIME values outside of the valid TIME range!
-*/
-static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days)
-{
- long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days;
- ltime->year= ltime->month= 0;
- if (daydiff >=0 )
- {
- ltime->day= daydiff;
- ltime->time_type= MYSQL_TIMESTAMP_TIME;
- }
- else
- {
- longlong timediff= ((((daydiff * 24LL +
- ltime->hour) * 60LL +
- ltime->minute) * 60LL +
- ltime->second) * 1000000LL +
- ltime->second_part);
- unpack_time(timediff, ltime, MYSQL_TIMESTAMP_TIME);
- }
+ int error;
+ Time tm(&error, from, len, cs, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&tm, &str, error);
}
int Field_time::store_time_dec(const MYSQL_TIME *ltime, uint dec)
{
- MYSQL_TIME l_time= *ltime;
ErrConvTime str(ltime);
- int was_cut= 0;
-
- if (curdays && l_time.time_type != MYSQL_TIMESTAMP_TIME)
- calc_datetime_days_diff(&l_time, curdays);
-
- int have_smth_to_conv= !check_time_range(&l_time, decimals(), &was_cut);
- return store_TIME_with_warning(&l_time, &str, was_cut, have_smth_to_conv);
+ int warn;
+ Time tm(&warn, ltime, curdays);
+ return store_TIME_with_warning(&tm, &str, warn);
}
int Field_time::store(double nr)
{
- MYSQL_TIME ltime;
ErrConvDouble str(nr);
int was_cut;
- bool neg= nr < 0;
- if (neg)
- nr= -nr;
- int have_smth_to_conv= !number_to_time(neg, (ulonglong) nr,
- (ulong)((nr - floor(nr)) * TIME_SECOND_PART_FACTOR),
- &ltime, &was_cut);
-
- return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+ Time tm(&was_cut, nr);
+ return store_TIME_with_warning(&tm, &str, was_cut);
}
int Field_time::store(longlong nr, bool unsigned_val)
{
- MYSQL_TIME ltime;
ErrConvInteger str(nr, unsigned_val);
int was_cut;
- if (nr < 0 && unsigned_val)
- nr= 99991231235959LL + 1;
- int have_smth_to_conv= !number_to_time(nr < 0,
- (ulonglong) (nr < 0 ? -nr : nr),
- 0, &ltime, &was_cut);
-
- return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+ Time tm(&was_cut, nr, unsigned_val);
+ return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -6064,16 +5915,10 @@ void Field_time_hires::store_TIME(const MYSQL_TIME *ltime)
int Field_time::store_decimal(const my_decimal *d)
{
- ulonglong nr;
- ulong sec_part;
ErrConvDecimal str(d);
- MYSQL_TIME ltime;
int was_cut;
- bool neg= my_decimal2seconds(d, &nr, &sec_part);
-
- int have_smth_to_conv= !number_to_time(neg, nr, sec_part, &ltime, &was_cut);
-
- return store_TIME_with_warning(&ltime, &str, was_cut, have_smth_to_conv);
+ Time tm(&was_cut, d);
+ return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -6113,14 +5958,28 @@ bool Field_time::can_be_substituted_to_equal_item(const Context &ctx,
Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
Item *const_item)
{
+ /*
+ Old mode conversion from DATETIME with non-zero YYYYMMDD part
+ to TIME works very inconsistently. Possible variants:
+ - truncate the YYYYMMDD part
+ - add (MM*33+DD)*24 to hours
+ - add (MM*31+DD)*24 to hours
+ Let's disallow propagation of DATETIME with non-zero YYYYMMDD
+ as an equal constant for a TIME field.
+ */
+ Time::datetime_to_time_mode_t mode=
+ (thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) ?
+ Time::DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY :
+ Time::DATETIME_TO_TIME_MINUS_CURRENT_DATE;
+
switch (ctx.subst_constraint()) {
case ANY_SUBST:
if (const_item->field_type() != MYSQL_TYPE_TIME)
{
- MYSQL_TIME ltime;
// Get the value of const_item with conversion from DATETIME to TIME
- ulonglong fuzzydate= Time::comparison_flags_for_get_date();
- if (const_item->get_time_with_conversion(thd, &ltime, fuzzydate))
+ Time tm(const_item,
+ Time::Options(Time::comparison_flags_for_get_date(), mode));
+ if (!tm.is_valid_time())
return NULL;
/*
Replace a DATE/DATETIME constant to a TIME constant:
@@ -6132,8 +5991,9 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
(assuming CURRENT_DATE is '2015-08-30'
*/
- return new (thd->mem_root) Item_time_literal(thd, &ltime,
- ltime.second_part ?
+ return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(),
+ tm.get_mysql_time()->
+ second_part ?
TIME_SECOND_PART_DIGITS :
0);
}
@@ -6142,8 +6002,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
if (const_item->field_type() != MYSQL_TYPE_TIME ||
const_item->decimals != decimals())
{
- MYSQL_TIME ltime;
- if (const_item->get_time_with_conversion(thd, &ltime, TIME_TIME_ONLY))
+ Time tm(const_item, Time::Options(TIME_TIME_ONLY, mode));
+ if (!tm.is_valid_time())
return NULL;
/*
Note, the value returned in "ltime" can have more fractional
@@ -6159,7 +6019,8 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx,
The optimized WHERE will return with "Impossible WHERE", without
having to do the full table scan.
*/
- return new (thd->mem_root) Item_time_literal(thd, &ltime, decimals());
+ return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(),
+ decimals());
}
break;
}
@@ -6253,7 +6114,7 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
int Field_year::store(const char *from, size_t len,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char *end;
int error;
longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
@@ -6301,7 +6162,7 @@ int Field_year::store(double nr)
int Field_year::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155)
{
*ptr= 0;
@@ -6395,7 +6256,7 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-void Field_date::store_TIME(MYSQL_TIME *ltime)
+void Field_date::store_TIME(const MYSQL_TIME *ltime)
{
uint tmp= ltime->year*10000L + ltime->month*100+ltime->day;
int4store(ptr,tmp);
@@ -6488,7 +6349,7 @@ void Field_date::sql_type(String &res) const
** In number context: YYYYMMDD
****************************************************************************/
-void Field_newdate::store_TIME(MYSQL_TIME *ltime)
+void Field_newdate::store_TIME(const MYSQL_TIME *ltime)
{
uint tmp= ltime->year*16*32 + ltime->month*32+ltime->day;
int3store(ptr,tmp);
@@ -6594,7 +6455,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
if (!is_temporal_type_with_date(const_item->field_type()))
{
// Get the value of const_item with conversion from TIME to DATETIME
- Datetime dt(thd, const_item, TIME_FUZZY_DATES | TIME_INVALID_DATES);
+ Datetime dt(thd, const_item, Datetime::comparison_flags_for_get_date());
if (!dt.is_valid_datetime())
return NULL;
/*
@@ -6639,7 +6500,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
-void Field_datetime::store_TIME(MYSQL_TIME *ltime)
+void Field_datetime::store_TIME(const MYSQL_TIME *ltime)
{
ulonglong tmp= TIME_to_ulonglong_datetime(ltime);
int8store(ptr,tmp);
@@ -6777,13 +6638,14 @@ int Field_datetime::set_time()
thd->variables.time_zone->gmt_sec_to_TIME(&now_time, thd->query_start());
now_time.second_part= thd->query_start_sec_part();
set_notnull();
+ my_time_trunc(&now_time, decimals());
store_TIME(&now_time);
thd->time_zone_used= 1;
return 0;
}
-void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
+void Field_datetime_hires::store_TIME(const MYSQL_TIME *ltime)
{
ulonglong packed= sec_part_shift(pack_time(ltime), dec);
store_bigendian(packed, ptr, Field_datetime_hires::pack_length());
@@ -6791,24 +6653,10 @@ void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
int Field_temporal_with_date::store_decimal(const my_decimal *d)
{
- ulonglong nr;
- ulong sec_part;
int error;
- MYSQL_TIME ltime;
- longlong tmp;
- THD *thd= get_thd();
ErrConvDecimal str(d);
-
- if (my_decimal2seconds(d, &nr, &sec_part))
- {
- tmp= -1;
- error= 2;
- }
- else
- tmp= number_to_datetime(nr, sec_part, &ltime, sql_mode_for_dates(thd),
- &error);
-
- return store_TIME_with_warning(&ltime, &str, error, tmp != -1);
+ Datetime tm(&error, d, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&tm, &str, error);
}
bool Field_datetime_with_dec::send_binary(Protocol *protocol)
@@ -6881,9 +6729,8 @@ int Field_datetimef::reset()
return 0;
}
-void Field_datetimef::store_TIME(MYSQL_TIME *ltime)
+void Field_datetimef::store_TIME(const MYSQL_TIME *ltime)
{
- my_time_trunc(ltime, decimals());
longlong tmp= TIME_to_longlong_datetime_packed(ltime);
my_datetime_packed_to_binary(tmp, ptr, dec);
}
@@ -6993,7 +6840,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint copy_length;
int rc;
@@ -7039,7 +6886,7 @@ int Field_str::store(longlong nr, bool unsigned_val)
int Field_str::store(double nr)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint local_char_length= MY_MIN(sizeof(buff),
field_length / field_charset->mbmaxlen);
@@ -7076,9 +6923,8 @@ uint Field_str::is_equal(Create_field *new_field)
int Field_longstr::store_decimal(const my_decimal *d)
{
- char buff[DECIMAL_MAX_STR_LENGTH+1];
- String str(buff, sizeof(buff), &my_charset_numeric);
- my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ StringBuffer<DECIMAL_MAX_STR_LENGTH+1> str;
+ d->to_string(&str);
return store(str.ptr(), str.length(), str.charset());
}
@@ -7295,11 +7141,12 @@ void Field_string::sql_type(String &res) const
size_t length;
length= cs->cset->snprintf(cs,(char*) res.ptr(),
- res.alloced_length(), "%s(%d)",
+ res.alloced_length(), "%s(%d)%s",
(type() == MYSQL_TYPE_VAR_STRING ?
(has_charset() ? "varchar" : "varbinary") :
(has_charset() ? "char" : "binary")),
- (int) field_length / charset()->mbmaxlen);
+ (int) field_length / charset()->mbmaxlen,
+ type() == MYSQL_TYPE_VAR_STRING ? "/*old*/" : "");
res.length(length);
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
has_charset() && (charset()->state & MY_CS_BINSORT))
@@ -7536,7 +7383,7 @@ int Field_varstring::save_field_metadata(uchar *metadata_ptr)
int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint copy_length;
int rc;
@@ -8073,7 +7920,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
int Field_varstring_compressed::store(const char *from, size_t length,
CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint compressed_length;
int rc= compress((char*) get_data(), field_length, from, (uint) length,
Field_varstring_compressed::max_display_length(),
@@ -8205,7 +8052,7 @@ int Field_blob::copy_value(Field_blob *from)
int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
size_t copy_length, new_length;
uint copy_len;
char *tmp;
@@ -8693,7 +8540,7 @@ uint Field_blob::is_equal(Create_field *new_field)
int Field_blob_compressed::store(const char *from, size_t length,
CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
uint compressed_length;
uint max_length= max_data_length();
uint to_length= (uint) MY_MIN(max_length,
@@ -9036,7 +8883,7 @@ void Field_enum::store_type(ulonglong value)
int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int err= 0;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
@@ -9088,7 +8935,7 @@ int Field_enum::store(double nr)
int Field_enum::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
if ((ulonglong) nr > typelib->count || nr == 0)
{
@@ -9219,7 +9066,7 @@ Field *Field_enum::make_new_field(MEM_ROOT *root, TABLE *new_table,
int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
bool got_warning= 0;
int err= 0;
char *not_used;
@@ -9259,7 +9106,7 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
int Field_set::store(longlong nr, bool unsigned_val)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int error= 0;
ulonglong max_nr;
@@ -9638,7 +9485,7 @@ uint Field_bit::is_equal(Create_field *new_field)
int Field_bit::store(const char *from, size_t length, CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
for (; length && !*from; from++, length--) // skip left 0's
@@ -10074,7 +9921,7 @@ Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg,
int Field_bit_as_char::store(const char *from, size_t length, CHARSET_INFO *cs)
{
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
uchar bits= (uchar) (field_length & 7);
@@ -10568,322 +10415,90 @@ uint pack_length_to_packflag(uint type)
}
-Field *make_field(TABLE_SHARE *share,
- MEM_ROOT *mem_root,
- uchar *ptr, uint32 field_length,
- uchar *null_pos, uchar null_bit,
- uint pack_flag,
- const Type_handler *handler,
- CHARSET_INFO *field_charset,
- Field::geometry_type geom_type, uint srid,
- Field::utype unireg_check,
- TYPELIB *interval,
- const LEX_CSTRING *field_name,
- uint32 flags)
+uint Column_definition_attributes::pack_flag_to_pack_length() const
{
- uchar *UNINIT_VAR(bit_ptr);
- uchar UNINIT_VAR(bit_offset);
+ uint type= f_packtype(pack_flag); // 0..15
+ DBUG_ASSERT(type < 16);
+ switch (type) {
+ case MYSQL_TYPE_TINY: return 1;
+ case MYSQL_TYPE_SHORT: return 2;
+ case MYSQL_TYPE_LONG: return 4;
+ case MYSQL_TYPE_LONGLONG: return 8;
+ case MYSQL_TYPE_INT24: return 3;
+ }
+ return 0; // This should not happen
+}
+
+Field *Column_definition_attributes::make_field(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const Record_addr *rec,
+ const Type_handler *handler,
+ const LEX_CSTRING *field_name,
+ uint32 flags)
+ const
+{
+ DBUG_ASSERT(length <= UINT_MAX32);
DBUG_PRINT("debug", ("field_type: %s, field_length: %u, interval: %p, pack_flag: %s%s%s%s%s",
- handler->name().ptr(), field_length, interval,
+ handler->name().ptr(), (uint) length, interval,
FLAGSTR(pack_flag, FIELDFLAG_BINARY),
FLAGSTR(pack_flag, FIELDFLAG_INTERVAL),
FLAGSTR(pack_flag, FIELDFLAG_NUMBER),
FLAGSTR(pack_flag, FIELDFLAG_PACK),
FLAGSTR(pack_flag, FIELDFLAG_BLOB)));
- if (handler == &type_handler_row)
- {
- DBUG_ASSERT(field_length == 0);
- DBUG_ASSERT(f_maybe_null(pack_flag));
- return new (mem_root) Field_row(ptr, field_name);
- }
-
- if (handler->real_field_type() == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
- {
- bit_ptr= null_pos;
- bit_offset= null_bit;
- if (f_maybe_null(pack_flag)) // if null field
- {
- bit_ptr+= (null_bit == 7); // shift bit_ptr and bit_offset
- bit_offset= (bit_offset + 1) & 7;
- }
- }
-
- if (!f_maybe_null(pack_flag))
- {
- null_pos=0;
- null_bit=0;
- }
- else
- {
- null_bit= ((uchar) 1) << null_bit;
- }
-
-
- if (f_is_alpha(pack_flag))
- {
- if (!f_is_packed(pack_flag))
- {
- enum_field_types field_type= handler->real_field_type();
- if (field_type == MYSQL_TYPE_STRING ||
- field_type == MYSQL_TYPE_DECIMAL || // 3.23 or 4.0 string
- field_type == MYSQL_TYPE_VAR_STRING)
- return new (mem_root)
- Field_string(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- field_charset);
- if (field_type == MYSQL_TYPE_VARCHAR)
- {
- if (unireg_check == Field::TMYSQL_COMPRESSED)
- return new (mem_root)
- Field_varstring_compressed(
- ptr, field_length,
- HA_VARCHAR_PACKLENGTH(field_length),
- null_pos, null_bit,
- unireg_check, field_name,
- share, field_charset, zlib_compression_method);
-
- return new (mem_root)
- Field_varstring(ptr,field_length,
- HA_VARCHAR_PACKLENGTH(field_length),
- null_pos,null_bit,
- unireg_check, field_name,
- share,
- field_charset);
- }
- return 0; // Error
- }
-
- // MYSQL_TYPE_VAR_STRING is handled above
- DBUG_ASSERT(f_packtype(pack_flag) != MYSQL_TYPE_VAR_STRING);
- const Type_handler *tmp;
- tmp= Type_handler::get_handler_by_real_type((enum_field_types)
- f_packtype(pack_flag));
- uint pack_length= tmp->calc_pack_length(field_length);
-
-#ifdef HAVE_SPATIAL
- if (f_is_geom(pack_flag))
- {
- status_var_increment(current_thd->status_var.feature_gis);
- return new (mem_root)
- Field_geom(ptr,null_pos,null_bit,
- unireg_check, field_name, share,
- pack_length, geom_type, srid);
- }
-#endif
- if (f_is_blob(pack_flag))
- {
- if (unireg_check == Field::TMYSQL_COMPRESSED)
- return new (mem_root)
- Field_blob_compressed(ptr, null_pos, null_bit,
- unireg_check, field_name, share,
- pack_length, field_charset, zlib_compression_method);
-
- return new (mem_root)
- Field_blob(ptr,null_pos,null_bit,
- unireg_check, field_name, share,
- pack_length, field_charset);
- }
- if (interval)
- {
- if (f_is_enum(pack_flag))
- return new (mem_root)
- Field_enum(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- pack_length, interval, field_charset);
- else
- return new (mem_root)
- Field_set(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- pack_length, interval, field_charset);
- }
- }
-
- switch (handler->real_field_type()) {
- case MYSQL_TYPE_DECIMAL:
- return new (mem_root)
- Field_decimal(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_decimals(pack_flag),
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_NEWDECIMAL:
- return new (mem_root)
- Field_new_decimal(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_decimals(pack_flag),
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_FLOAT:
- {
- int decimals= f_decimals(pack_flag);
- if (decimals == FLOATING_POINT_DECIMALS)
- decimals= NOT_FIXED_DEC;
- return new (mem_root)
- Field_float(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- decimals,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag)== 0);
- }
- case MYSQL_TYPE_DOUBLE:
- {
- int decimals= f_decimals(pack_flag);
- if (decimals == FLOATING_POINT_DECIMALS)
- decimals= NOT_FIXED_DEC;
- return new (mem_root)
- Field_double(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- decimals,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag)== 0);
- }
- case MYSQL_TYPE_TINY:
- return new (mem_root)
- Field_tiny(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_SHORT:
- return new (mem_root)
- Field_short(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_INT24:
- return new (mem_root)
- Field_medium(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_LONG:
- return new (mem_root)
- Field_long(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- case MYSQL_TYPE_LONGLONG:
- if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
- {
- return new (mem_root)
- Field_vers_trx_id(ptr, field_length, null_pos, null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- }
- else
- {
- return new (mem_root)
- Field_longlong(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name,
- f_is_zerofill(pack_flag) != 0,
- f_is_dec(pack_flag) == 0);
- }
- case MYSQL_TYPE_TIMESTAMP:
- {
- uint dec= field_length > MAX_DATETIME_WIDTH ?
- field_length - MAX_DATETIME_WIDTH - 1: 0;
- return new_Field_timestamp(mem_root, ptr, null_pos, null_bit, unireg_check,
- field_name, share, dec);
- }
- case MYSQL_TYPE_TIMESTAMP2:
- {
- uint dec= field_length > MAX_DATETIME_WIDTH ?
- field_length - MAX_DATETIME_WIDTH - 1: 0;
- return new (mem_root)
- Field_timestampf(ptr, null_pos, null_bit, unireg_check,
- field_name, share, dec);
- }
- case MYSQL_TYPE_YEAR:
- return new (mem_root)
- Field_year(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name);
- case MYSQL_TYPE_DATE:
- return new (mem_root)
- Field_date(ptr,null_pos,null_bit,
- unireg_check, field_name);
- case MYSQL_TYPE_NEWDATE:
- return new (mem_root)
- Field_newdate(ptr,null_pos,null_bit,
- unireg_check, field_name);
- case MYSQL_TYPE_TIME:
- {
- uint dec= field_length > MIN_TIME_WIDTH ?
- field_length - MIN_TIME_WIDTH - 1: 0;
- return new_Field_time(mem_root, ptr, null_pos, null_bit, unireg_check,
- field_name, dec);
- }
- case MYSQL_TYPE_TIME2:
- {
- uint dec= field_length > MIN_TIME_WIDTH ?
- field_length - MIN_TIME_WIDTH - 1: 0;
- return new (mem_root)
- Field_timef(ptr, null_pos, null_bit, unireg_check,
- field_name, dec);
- }
- case MYSQL_TYPE_DATETIME:
- {
- uint dec= field_length > MAX_DATETIME_WIDTH ?
- field_length - MAX_DATETIME_WIDTH - 1: 0;
- return new_Field_datetime(mem_root, ptr, null_pos, null_bit, unireg_check,
- field_name, dec);
- }
- case MYSQL_TYPE_DATETIME2:
- {
- uint dec= field_length > MAX_DATETIME_WIDTH ?
- field_length - MAX_DATETIME_WIDTH - 1: 0;
- return new (mem_root)
- Field_datetimef(ptr, null_pos, null_bit, unireg_check,
- field_name, dec);
- }
- case MYSQL_TYPE_NULL:
- return new (mem_root)
- Field_null(ptr, field_length, unireg_check, field_name,
- field_charset);
- case MYSQL_TYPE_BIT:
- return (f_bit_as_char(pack_flag) ?
- new (mem_root)
- Field_bit_as_char(ptr, field_length, null_pos, null_bit,
- unireg_check, field_name) :
- new (mem_root)
- Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
- bit_offset, unireg_check, field_name));
-
- default: // Impossible (Wrong version)
- break;
- }
- return 0;
+ Record_addr addr(rec->ptr(), f_maybe_null(pack_flag) ? rec->null() :
+ Bit_addr());
+ /*
+ Special code for the BIT-alike data types
+ who store data bits together with NULL-bits.
+ */
+ Bit_addr bit(rec->null());
+ if (f_maybe_null(pack_flag))
+ bit.inc();
+ return handler->make_table_field_from_def(share, mem_root, field_name,
+ addr, bit, this, flags);
}
+
bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const
{
- return item->type() == Item::DATE_ITEM;
+ return item->is_of_type(Item::CONST_ITEM, TIME_RESULT);
}
+Column_definition_attributes::Column_definition_attributes(const Field *field)
+ :length(field->character_octet_length() / field->charset()->mbmaxlen),
+ unireg_check(field->unireg_check),
+ interval(NULL),
+ charset(field->charset()), // May be NULL ptr
+ srid(0),
+ geom_type(Field::GEOM_GEOMETRY),
+ pack_flag(0)
+{}
+
+
/** Create a field suitable for create of table. */
Column_definition::Column_definition(THD *thd, Field *old_field,
Field *orig_field)
+ :Column_definition_attributes(old_field)
{
on_update= NULL;
field_name= old_field->field_name;
- length= old_field->field_length;
flags= old_field->flags;
- unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
key_length= old_field->key_length();
set_handler(old_field->type_handler());
- charset= old_field->charset(); // May be NULL ptr
comment= old_field->comment;
decimals= old_field->decimals();
vcol_info= old_field->vcol_info;
option_list= old_field->option_list;
- pack_flag= 0;
compression_method_ptr= 0;
versioning= VERSIONING_NOT_SET;
invisible= old_field->invisible;
+ interval_list.empty(); // prepare_interval_field() needs this
+ char_length= (uint) length;
if (orig_field)
{
@@ -10901,66 +10516,9 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
check_constraint= 0;
}
- switch (real_field_type()) {
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- length/= charset->mbmaxlen;
- key_length/= charset->mbmaxlen;
- break;
- case MYSQL_TYPE_STRING:
- /* Change CHAR -> VARCHAR if dynamic record length */
- if (old_field->type() == MYSQL_TYPE_VAR_STRING)
- set_handler(&type_handler_varchar);
- /* fall through */
-
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- /* This is corrected in create_length_to_internal_length */
- length= (length+charset->mbmaxlen-1) / charset->mbmaxlen -
- MY_TEST(old_field->compression_method());
- break;
-#ifdef HAVE_SPATIAL
- case MYSQL_TYPE_GEOMETRY:
- geom_type= ((Field_geom*)old_field)->geom_type;
- srid= ((Field_geom*)old_field)->srid;
- break;
-#endif
- case MYSQL_TYPE_YEAR:
- if (length != 4)
- {
- char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
- my_snprintf(buff, sizeof(buff), "YEAR(%llu)", length);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_WARN_DEPRECATED_SYNTAX,
- ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
- buff, "YEAR(4)");
- }
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- /*
- Floating points are stored with FLOATING_POINT_DECIMALS but internally
- in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS.
- */
- if (decimals >= FLOATING_POINT_DECIMALS)
- decimals= NOT_FIXED_DEC;
- break;
- default:
- break;
- }
-
- if (flags & (ENUM_FLAG | SET_FLAG))
- interval= ((Field_enum*) old_field)->typelib;
- else
- interval=0;
+ type_handler()->Column_definition_reuse_fix_attributes(thd, this, old_field);
- interval_list.empty(); // prepare_interval_field() needs this
-
- char_length= (uint)length;
+ type_handler()->Column_definition_implicit_upgrade(this);
/*
Copy the default (constant/function) from the column object orig_field, if
@@ -11042,11 +10600,11 @@ Column_definition::redefine_stage1_common(const Column_definition *dup_field,
uint32 Field_blob::char_length() const
{
- return Field_blob::octet_length();
+ return Field_blob::character_octet_length();
}
-uint32 Field_blob::octet_length() const
+uint32 Field_blob::character_octet_length() const
{
switch (packlength)
{
diff --git a/sql/field.h b/sql/field.h
index 2037802df9a..ed61afe01eb 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -48,6 +48,9 @@ class Item_equal;
class Virtual_tmp_table;
class Qualified_column_ident;
class Table_ident;
+class SEL_ARG;
+class RANGE_OPT_PARAM;
+struct KEY_PART;
enum enum_check_fields
{
@@ -467,31 +470,6 @@ inline bool is_temporal_type_with_date(enum_field_types type)
}
-/**
- Convert temporal real types as retuned by field->real_type()
- to field type as returned by field->type().
-
- @param real_type Real type.
- @retval Field type.
-*/
-inline enum_field_types real_type_to_type(enum_field_types real_type)
-{
- switch (real_type)
- {
- case MYSQL_TYPE_TIME2:
- return MYSQL_TYPE_TIME;
- case MYSQL_TYPE_DATETIME2:
- return MYSQL_TYPE_DATETIME;
- case MYSQL_TYPE_TIMESTAMP2:
- return MYSQL_TYPE_TIMESTAMP;
- case MYSQL_TYPE_NEWDATE:
- return MYSQL_TYPE_DATE;
- /* Note: NEWDECIMAL is a type, not only a real_type */
- default: return real_type;
- }
-}
-
-
enum enum_vcol_info_type
{
VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
@@ -835,7 +813,7 @@ public:
return nr < 0 ? 0 : (ulonglong) nr;
}
virtual bool val_bool(void)= 0;
- virtual my_decimal *val_decimal(my_decimal *);
+ virtual my_decimal *val_decimal(my_decimal *)=0;
inline String *val_str(String *str) { return val_str(str, str); }
/*
val_str(buf1, buf2) gets two buffers and should use them as follows:
@@ -872,6 +850,10 @@ public:
to be quoted when used in constructing an SQL query.
*/
virtual bool str_needs_quotes() { return FALSE; }
+ const Type_handler *type_handler_for_comparison() const
+ {
+ return type_handler()->type_handler_for_comparison();
+ }
Item_result result_type () const
{
return type_handler()->result_type();
@@ -880,7 +862,6 @@ public:
{
return type_handler()->cmp_type();
}
- static enum_field_types field_type_merge(enum_field_types, enum_field_types);
virtual bool eq(Field *field)
{
return (ptr == field->ptr && null_ptr == field->null_ptr &&
@@ -1245,6 +1226,12 @@ public:
virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
uchar *new_null_ptr, uint new_null_bit);
+ Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table,
+ bool maybe_null_arg);
+ Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table)
+ {
+ return create_tmp_field(root, new_table, maybe_null());
+ }
Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff,
bool stat_flag= FALSE);
@@ -1395,6 +1382,59 @@ protected:
}
int warn_if_overflow(int op_result);
Copy_func *get_identical_copy_func() const;
+ bool can_optimize_scalar_range(const RANGE_OPT_PARAM *param,
+ const KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op,
+ const Item *value) const;
+ uchar *make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part);
+ SEL_ARG *get_mm_leaf_int(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value,
+ bool unsigned_field);
+ /*
+ Make a leaf tree for the cases when the value was stored
+ to the field exactly, without any truncation, rounding or adjustments.
+ For example, if we stored an INT value into an INT column,
+ and value->save_in_field_no_warnings() returned 0,
+ we know that the value was stored exactly.
+ */
+ SEL_ARG *stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op,
+ Item *value);
+ /*
+ Make a leaf tree for the cases when we don't know if
+ the value was stored to the field without any data loss,
+ or was modified to a smaller or a greater value.
+ Used for the data types whose methods Field::store*()
+ silently adjust the value. This is the most typical case.
+ */
+ SEL_ARG *stored_field_make_mm_leaf(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op, Item *value);
+ /*
+ Make a leaf tree when an INT value was stored into a field of INT type,
+ and some truncation happened. Tries to adjust the range search condition
+ when possible, e.g. "tinytint < 300" -> "tinyint <= 127".
+ Can also return SEL_ARG_IMPOSSIBLE(), and NULL (not sargable).
+ */
+ SEL_ARG *stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op,
+ Item *value,
+ bool unsigned_field);
+ /*
+ Make a leaf tree when some truncation happened during
+ value->save_in_field_no_warning(this), and we cannot yet adjust the range
+ search condition for the current combination of the field and the value
+ data types.
+ Returns SEL_ARG_IMPOSSIBLE() for "=" and "<=>".
+ Returns NULL (not sargable) for other comparison operations.
+ */
+ SEL_ARG *stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *prm,
+ scalar_comparison_op,
+ Item *value);
public:
void set_table_name(String *alias)
{
@@ -1405,6 +1445,19 @@ public:
orig_table= table= table_arg;
set_table_name(&table_arg->alias);
}
+ virtual void init_for_tmp_table(Field *org_field, TABLE *new_table)
+ {
+ init(new_table);
+ orig_table= org_field->orig_table;
+ vcol_info= 0;
+ cond_selectivity= 1.0;
+ next_equal_field= NULL;
+ option_list= NULL;
+ option_struct= NULL;
+ if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
+ org_field->type() == MYSQL_TYPE_VARCHAR)
+ new_table->s->db_create_options|= HA_OPTION_PACK_RECORD;
+ }
void init_for_make_new_field(TABLE *new_table_arg, TABLE *orig_table_arg)
{
init(new_table_arg);
@@ -1431,12 +1484,21 @@ public:
/* convert decimal to longlong with overflow check */
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err);
+ /*
+ Maximum number of bytes in character representation.
+ - For string types it is equal to the field capacity, in bytes.
+ - For non-string types it represents the longest possible string length
+ after conversion to string.
+ */
+ virtual uint32 character_octet_length() const
+ {
+ return field_length;
+ }
/* The max. number of characters */
virtual uint32 char_length() const
{
return field_length / charset()->mbmaxlen;
}
-
virtual geometry_type get_geometry_type()
{
/* shouldn't get here. */
@@ -1554,6 +1616,10 @@ public:
const Item *item,
bool is_eq_func) const;
+ virtual SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)= 0;
+
bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond,
const Item *item) const
{
@@ -1715,6 +1781,9 @@ public:
{
return pos_in_interval_val_real(min, max);
}
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value);
};
@@ -1752,6 +1821,7 @@ public:
enum Derivation derivation(void) const { return field_derivation; }
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_display_length() const { return field_length; }
+ uint32 character_octet_length() const { return field_length; }
uint32 char_length() const { return field_length / field_charset->mbmaxlen; }
Information_schema_character_attributes
information_schema_character_attributes() const
@@ -1771,6 +1841,9 @@ public:
return pos_in_interval_val_str(min, max, length_size());
}
bool test_if_equality_guarantees_uniqueness(const Item *const_item) const;
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value);
};
/* base class for Field_string, Field_varstring and Field_blob */
@@ -1883,7 +1956,7 @@ public:
return Field_num::memcpy_field_possible(from) &&
field_length >= from->field_length;
}
- int store_decimal(const my_decimal *);
+ int store_decimal(const my_decimal *dec) { return store(dec->to_double()); }
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
my_decimal *val_decimal(my_decimal *);
@@ -1966,8 +2039,8 @@ public:
}
int save_in_field(Field *to)
{
- my_decimal buff;
- return to->store_decimal(val_decimal(&buff));
+ my_decimal tmp(ptr, precision, dec);
+ return to->store_decimal(&tmp);
}
bool memcpy_field_possible(const Field *from) const
{
@@ -1983,17 +2056,33 @@ public:
int store(longlong nr, bool unsigned_val);
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
int store_decimal(const my_decimal *);
- double val_real(void);
- longlong val_int(void);
- ulonglong val_uint(void);
+ double val_real(void)
+ {
+ return my_decimal(ptr, precision, dec).to_double();
+ }
+ longlong val_int(void)
+ {
+ return my_decimal(ptr, precision, dec).to_longlong(unsigned_flag);
+ }
+ ulonglong val_uint(void)
+ {
+ return (ulonglong) my_decimal(ptr, precision, dec).to_longlong(true);
+ }
my_decimal *val_decimal(my_decimal *);
- String *val_str(String*, String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ String *val_str(String *val_buffer, String *val_ptr __attribute__((unused)))
+ {
+ uint fixed_precision= zerofill ? precision : 0;
+ return my_decimal(ptr, precision, dec).
+ to_string(val_buffer, fixed_precision, dec, '0');
+ }
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ {
+ return my_decimal(ptr, precision, dec).
+ to_datetime_with_warn(ltime, fuzzydate, field_name.str);
+ }
bool val_bool()
{
- my_decimal decimal_value;
- my_decimal *val= val_decimal(&decimal_value);
- return val ? !my_decimal_is_zero(val) : 0;
+ return my_decimal(ptr, precision, dec).to_bool();
}
int cmp(const uchar *, const uchar *);
void sort_string(uchar *buff, uint length);
@@ -2068,6 +2157,12 @@ public:
uint32 prec= type_limits_int()->precision();
return Information_schema_numeric_attributes(prec, 0);
}
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)
+ {
+ return get_mm_leaf_int(param, key_part, cond, op, value, unsigned_flag);
+ }
};
@@ -2416,6 +2511,11 @@ public:
if (dec_arg >= FLOATING_POINT_DECIMALS)
dec_arg= NOT_FIXED_DEC;
}
+ void init_for_tmp_table(Field *org_field, TABLE *new_table)
+ {
+ Field::init_for_tmp_table(org_field, new_table);
+ not_fixed= true;
+ }
const Type_handler *type_handler() const { return &type_handler_double; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2494,6 +2594,20 @@ class Field_temporal: public Field {
protected:
Item *get_equal_const_item_datetime(THD *thd, const Context &ctx,
Item *const_item);
+ int store_TIME_return_code_with_warnings(int warn, const ErrConv *str,
+ timestamp_type ts_type)
+ {
+ if (!MYSQL_TIME_WARN_HAVE_WARNINGS(warn) &&
+ MYSQL_TIME_WARN_HAVE_NOTES(warn))
+ {
+ set_warnings(Sql_condition::WARN_LEVEL_NOTE, str,
+ warn | MYSQL_TIME_WARN_TRUNCATED, ts_type);
+ return 3;
+ }
+ set_warnings(Sql_condition::WARN_LEVEL_WARN, str, warn, ts_type);
+ return warn ? 2 : 0;
+ }
+
public:
Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -2544,6 +2658,9 @@ public:
{
return true;
}
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value);
};
@@ -2556,9 +2673,10 @@ public:
*/
class Field_temporal_with_date: public Field_temporal {
protected:
- int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
- int was_cut, int have_smth_to_conv);
- virtual void store_TIME(MYSQL_TIME *ltime) = 0;
+ int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
+ int was_cut);
+ void store_TIME_with_trunc(const Time *);
+ virtual void store_TIME(const MYSQL_TIME *ltime) = 0;
virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos,
ulonglong fuzzydate) const = 0;
bool validate_MMDD(bool not_zero_date, uint month, uint day,
@@ -2590,8 +2708,12 @@ public:
class Field_timestamp :public Field_temporal {
protected:
sql_mode_t sql_mode_for_timestamp(THD *thd) const;
- int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *,
- int warnings, bool have_smth_to_conv);
+ int store_TIME_with_warning(THD *, const Datetime *,
+ const ErrConv *, int warn);
+ virtual void store_TIMEVAL(const timeval &tv)
+ {
+ int4store(ptr, tv.tv_sec);
+ }
public:
Field_timestamp(uchar *ptr_arg, uint32 len_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -2631,9 +2753,9 @@ public:
{
return get_timestamp(ptr, sec_part);
}
- virtual void store_TIME(my_time_t timestamp, ulong sec_part)
+ void store_TIME(my_time_t timestamp, ulong sec_part)
{
- int4store(ptr,timestamp);
+ store_TIMEVAL(Timeval(timestamp, sec_part).trunc(decimals()));
}
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
uchar *pack(uchar *to, const uchar *from,
@@ -2703,6 +2825,7 @@ class Field_timestamp_hires :public Field_timestamp_with_dec {
{
return Type_handler_timestamp::sec_part_bytes(dec);
}
+ void store_TIMEVAL(const timeval &tv);
public:
Field_timestamp_hires(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -2715,7 +2838,6 @@ public:
DBUG_ASSERT(dec);
}
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
- void store_TIME(my_time_t timestamp, ulong sec_part);
int cmp(const uchar *,const uchar *);
uint32 pack_length() const { return 4 + sec_part_bytes(dec); }
uint size_of() const { return sizeof(*this); }
@@ -2731,6 +2853,7 @@ class Field_timestampf :public Field_timestamp_with_dec {
*metadata_ptr= (uchar) decimals();
return 1;
}
+ void store_TIMEVAL(const timeval &tv);
public:
Field_timestampf(uchar *ptr_arg,
uchar *null_ptr_arg, uchar null_bit_arg,
@@ -2759,7 +2882,6 @@ public:
}
void set_max();
bool is_max();
- void store_TIME(my_time_t timestamp, ulong sec_part);
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
my_time_t get_timestamp(ulong *sec_part) const
{
@@ -2777,7 +2899,10 @@ public:
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, 1, 1)
{}
- const Type_handler *type_handler() const { return &type_handler_year; }
+ const Type_handler *type_handler() const
+ {
+ return field_length == 2 ? &type_handler_year2 : &type_handler_year;
+ }
Copy_func *get_copy_func(const Field *from) const
{
if (eq_def(from))
@@ -2824,14 +2949,31 @@ public:
};
-class Field_date :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
+class Field_date_common: public Field_temporal_with_date
+{
+public:
+ Field_date_common(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg,
+ const LEX_CSTRING *field_name_arg)
+ :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH,
+ null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
+ {}
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value);
+};
+
+
+class Field_date :public Field_date_common
+{
+ void store_TIME(const MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
- :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg) {}
+ :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg) {}
const Type_handler *type_handler() const { return &type_handler_date; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
@@ -2859,14 +3001,15 @@ public:
};
-class Field_newdate :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
+class Field_newdate :public Field_date_common
+{
+ void store_TIME(const MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
- :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg)
+ :Field_date_common(ptr_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg)
{}
const Type_handler *type_handler() const { return &type_handler_newdate; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
@@ -2895,8 +3038,7 @@ class Field_time :public Field_temporal {
long curdays;
protected:
virtual void store_TIME(const MYSQL_TIME *ltime);
- int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str,
- int was_cut, int have_smth_to_conv);
+ int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn);
void set_warnings(Sql_condition::enum_warning_level level,
const ErrConv *str, int was_cut)
{
@@ -3054,7 +3196,7 @@ public:
class Field_datetime :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
+ void store_TIME(const MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
@@ -3147,7 +3289,7 @@ public:
DATETIME(1..6)
*/
class Field_datetime_hires :public Field_datetime_with_dec {
- void store_TIME(MYSQL_TIME *ltime);
+ void store_TIME(const MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
public:
Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg,
@@ -3170,7 +3312,7 @@ public:
DATETIME(0..6) - MySQL56 version
*/
class Field_datetimef :public Field_datetime_with_dec {
- void store_TIME(MYSQL_TIME *ltime);
+ void store_TIME(const MYSQL_TIME *ltime);
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
int save_field_metadata(uchar *metadata_ptr)
{
@@ -3475,6 +3617,7 @@ private:
str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/"));
}
uint32 max_display_length() const { return field_length - 1; }
+ uint32 character_octet_length() const { return field_length - 1; }
uint32 char_length() const
{
return (field_length - 1) / field_charset->mbmaxlen;
@@ -3607,7 +3750,7 @@ public:
Information_schema_character_attributes
information_schema_character_attributes() const
{
- uint32 octets= Field_blob::octet_length();
+ uint32 octets= Field_blob::character_octet_length();
uint32 chars= octets / field_charset->mbminlen;
return Information_schema_character_attributes(octets, chars);
}
@@ -3773,7 +3916,7 @@ public:
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
uint32 max_display_length() const;
uint32 char_length() const;
- uint32 octet_length() const;
+ uint32 character_octet_length() const;
uint is_equal(Create_field *new_field);
friend void TABLE::remember_blob_values(String *blob_storage);
@@ -4181,6 +4324,12 @@ public:
}
void hash(ulong *nr, ulong *nr2);
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)
+ {
+ return get_mm_leaf_int(param, key_part, cond, op, value, true);
+ }
private:
virtual size_t do_last_null_byte() const;
int save_field_metadata(uchar *first_byte);
@@ -4225,21 +4374,53 @@ public:
extern const LEX_CSTRING null_clex_str;
-Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
- uchar *ptr, uint32 field_length,
- uchar *null_pos, uchar null_bit,
- uint pack_flag, const Type_handler *handler,
- CHARSET_INFO *cs,
- Field::geometry_type geom_type, uint srid,
- Field::utype unireg_check,
- TYPELIB *interval, const LEX_CSTRING *field_name,
- uint32 flags);
+class Column_definition_attributes
+{
+public:
+ /*
+ At various stages in execution this can be length of field in bytes or
+ max number of characters.
+ */
+ ulonglong length;
+ Field::utype unireg_check;
+ TYPELIB *interval; // Which interval to use
+ CHARSET_INFO *charset;
+ uint32 srid;
+ Field::geometry_type geom_type;
+ uint pack_flag;
+ Column_definition_attributes()
+ :length(0),
+ unireg_check(Field::NONE),
+ interval(NULL),
+ charset(&my_charset_bin),
+ srid(0),
+ geom_type(Field::GEOM_GEOMETRY),
+ pack_flag(0)
+ { }
+ Column_definition_attributes(const Field *field);
+ Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const Record_addr *rec,
+ const Type_handler *handler,
+ const LEX_CSTRING *field_name,
+ uint32 flags) const;
+ uint temporal_dec(uint intlen) const
+ {
+ return (uint) (length > intlen ? length - intlen - 1 : 0);
+ }
+ uint pack_flag_to_pack_length() const;
+ void frm_pack_basic(uchar *buff) const;
+ void frm_pack_charset(uchar *buff) const;
+ void frm_unpack_basic(const uchar *buff);
+ bool frm_unpack_charset(TABLE_SHARE *share, const uchar *buff);
+};
+
/*
Create field class for CREATE TABLE
*/
class Column_definition: public Sql_alloc,
- public Type_handler_hybrid_field_type
+ public Type_handler_hybrid_field_type,
+ public Column_definition_attributes
{
/**
Create "interval" from "interval_list".
@@ -4294,11 +4475,6 @@ public:
WITHOUT_VERSIONING
};
Item *on_update; // ON UPDATE NOW()
- /*
- At various stages in execution this can be length of field in bytes or
- max number of characters.
- */
- ulonglong length;
field_visibility_t invisible;
/*
The value of `length' as set by parser: is the number of characters
@@ -4306,15 +4482,9 @@ public:
*/
uint32 char_length;
uint decimals, flags, pack_length, key_length;
- Field::utype unireg_check;
- TYPELIB *interval; // Which interval to use
List<String> interval_list;
- CHARSET_INFO *charset;
- uint32 srid;
- Field::geometry_type geom_type;
engine_option_value *option_list;
- uint pack_flag;
/*
This is additinal data provided for any computed(virtual) field.
@@ -4332,11 +4502,9 @@ public:
:Type_handler_hybrid_field_type(&type_handler_null),
compression_method_ptr(0),
comment(null_clex_str),
- on_update(NULL), length(0), invisible(VISIBLE), decimals(0),
- flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE),
- interval(0), charset(&my_charset_bin),
- srid(0), geom_type(Field::GEOM_GEOMETRY),
- option_list(NULL), pack_flag(0),
+ on_update(NULL), invisible(VISIBLE), decimals(0),
+ flags(0), pack_length(0), key_length(0),
+ option_list(NULL),
vcol_info(0), default_value(0), check_constraint(0),
versioning(VERSIONING_NOT_SET)
{
@@ -4466,20 +4634,18 @@ public:
}
Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
- uchar *ptr, uchar *null_pos, uchar null_bit,
+ const Record_addr *addr,
const LEX_CSTRING *field_name_arg) const
{
- return ::make_field(share, mem_root, ptr,
- (uint32)length, null_pos, null_bit,
- pack_flag, type_handler(), charset,
- geom_type, srid, unireg_check, interval,
- field_name_arg, flags);
+ return Column_definition_attributes::make_field(share, mem_root, addr,
+ type_handler(),
+ field_name_arg, flags);
}
Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
const LEX_CSTRING *field_name_arg) const
{
- return make_field(share, mem_root, (uchar *) 0, (uchar *) "", 0,
- field_name_arg);
+ Record_addr addr(true);
+ return make_field(share, mem_root, &addr, field_name_arg);
}
/* Return true if default is an expression that must be saved explicitely */
bool has_default_expression();
@@ -4801,7 +4967,7 @@ bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
#define FIELDFLAG_DEC_SHIFT 8
#define FIELDFLAG_MAX_DEC 63U
-#define MTYP_TYPENR(type) (type & 127U) /* Remove bits from type */
+#define MTYP_TYPENR(type) ((type) & 127U) // Remove bits from type
#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL)
#define f_is_num(x) ((x) & FIELDFLAG_NUMBER)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 64d0bc6c452..f413dec82be 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -413,8 +413,8 @@ void Field::do_field_real(Copy_field *copy)
void Field::do_field_decimal(Copy_field *copy)
{
- my_decimal value;
- copy->to_field->store_decimal(copy->from_field->val_decimal(&value));
+ my_decimal value(copy->from_field);
+ copy->to_field->store_decimal(&value);
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index a4be9e4acfa..6901cee043f 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -258,7 +258,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort,
}
if (memory_available < min_sort_memory)
{
- my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR + ME_FATALERROR));
+ my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR_LOG + ME_FATAL));
goto err;
}
tracker->report_sort_buffer_size(sort->sort_buffer_size());
@@ -710,7 +710,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
uchar *ref_pos, *next_pos, ref_buff[MAX_REFLENGTH];
TABLE *sort_form;
handler *file;
- MY_BITMAP *save_read_set, *save_write_set, *save_vcol_set;
+ MY_BITMAP *save_read_set, *save_write_set;
Item *sort_cond;
ha_rows retval;
DBUG_ENTER("find_all_keys");
@@ -745,13 +745,11 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
/* Remember original bitmaps */
save_read_set= sort_form->read_set;
save_write_set= sort_form->write_set;
- save_vcol_set= sort_form->vcol_set;
/* Set up temporary column read map for columns used by sort */
DBUG_ASSERT(save_read_set != &sort_form->tmp_set);
bitmap_clear_all(&sort_form->tmp_set);
- sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set,
- &sort_form->tmp_set);
+ sort_form->column_bitmaps_set(&sort_form->tmp_set, &sort_form->tmp_set);
register_used_fields(param);
if (quick_select)
select->quick->add_used_key_part_to_set();
@@ -809,16 +807,12 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
*/
MY_BITMAP *tmp_read_set= sort_form->read_set;
MY_BITMAP *tmp_write_set= sort_form->write_set;
- MY_BITMAP *tmp_vcol_set= sort_form->vcol_set;
if (select->cond->with_subquery())
- sort_form->column_bitmaps_set(save_read_set, save_write_set,
- save_vcol_set);
+ sort_form->column_bitmaps_set(save_read_set, save_write_set);
write_record= (select->skip_record(thd) > 0);
if (select->cond->with_subquery())
- sort_form->column_bitmaps_set(tmp_read_set,
- tmp_write_set,
- tmp_vcol_set);
+ sort_form->column_bitmaps_set(tmp_read_set, tmp_write_set);
}
else
write_record= true;
@@ -864,7 +858,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
}
/* Signal we should use orignal column read and write maps */
- sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ sort_form->column_bitmaps_set(save_read_set, save_write_set);
if (unlikely(thd->is_error()))
DBUG_RETURN(HA_POS_ERROR);
@@ -872,8 +866,8 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
DBUG_PRINT("test",("error: %d indexpos: %d",error,indexpos));
if (unlikely(error != HA_ERR_END_OF_FILE))
{
- file->print_error(error,MYF(ME_ERROR | ME_WAITTANG)); // purecov: inspected
- DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ file->print_error(error,MYF(ME_ERROR_LOG));
+ DBUG_RETURN(HA_POS_ERROR);
}
if (indexpos && idx &&
write_keys(param, fs_info, idx, buffpek_pointers, tempfile))
@@ -885,7 +879,7 @@ static ha_rows find_all_keys(THD *thd, Sort_param *param, SQL_SELECT *select,
DBUG_RETURN(retval);
err:
- sort_form->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ sort_form->column_bitmaps_set(save_read_set, save_write_set);
DBUG_RETURN(HA_POS_ERROR);
} /* find_all_keys */
@@ -1122,9 +1116,8 @@ Type_handler_decimal_result::make_sort_key(uchar *to, Item *item,
}
*to++= 1;
}
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, to,
- item->max_length - (item->decimals ? 1 : 0),
- item->decimals);
+ dec_val->to_binary(to, item->max_length - (item->decimals ? 1 : 0),
+ item->decimals);
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 7e04cabc765..262e791ec7a 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -6809,7 +6809,7 @@ FT_INFO *ha_partition::ft_init_ext(uint flags, uint inx, String *key)
sizeof(FT_INFO *) * m_tot_parts,
NullS)))
{
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
DBUG_RETURN(NULL);
}
ft_target->part_ft_info= tmp_ft_info;
@@ -10648,8 +10648,6 @@ int ha_partition::check_misplaced_rows(uint read_part_id, bool do_repair)
{
/* Only need to read the partitioning fields. */
bitmap_union(table->read_set, &m_part_info->full_part_field_set);
- if (table->vcol_set)
- bitmap_union(table->vcol_set, &m_part_info->full_part_field_set);
}
if ((result= m_file[read_part_id]->ha_rnd_init(1)))
diff --git a/sql/handler.cc b/sql/handler.cc
index 306b0868d15..943722af3b3 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -295,7 +295,7 @@ handler *get_ha_partition(partition_info *part_info)
}
else
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR),
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL),
static_cast<int>(sizeof(ha_partition)));
}
DBUG_RETURN(((handler*) partition));
@@ -2543,7 +2543,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
dummy_share.table_name= *alias;
dummy_table.alias.set(alias->str, alias->length, table_alias_charset);
file->change_table_ptr(&dummy_table, &dummy_share);
- file->print_error(error, MYF(intercept ? ME_JUST_WARNING : 0));
+ file->print_error(error, MYF(intercept ? ME_WARNING : 0));
}
if (intercept)
error= 0;
@@ -3600,7 +3600,7 @@ void handler::print_error(int error, myf errflag)
if (ha_thd()->transaction_rollback_request)
{
/* Ensure this becomes a true error */
- errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO);
+ errflag&= ~(ME_WARNING | ME_NOTE);
}
int textno= -1; // impossible value
@@ -3735,14 +3735,14 @@ void handler::print_error(int error, myf errflag)
{
textno=ER_RECORD_FILE_FULL;
/* Write the error message to error log */
- errflag|= ME_NOREFRESH;
+ errflag|= ME_ERROR_LOG;
break;
}
case HA_ERR_INDEX_FILE_FULL:
{
textno=ER_INDEX_FILE_FULL;
/* Write the error message to error log */
- errflag|= ME_NOREFRESH;
+ errflag|= ME_ERROR_LOG;
break;
}
case HA_ERR_LOCK_WAIT_TIMEOUT:
@@ -3869,14 +3869,14 @@ void handler::print_error(int error, myf errflag)
if (unlikely(fatal_error))
{
/* Ensure this becomes a true error */
- errflag&= ~(ME_JUST_WARNING | ME_JUST_INFO);
+ errflag&= ~(ME_WARNING | ME_NOTE);
if ((debug_assert_if_crashed_table ||
global_system_variables.log_warnings > 1))
{
/*
Log error to log before we crash or if extended warnings are requested
*/
- errflag|= ME_NOREFRESH;
+ errflag|= ME_ERROR_LOG;
}
}
@@ -4048,7 +4048,8 @@ static bool update_frm_version(TABLE *table)
int4store(version, MYSQL_VERSION_ID);
- if ((result= (int)mysql_file_pwrite(file, (uchar*) version, 4, 51L, MYF_RW)))
+ if ((result= (int)mysql_file_pwrite(file, (uchar*) version, 4, 51L,
+ MYF(MY_WME+MY_NABP))))
goto err;
table->s->mysql_version= MYSQL_VERSION_ID;
@@ -4969,7 +4970,7 @@ int ha_create_table(THD *thd, const char *path,
{
if (!thd->is_error())
my_error(ER_CANT_CREATE_TABLE, MYF(0), db, table_name, error);
- table.file->print_error(error, MYF(ME_JUST_WARNING));
+ table.file->print_error(error, MYF(ME_WARNING));
PSI_CALL_drop_table_share(temp_table, share.db.str, (uint)share.db.length,
share.table_name.str, (uint)share.table_name.length);
}
diff --git a/sql/handler.h b/sql/handler.h
index e3ab87b941b..68a54cc207a 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -3226,7 +3226,7 @@ public:
/*
True if changes to the table is persistent (no rollback)
- This is manly used to decide how to log changes to the table in
+ This is mainly used to decide how to log changes to the table in
the binary log.
*/
bool has_transactions()
diff --git a/sql/item.cc b/sql/item.cc
index 8fa3a0b741b..f6198e1df68 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -118,7 +118,7 @@ void Item::push_note_converted_to_positive_complement(THD *thd)
longlong Item::val_datetime_packed_result()
{
MYSQL_TIME ltime, tmp;
- if (get_date_result(&ltime, TIME_FUZZY_DATES | TIME_INVALID_DATES))
+ if (get_date_result(&ltime, Datetime::comparison_flags_for_get_date()))
return 0;
if (ltime.time_type != MYSQL_TIMESTAMP_TIME)
return pack_time(&ltime);
@@ -128,50 +128,6 @@ longlong Item::val_datetime_packed_result()
}
-/**
- Get date/time/datetime.
- If DATETIME or DATE result is returned, it's converted to TIME.
-*/
-bool Item::get_time_with_conversion(THD *thd, MYSQL_TIME *ltime,
- ulonglong fuzzydate)
-{
- if (get_date(ltime, fuzzydate))
- return true;
- if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
- {
- MYSQL_TIME ltime2;
- if ((thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST) &&
- (ltime->year || ltime->day || ltime->month))
- {
- /*
- Old mode conversion from DATETIME with non-zero YYYYMMDD part
- to TIME works very inconsistently. Possible variants:
- - truncate the YYYYMMDD part
- - add (MM*33+DD)*24 to hours
- - add (MM*31+DD)*24 to hours
- Let's return TRUE here, to disallow equal field propagation.
- Note, If we start to use this method in more pieces of the code other
- than equal field propagation, we should probably return
- TRUE only if some flag in fuzzydate is set.
- */
- return true;
- }
- if (datetime_to_time_with_warn(thd, ltime, &ltime2, TIME_SECOND_PART_DIGITS))
- {
- /*
- If the time difference between CURRENT_DATE and ltime
- did not fit into the supported TIME range, then we set the
- difference to the maximum possible value in the supported TIME range
- */
- DBUG_ASSERT(0);
- return (null_value= true);
- }
- *ltime= ltime2;
- }
- return false;
-}
-
-
/*
For the items which don't have its own fast val_str_ascii()
implementation we provide a generic slower version,
@@ -253,36 +209,6 @@ String *Item::val_string_from_int(String *str)
}
-String *Item::val_string_from_decimal(String *str)
-{
- my_decimal dec_buf, *dec= val_decimal(&dec_buf);
- if (null_value)
- return 0;
- my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
- my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str);
- return str;
-}
-
-
-/*
- All val_xxx_from_date() must call this method, to expose consistent behaviour
- regarding SQL_MODE when converting DATE/DATETIME to other data types.
-*/
-bool Item::get_temporal_with_sql_mode(MYSQL_TIME *ltime)
-{
- return get_date(ltime, field_type() == MYSQL_TYPE_TIME
- ? TIME_TIME_ONLY
- : sql_mode_for_dates(current_thd));
-}
-
-
-bool Item::is_null_from_temporal()
-{
- MYSQL_TIME ltime;
- return get_temporal_with_sql_mode(&ltime);
-}
-
-
longlong Item::val_int_from_str(int *error)
{
char buff[MAX_FIELD_WIDTH];
@@ -333,21 +259,6 @@ longlong Item::val_int_unsigned_typecast_from_int()
}
-String *Item::val_string_from_date(String *str)
-{
- MYSQL_TIME ltime;
- if (get_temporal_with_sql_mode(&ltime) ||
- str->alloc(MAX_DATE_STRING_REP_LENGTH))
- {
- null_value= 1;
- return (String *) 0;
- }
- str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
- str->set_charset(&my_charset_numeric);
- return str;
-}
-
-
my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
{
double nr= val_real();
@@ -379,89 +290,6 @@ my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
}
-my_decimal *Item::val_decimal_from_date(my_decimal *decimal_value)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_temporal_with_sql_mode(&ltime))
- {
- my_decimal_set_zero(decimal_value);
- null_value= 1; // set NULL, stop processing
- return 0;
- }
- return date2my_decimal(&ltime, decimal_value);
-}
-
-
-my_decimal *Item::val_decimal_from_time(my_decimal *decimal_value)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_time(&ltime))
- {
- my_decimal_set_zero(decimal_value);
- return 0;
- }
- return date2my_decimal(&ltime, decimal_value);
-}
-
-
-longlong Item::val_int_from_date()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_temporal_with_sql_mode(&ltime))
- return 0;
- longlong v= TIME_to_ulonglong(&ltime);
- return ltime.neg ? -v : v;
-}
-
-
-double Item::val_real_from_date()
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_temporal_with_sql_mode(&ltime))
- return 0;
- return TIME_to_double(&ltime);
-}
-
-
-double Item::val_real_from_decimal()
-{
- /* Note that fix_fields may not be called for Item_avg_field items */
- double result;
- my_decimal value_buff, *dec_val= val_decimal(&value_buff);
- if (null_value)
- return 0.0;
- my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result);
- return result;
-}
-
-
-longlong Item::val_int_from_decimal()
-{
- /* Note that fix_fields may not be called for Item_avg_field items */
- longlong result;
- my_decimal value, *dec_val= val_decimal(&value);
- if (null_value)
- return 0;
- my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result);
- return result;
-}
-
-
-longlong Item::val_int_unsigned_typecast_from_decimal()
-{
- longlong result;
- my_decimal tmp, *dec= val_decimal(&tmp);
- if (null_value)
- return 0;
- my_decimal2int(E_DEC_FATAL_ERROR, dec, 1, &result);
- return result;
-}
-
-
int Item::save_time_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
@@ -515,11 +343,11 @@ int Item::save_str_value_in_field(Field *field, String *result)
Item::Item(THD *thd):
is_expensive_cache(-1), rsize(0), name(null_clex_str), orig_name(0),
- fixed(0), is_autogenerated_name(TRUE)
+ is_autogenerated_name(TRUE)
{
DBUG_ASSERT(thd);
marker= 0;
- maybe_null=null_value=with_sum_func=with_window_func=with_field=0;
+ maybe_null= null_value= with_window_func= with_field= false;
in_rollup= 0;
with_param= 0;
@@ -563,11 +391,9 @@ Item::Item(THD *thd, Item *item):
maybe_null(item->maybe_null),
in_rollup(item->in_rollup),
null_value(item->null_value),
- with_sum_func(item->with_sum_func),
with_param(item->with_param),
with_window_func(item->with_window_func),
with_field(item->with_field),
- fixed(item->fixed),
is_autogenerated_name(item->is_autogenerated_name)
{
next= thd->free_list; // Put in free list
@@ -637,7 +463,6 @@ void Item::cleanup()
{
DBUG_ENTER("Item::cleanup");
DBUG_PRINT("enter", ("this: %p", this));
- fixed= 0;
marker= 0;
join_tab_idx= MAX_TABLES;
if (orig_name)
@@ -657,7 +482,7 @@ void Item::cleanup()
bool Item::cleanup_processor(void *arg)
{
- if (fixed)
+ if (is_fixed())
cleanup();
return FALSE;
}
@@ -749,7 +574,8 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
:Item_result_field(thd), orig_db_name(NullS),
orig_table_name(view_arg->table_name.str),
orig_field_name(*field_name_arg),
- context(&view_arg->view->select_lex.context),
+ /* TODO: suspicious use of first_select_lex */
+ context(&view_arg->view->first_select_lex()->context),
db_name(NullS), table_name(view_arg->alias.str),
field_name(*field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
@@ -943,12 +769,15 @@ bool Item_field::register_field_in_read_map(void *arg)
{
TABLE *table= (TABLE *) arg;
int res= 0;
+ if (table && table != field->table)
+ return res;
+
if (field->vcol_info &&
- !bitmap_fast_test_and_set(field->table->vcol_set, field->field_index))
+ !bitmap_fast_test_and_set(field->table->read_set, field->field_index))
{
res= field->vcol_info->expr->walk(&Item::register_field_in_read_map,1,arg);
}
- if (field->table == table || !table)
+ else
bitmap_set_bit(field->table->read_set, field->field_index);
return res;
}
@@ -1176,7 +1005,7 @@ bool Item::check_type_scalar(const char *opname) const
This hack in Item_outer_ref should probably be refactored eventually.
Discuss with Sanja.
*/
- DBUG_ASSERT(fixed || type() == REF_ITEM);
+ DBUG_ASSERT(is_fixed() || type() == REF_ITEM);
const Type_handler *handler= type_handler();
if (handler->is_scalar_type())
return false;
@@ -1325,7 +1154,6 @@ Item *Item_cache::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
unlikely(!(cache= new (thd->mem_root) Item_cache_str(thd, conv))))
return NULL; // Safe conversion is not possible, or OEM
cache->setup(thd, conv);
- cache->fixed= false; // Make Item::fix_fields() happy
return cache;
}
@@ -1376,7 +1204,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
const char *func_name)
{
DBUG_ASSERT(const_item());
- DBUG_ASSERT(fixed);
+ DBUG_ASSERT(is_fixed());
StringBuffer<64>tmp;
String *s= val_str(&tmp);
MEM_ROOT *mem_root= thd->mem_root;
@@ -1456,26 +1284,6 @@ bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item::get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate)
-{
- longlong value= val_int();
- DBUG_ASSERT(unsigned_flag || value >= 0);
- if (max_length == 2)
- {
- if (value < 70)
- value+= 2000;
- else if (value <= 1900)
- value+= 1900;
- }
- value*= 10000; /* make it YYYYMMHH */
- if (null_value || int_to_datetime_with_warn(false, value,
- ltime, fuzzydate,
- field_name_or_null()))
- return null_value|= make_zero_date(ltime, fuzzydate);
- return null_value= false;
-}
-
-
bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
double value= val_real();
@@ -1486,17 +1294,6 @@ bool Item::get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item::get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate)
-{
- my_decimal value, *res;
- if (!(res= val_decimal(&value)) ||
- decimal_to_datetime_with_warn(res, ltime, fuzzydate,
- field_name_or_null()))
- return null_value|= make_zero_date(ltime, fuzzydate);
- return null_value= false;
-}
-
-
bool Item::get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
char buff[40];
@@ -1535,21 +1332,6 @@ bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
return !(fuzzydate & TIME_FUZZY_DATES);
}
-bool Item::get_seconds(ulonglong *sec, ulong *sec_part)
-{
- if (decimals == 0)
- { // optimize for an important special case
- longlong val= val_int();
- bool neg= val < 0 && !unsigned_flag;
- *sec= neg ? -val : val;
- *sec_part= 0;
- return neg;
- }
- my_decimal tmp, *dec= val_decimal(&tmp);
- if (!dec)
- return 0;
- return my_decimal2seconds(dec, sec, sec_part);
-}
const MY_LOCALE *Item::locale_from_val_str()
{
@@ -1686,7 +1468,7 @@ Query_fragment::Query_fragment(THD *thd, sp_head *sphead,
*****************************************************************************/
Item_sp_variable::Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name)
- :Item(thd), m_thd(0), m_name(*sp_var_name)
+ :Item_fixed_hybrid(thd), m_thd(0), m_name(*sp_var_name)
#ifndef DBUG_OFF
, m_sp(0)
#endif
@@ -1698,7 +1480,7 @@ bool Item_sp_variable::fix_fields_from_item(THD *thd, Item **, const Item *it)
{
m_thd= thd; /* NOTE: this must be set before any this_xxx() */
- DBUG_ASSERT(it->fixed);
+ DBUG_ASSERT(it->is_fixed());
max_length= it->max_length;
decimals= it->decimals;
@@ -1819,10 +1601,10 @@ Item_splocal::Item_splocal(THD *thd,
Rewritable_query_parameter(pos_in_q, len_in_q),
Type_handler_hybrid_field_type(handler),
m_rcontext_handler(rh),
- m_var_idx(sp_var_idx)
+ m_var_idx(sp_var_idx),
+ m_type(handler == &type_handler_row ? ROW_ITEM : CONST_ITEM)
{
maybe_null= TRUE;
- m_type= sp_map_item_type(handler);
}
@@ -2175,54 +1957,25 @@ bool Item_name_const::is_null()
Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
- Item(thd), value_item(val), name_item(name_arg)
+ Item_fixed_hybrid(thd), value_item(val), name_item(name_arg)
{
Item::maybe_null= TRUE;
- valid_args= true;
- if (!name_item->basic_const_item())
- goto err;
-
- if (value_item->basic_const_item())
- return; // ok
-
- if (value_item->type() == FUNC_ITEM)
- {
- Item_func *value_func= (Item_func *) value_item;
- if (value_func->functype() != Item_func::COLLATE_FUNC &&
- value_func->functype() != Item_func::NEG_FUNC)
- goto err;
-
- if (value_func->key_item()->basic_const_item())
- return; // ok
- }
-
-err:
- valid_args= false;
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
}
Item::Type Item_name_const::type() const
{
/*
- As
- 1. one can try to create the Item_name_const passing non-constant
- arguments, although it's incorrect and
- 2. the type() method can be called before the fix_fields() to get
- type information for a further type cast, e.g.
- if (item->type() == FIELD_ITEM)
- ((Item_field *) item)->...
- we return NULL_ITEM in the case to avoid wrong casting.
-
- valid_args guarantees value_item->basic_const_item(); if type is
- FUNC_ITEM, then we have a fudged item_func_neg() on our hands
- and return the underlying type.
+
+ We are guarenteed that value_item->basic_const_item(), if not
+ an error is thrown that WRONG ARGUMENTS are supplied to
+ NAME_CONST function.
+ If type is FUNC_ITEM, then we have a fudged item_func_neg()
+ on our hands and return the underlying type.
For Item_func_set_collation()
e.g. NAME_CONST('name', 'value' COLLATE collation) we return its
'value' argument type.
*/
- if (!valid_args)
- return NULL_ITEM;
Item::Type value_type= value_item->type();
if (value_type == FUNC_ITEM)
{
@@ -2365,7 +2118,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
else
{
/* Not a SUM() function */
- if (unlikely((!with_sum_func && !(split_flags & SPLIT_SUM_SELECT))))
+ if (unlikely((!with_sum_func() && !(split_flags & SPLIT_SUM_SELECT))))
{
/*
This is not a SUM function and there are no SUM functions inside.
@@ -2373,7 +2126,7 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
*/
return;
}
- if (likely(with_sum_func ||
+ if (likely(with_sum_func() ||
(type() == FUNC_ITEM &&
(((Item_func *) this)->functype() ==
Item_func::ISNOTNULLTEST_FUNC ||
@@ -2748,7 +2501,7 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll,
else
thd->change_item_tree(arg, conv);
- if (conv->fix_fields(thd, arg))
+ if (conv->fix_fields_if_needed(thd, arg))
{
res= TRUE;
break; // we cannot return here, we need to restore "arena".
@@ -2897,7 +2650,7 @@ bool Item_sp::execute(THD *thd, bool *null_value, Item **args, uint arg_count)
if (unlikely(execute_impl(thd, args, arg_count)))
{
*null_value= 1;
- context->process_error(thd);
+ process_error(thd);
if (thd->killed)
thd->send_kill_message();
return true;
@@ -2930,7 +2683,7 @@ Item_sp::execute_impl(THD *thd, Item **args, uint arg_count)
DBUG_ENTER("Item_sp::execute_impl");
- if (context->security_ctx)
+ if (context && context->security_ctx)
{
/* Set view definer security context */
thd->security_ctx= context->security_ctx;
@@ -3109,7 +2862,10 @@ Item_field::Item_field(THD *thd, Field *f)
have_privileges(0), any_privileges(0)
{
set_field(f);
-
+ /*
+ field_name and table_name should not point to garbage
+ if this item is to be reused
+ */
orig_table_name= table_name;
orig_field_name= field_name;
with_field= 1;
@@ -3645,6 +3401,48 @@ longlong Item_field::val_int_endpoint(bool left_endp, bool *incl_endp)
return null_value? LONGLONG_MIN : res;
}
+
+bool Item_basic_value::eq(const Item *item, bool binary_cmp) const
+{
+ const Item_const *c0, *c1;
+ const Type_handler *h0, *h1;
+ /*
+ - Test get_item_const() for NULL filters out Item_param
+ bound in a way that needs a data type conversion
+ (e.g. non-integer value in a LIMIT clause).
+ Item_param::get_item_const() return NULL in such cases.
+ - Test for type_handler_for_comparison() equality makes sure
+ that values of different data type groups do not get detected
+ as equal (e.g. numbers vs strings, time vs datetime).
+ - Test for cast_to_int_type_handler() equality distinguishes
+ values with dual properties. For example, VARCHAR 'abc' and hex
+ hybrid 0x616263 are equal in string context, but they are not equal
+ if the hybrid appears in integer context (it behaves as integer then).
+ Here we have no full information about the context, so treat them
+ as not equal.
+ QQ: We could pass Value_source::Context here instead of
+ "bool binary_cmp", to make substitution more delicate.
+ See Field::get_equal_const_item().
+ */
+ bool res= (c0= get_item_const()) &&
+ (c1= item->get_item_const()) &&
+ (h0= type_handler())->type_handler_for_comparison() ==
+ (h1= item->type_handler())->type_handler_for_comparison() &&
+ h0->cast_to_int_type_handler()->type_handler_for_comparison() ==
+ h1->cast_to_int_type_handler()->type_handler_for_comparison() &&
+ h0->Item_const_eq(c0, c1, binary_cmp);
+ DBUG_EXECUTE_IF("Item_basic_value",
+ push_warning_printf(current_thd,
+ Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "%seq=%d a=%s b=%s",
+ binary_cmp ? "bin_" : "", (int) res,
+ DbugStringItemTypeValue(current_thd, this).c_ptr(),
+ DbugStringItemTypeValue(current_thd, item).c_ptr()
+ ););
+ return res;
+}
+
+
/**
Create an item from a string we KNOW points to a valid longlong
end \\0 terminated number string.
@@ -3664,7 +3462,6 @@ Item_int::Item_int(THD *thd, const char *str_arg, size_t length):
the field name.
*/
name.length= !str_arg[max_length] ? max_length : strlen(str_arg);
- fixed= 1;
}
@@ -3676,8 +3473,6 @@ my_decimal *Item_int::val_decimal(my_decimal *decimal_value)
String *Item_int::val_str(String *str)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
str->set_int(value, unsigned_flag, collation.collation);
return str;
}
@@ -3714,8 +3509,6 @@ Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length):
String *Item_uint::val_str(String *str)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
str->set((ulonglong) value, collation.collation);
return str;
}
@@ -3737,7 +3530,6 @@ Item_decimal::Item_decimal(THD *thd, const char *str_arg, size_t length,
name.str= str_arg;
name.length= safe_strlen(str_arg);
decimals= (uint8) decimal_value.frac;
- fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
@@ -3749,7 +3541,6 @@ Item_decimal::Item_decimal(THD *thd, longlong val, bool unsig):
{
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
- fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
@@ -3762,7 +3553,6 @@ Item_decimal::Item_decimal(THD *thd, double val, int precision, int scale):
{
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac;
- fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
@@ -3779,16 +3569,14 @@ Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
name.length= safe_strlen(str);
decimals= (uint8) decimal_par;
max_length= length;
- fixed= 1;
}
-Item_decimal::Item_decimal(THD *thd, my_decimal *value_par):
+Item_decimal::Item_decimal(THD *thd, const my_decimal *value_par):
Item_num(thd)
{
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
- fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
@@ -3797,63 +3585,15 @@ Item_decimal::Item_decimal(THD *thd, my_decimal *value_par):
Item_decimal::Item_decimal(THD *thd, const uchar *bin, int precision, int scale):
- Item_num(thd)
+ Item_num(thd),
+ decimal_value(bin, precision, scale)
{
- binary2my_decimal(E_DEC_FATAL_ERROR, bin,
- &decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac;
- fixed= 1;
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
-longlong Item_decimal::val_int()
-{
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result);
- return result;
-}
-
-double Item_decimal::val_real()
-{
- double result;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
- return result;
-}
-
-String *Item_decimal::val_str(String *result)
-{
- result->set_charset(&my_charset_numeric);
- my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
- return result;
-}
-
-void Item_decimal::print(String *str, enum_query_type query_type)
-{
- my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
- str->append(str_value);
-}
-
-
-bool Item_decimal::eq(const Item *item, bool binary_cmp) const
-{
- if (type() == item->type() && item->basic_const_item())
- {
- /*
- We need to cast off const to call val_decimal(). This should
- be OK for a basic constant. Additionally, we can pass 0 as
- a true decimal constant will return its internal decimal
- storage and ignore the argument.
- */
- Item *arg= (Item*) item;
- my_decimal *value= arg->val_decimal(0);
- return !my_decimal_cmp(&decimal_value, value);
- }
- return 0;
-}
-
-
void Item_decimal::set_decimal_value(my_decimal *value_par)
{
my_decimal2decimal(value_par, &decimal_value);
@@ -3875,8 +3615,6 @@ Item *Item_decimal::clone_item(THD *thd)
String *Item_float::val_str(String *str)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
str->set_real(value, decimals, &my_charset_numeric);
return str;
}
@@ -3884,8 +3622,6 @@ String *Item_float::val_str(String *str)
my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
return (decimal_value);
}
@@ -3946,7 +3682,6 @@ void Item_string::print(String *str, enum_query_type query_type)
double Item_string::val_real()
{
- DBUG_ASSERT(fixed == 1);
return double_from_string_with_check(&str_value);
}
@@ -3957,7 +3692,6 @@ double Item_string::val_real()
*/
longlong Item_string::val_int()
{
- DBUG_ASSERT(fixed == 1);
return longlong_from_string_with_check(&str_value);
}
@@ -3970,23 +3704,17 @@ my_decimal *Item_string::val_decimal(my_decimal *decimal_value)
double Item_null::val_real()
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
null_value=1;
return 0.0;
}
longlong Item_null::val_int()
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
null_value=1;
return 0;
}
/* ARGSUSED */
String *Item_null::val_str(String *str)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
null_value=1;
return 0;
}
@@ -3999,8 +3727,6 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
make_zero_date(ltime, fuzzydate);
return (null_value= true);
}
@@ -4050,8 +3776,6 @@ Item_param::Item_param(THD *thd, const LEX_CSTRING *name_arg,
*/
Type_handler_hybrid_field_type(&type_handler_null),
state(NO_VALUE),
- /* Don't pretend to be a literal unless value for this item is set. */
- item_type(PARAM_ITEM),
m_empty_string_is_null(false),
indicator(STMT_INDICATOR_NONE),
m_out_param_info(NULL),
@@ -4090,7 +3814,6 @@ void Item_param::set_null()
max_length= 0;
decimals= 0;
state= NULL_VALUE;
- fix_type(Item::NULL_ITEM);
DBUG_VOID_RETURN;
}
@@ -4105,7 +3828,6 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
decimals= 0;
maybe_null= 0;
null_value= 0;
- fix_type(Item::INT_ITEM);
DBUG_VOID_RETURN;
}
@@ -4120,7 +3842,6 @@ void Item_param::set_double(double d)
decimals= NOT_FIXED_DEC;
maybe_null= 0;
null_value= 0;
- fix_type(Item::REAL_ITEM);
DBUG_VOID_RETURN;
}
@@ -4153,7 +3874,6 @@ void Item_param::set_decimal(const char *str, ulong length)
decimals, unsigned_flag);
maybe_null= 0;
null_value= 0;
- fix_type(Item::DECIMAL_ITEM);
DBUG_VOID_RETURN;
}
@@ -4171,7 +3891,6 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
decimals, unsigned_flag);
maybe_null= 0;
null_value= 0;
- fix_type(Item::DECIMAL_ITEM);
}
@@ -4183,7 +3902,6 @@ void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
decimals= decimals_arg;
maybe_null= 0;
null_value= 0;
- fix_type(Item::DATE_ITEM);
}
@@ -4268,7 +3986,6 @@ bool Item_param::set_str(const char *str, ulong length,
null_value= 0;
/* max_length and decimals are set after charset conversion */
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
- fix_type(Item::STRING_ITEM);
DBUG_RETURN(FALSE);
}
@@ -4302,7 +4019,6 @@ bool Item_param::set_longdata(const char *str, ulong length)
state= LONG_DATA_VALUE;
maybe_null= 0;
null_value= 0;
- fix_type(Item::STRING_ITEM);
DBUG_RETURN(FALSE);
}
@@ -4404,16 +4120,6 @@ void Item_param::reset()
state= NO_VALUE;
maybe_null= 1;
null_value= 0;
- fixed= false;
- /*
- Don't reset item_type to PARAM_ITEM: it's only needed to guard
- us from item optimizations at prepare stage, when item doesn't yet
- contain a literal of some kind.
- In all other cases when this object is accessed its value is
- set (this assumption is guarded by 'state' and
- DBUG_ASSERTS(state != NO_VALUE) in all Item_param::get_*
- methods).
- */
DBUG_VOID_RETURN;
}
@@ -4505,11 +4211,7 @@ double Item_param::PValue::val_real() const
case INT_RESULT:
return (double) integer;
case DECIMAL_RESULT:
- {
- double result;
- my_decimal2double(E_DEC_FATAL_ERROR, &m_decimal, &result);
- return result;
- }
+ return m_decimal.to_double();
case STRING_RESULT:
return double_from_string_with_check(&m_string);
case TIME_RESULT:
@@ -4534,11 +4236,7 @@ longlong Item_param::PValue::val_int(const Type_std_attributes *attr) const
case INT_RESULT:
return integer;
case DECIMAL_RESULT:
- {
- longlong i;
- my_decimal2int(E_DEC_FATAL_ERROR, &m_decimal, attr->unsigned_flag, &i);
- return i;
- }
+ return m_decimal.to_longlong(attr->unsigned_flag);
case STRING_RESULT:
return longlong_from_string_with_check(&m_string);
case TIME_RESULT:
@@ -4588,7 +4286,7 @@ String *Item_param::PValue::val_str(String *str,
str->set(integer, &my_charset_bin);
return str;
case DECIMAL_RESULT:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &m_decimal, 0, 0, 0, str) <= 1)
+ if (m_decimal.to_string_native(str, 0, 0, 0) <= 1)
return str;
return NULL;
case TIME_RESULT:
@@ -4629,8 +4327,7 @@ const String *Item_param::value_query_val_str(THD *thd, String *str) const
str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin);
return str;
case DECIMAL_RESULT:
- if (my_decimal2string(E_DEC_FATAL_ERROR, &value.m_decimal,
- 0, 0, 0, str) > 1)
+ if (value.m_decimal.to_string_native(str, 0, 0, 0) > 1)
return &my_null_string;
return str;
case TIME_RESULT:
@@ -4735,11 +4432,20 @@ bool Item_param::convert_str_value(THD *thd)
bool Item_param::basic_const_item() const
{
- DBUG_ASSERT(fixed || state == NO_VALUE);
- if (state == NO_VALUE ||
- (state == SHORT_DATA_VALUE && type_handler()->cmp_type() == TIME_RESULT))
- return FALSE;
- return TRUE;
+ switch (state) {
+ case LONG_DATA_VALUE:
+ case NULL_VALUE:
+ return true;
+ case SHORT_DATA_VALUE:
+ return type_handler()->cmp_type() != TIME_RESULT;
+ case DEFAULT_VALUE:
+ case IGNORE_VALUE:
+ invalid_default_param();
+ return false;
+ case NO_VALUE:
+ break;
+ }
+ return false;
}
@@ -4800,48 +4506,6 @@ Item_param::clone_item(THD *thd)
}
-bool Item_param::value_eq(const Item *item, bool binary_cmp) const
-{
- switch (value.type_handler()->cmp_type()) {
- case INT_RESULT:
- return int_eq(value.integer, item);
- case REAL_RESULT:
- return real_eq(value.real, item);
- case STRING_RESULT:
- return str_eq(&value.m_string, item, binary_cmp);
- case DECIMAL_RESULT:
- case TIME_RESULT:
- case ROW_RESULT:
- break;
- }
- return false;
-}
-
-
-bool
-Item_param::eq(const Item *item, bool binary_cmp) const
-{
- if (!basic_const_item())
- return FALSE;
-
- // There's no "default". See comments in Item_param::save_in_field().
- switch (state) {
- case IGNORE_VALUE:
- case DEFAULT_VALUE:
- invalid_default_param();
- return false;
- case NULL_VALUE:
- return null_eq(item);
- case SHORT_DATA_VALUE:
- case LONG_DATA_VALUE:
- return value_eq(item, binary_cmp);
- case NO_VALUE:
- return false;
- }
- DBUG_ASSERT(0); // Garbage
- return FALSE;
-}
-
/* End of Item_param related */
void Item_param::print(String *str, enum_query_type query_type)
@@ -4895,12 +4559,10 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
{
Type_std_attributes::set(src);
set_handler(src->type_handler());
- item_type= src->item_type;
maybe_null= src->maybe_null;
null_value= src->null_value;
state= src->state;
- fixed= src->fixed;
value.swap(src->value);
}
@@ -4910,7 +4572,6 @@ void Item_param::set_default()
{
m_is_settable_routine_parameter= false;
state= DEFAULT_VALUE;
- fixed= true;
/*
When Item_param is set to DEFAULT_VALUE:
- its val_str() and val_decimal() return NULL
@@ -4926,7 +4587,6 @@ void Item_param::set_ignore()
{
m_is_settable_routine_parameter= false;
state= IGNORE_VALUE;
- fixed= true;
null_value= true;
}
@@ -5230,37 +4890,19 @@ int Item_copy_decimal::save_in_field(Field *field, bool no_conversions)
String *Item_copy_decimal::val_str(String *result)
{
- if (null_value)
- return (String *) 0;
- result->set_charset(&my_charset_bin);
- my_decimal2string(E_DEC_FATAL_ERROR, &cached_value, 0, 0, 0, result);
- return result;
+ return null_value ? NULL : cached_value.to_string(result);
}
double Item_copy_decimal::val_real()
{
- if (null_value)
- return 0.0;
- else
- {
- double result;
- my_decimal2double(E_DEC_FATAL_ERROR, &cached_value, &result);
- return result;
- }
+ return null_value ? 0.0 : cached_value.to_double();
}
longlong Item_copy_decimal::val_int()
{
- if (null_value)
- return 0;
- else
- {
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result);
- return result;
- }
+ return null_value ? 0 : cached_value.to_longlong(unsigned_flag);
}
@@ -5277,17 +4919,6 @@ void Item_copy_decimal::copy()
Functions to convert item to field (for send_result_set_metadata)
*/
-/* ARGSUSED */
-bool Item::fix_fields(THD *thd, Item **ref)
-{
-
- // We do not check fields which are fixed during construction
- DBUG_ASSERT(fixed == 0 || basic_const_item());
- fixed= 1;
- return FALSE;
-}
-
-
void Item_ref_null_helper::save_val(Field *to)
{
DBUG_ASSERT(fixed == 1);
@@ -5636,7 +5267,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
ref->alias_name_used= TRUE;
/* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
- if (select->having_fix_field && !ref->with_sum_func && group_list)
+ if (select->having_fix_field && !ref->with_sum_func() && group_list)
{
group_by_ref= find_field_in_group_list(ref, group_list);
@@ -5678,7 +5309,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
ref->name.str, "forward reference in item list");
return NULL;
}
- DBUG_ASSERT((*select_ref)->fixed);
+ DBUG_ASSERT((*select_ref)->is_fixed());
return &select->ref_pointer_array[counter];
}
if (group_by_ref)
@@ -5801,7 +5432,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
Name_resolution_context *outer_context= 0;
SELECT_LEX *select= 0;
/* Currently derived tables cannot be correlated */
- if (current_sel->master_unit()->first_select()->linkage !=
+ if (current_sel->master_unit()->first_select()->get_linkage() !=
DERIVED_TABLE_TYPE)
outer_context= context->outer_context;
@@ -5955,7 +5586,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
return -1; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
- DBUG_ASSERT(*ref && (*ref)->fixed);
+ DBUG_ASSERT(*ref && (*ref)->is_fixed());
prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
@@ -5997,7 +5628,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
Item_ref *rf;
/* Should have been checked in resolve_ref_in_select_and_group(). */
- DBUG_ASSERT(*ref && (*ref)->fixed);
+ DBUG_ASSERT(*ref && (*ref)->is_fixed());
/*
Here, a subset of actions performed by Item_ref::set_properties
is not enough. So we pass ptr to NULL into Item_[direct]_ref
@@ -6573,7 +6204,7 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
comparison context, and it's safe to replace it to the constant from
item_equal.
*/
- DBUG_ASSERT(type_handler()->type_handler_for_comparison()->cmp_type() ==
+ DBUG_ASSERT(type_handler_for_comparison()->cmp_type() ==
item_equal->compare_type_handler()->cmp_type());
return const_item2;
}
@@ -6945,12 +6576,11 @@ int Item::save_real_in_field(Field *field, bool no_conversions)
int Item::save_decimal_in_field(Field *field, bool no_conversions)
{
- my_decimal decimal_value;
- my_decimal *value= val_decimal(&decimal_value);
- if (null_value)
+ VDec value(this);
+ if (value.is_null())
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
- return field->store_decimal(value);
+ return field->store_decimal(value.ptr());
}
@@ -7017,14 +6647,18 @@ Item_string::make_string_literal_concat(THD *thd, const LEX_CSTRING *str)
*/
Item *Item_string::make_odbc_literal(THD *thd, const LEX_CSTRING *typestr)
{
- enum_field_types type= odbc_temporal_literal_type(typestr);
- Item *res= type == MYSQL_TYPE_STRING ? this :
- create_temporal_literal(thd, val_str(NULL), type, false);
+ Item_literal *res;
+ const Type_handler *h;
+ if (collation.repertoire == MY_REPERTOIRE_ASCII &&
+ str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4 &&
+ (h= Type_handler::odbc_literal_type_handler(typestr)) &&
+ (res= h->create_literal_item(thd, val_str(NULL), false)))
+ return res;
/*
- create_temporal_literal() returns NULL if failed to parse the string,
+ h->create_literal_item() returns NULL if failed to parse the string,
or the string format did not match the type, e.g.: {d'2001-01-01 10:10:10'}
*/
- return res ? res : this;
+ return this;
}
@@ -7227,7 +6861,6 @@ Item_float::Item_float(THD *thd, const char *str_arg, size_t length):
name.length= strlen(str_arg);
decimals=(uint8) nr_of_decimals(str_arg, str_arg+length);
max_length=(uint32)length;
- fixed= 1;
}
@@ -7283,7 +6916,6 @@ void Item_hex_constant::hex_string_init(THD *thd, const char *str, size_t str_le
}
*ptr=0; // Keep purify happy
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
- fixed= 1;
unsigned_flag= 1;
}
@@ -7362,19 +6994,9 @@ Item_bin_string::Item_bin_string(THD *thd, const char *str, size_t str_length):
ptr[0]= 0;
collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
- fixed= 1;
}
-bool Item_temporal_literal::eq(const Item *item, bool binary_cmp) const
-{
- return
- item->basic_const_item() && type() == item->type() &&
- field_type() == ((Item_temporal_literal *) item)->field_type() &&
- !my_time_compare(&cached_time,
- &((Item_temporal_literal *) item)->cached_time);
-}
-
void Item_date_literal::print(String *str, enum_query_type query_type)
{
str->append("DATE'");
@@ -7393,7 +7015,6 @@ Item *Item_date_literal::clone_item(THD *thd)
bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- DBUG_ASSERT(fixed);
fuzzy_date |= sql_mode_for_dates(current_thd);
*ltime= cached_time;
return (null_value= check_date_with_warn(ltime, fuzzy_date,
@@ -7419,7 +7040,6 @@ Item *Item_datetime_literal::clone_item(THD *thd)
bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- DBUG_ASSERT(fixed);
fuzzy_date |= sql_mode_for_dates(current_thd);
*ltime= cached_time;
return (null_value= check_date_with_warn(ltime, fuzzy_date,
@@ -7445,7 +7065,6 @@ Item *Item_time_literal::clone_item(THD *thd)
bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- DBUG_ASSERT(fixed);
*ltime= cached_time;
if (fuzzy_date & TIME_TIME_ONLY)
return (null_value= false);
@@ -7565,7 +7184,7 @@ void Item_field::update_null_value()
no_errors= thd->no_errors;
thd->no_errors= 1;
- Item::update_null_value();
+ type_handler()->Item_update_null_value(this);
thd->no_errors= no_errors;
}
@@ -7616,6 +7235,231 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
}
+/**
+ @brief
+ Prepare AND/OR formula for extraction of a pushable condition
+
+ @param checker the checker callback function to be applied to the nodes
+ of the tree of the object
+ @param arg parameter to be passed to the checker
+
+ @details
+ This method recursively traverses this AND/OR condition and for each
+ subformula of the condition it checks whether it can be usable for the
+ extraction of a pushable condition. The criteria of pushability of
+ a subformula is checked by the callback function 'checker' with one
+ parameter arg. The subformulas that are not usable are marked with
+ the flag NO_EXTRACTION_FL.
+ @note
+ This method is called before any call of build_pushable_cond.
+ The flag NO_EXTRACTION_FL set in a subformula allows to avoid building
+ clones for the subformulas that are not used in the pushable condition.
+ @note
+ This method is called for pushdown conditions into materialized
+ derived tables/views optimization.
+ Item::pushable_cond_checker_for_derived() is passed as the actual callback
+ function.
+ Also it is called for pushdown conditions in materialized IN subqueries.
+ Item::pushable_cond_checker_for_subquery is passed as the actual
+ callback function.
+*/
+
+void Item::check_pushable_cond(Pushdown_checker checker, uchar *arg)
+{
+ clear_extraction_flag();
+ if (type() == Item::COND_ITEM)
+ {
+ bool and_cond= ((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC;
+ List_iterator<Item> li(*((Item_cond*) this)->argument_list());
+ uint count= 0;
+ Item *item;
+ while ((item=li++))
+ {
+ item->check_pushable_cond(checker, arg);
+ if (item->get_extraction_flag() != NO_EXTRACTION_FL)
+ count++;
+ else if (!and_cond)
+ break;
+ }
+ if ((and_cond && count == 0) || item)
+ {
+ set_extraction_flag(NO_EXTRACTION_FL);
+ if (and_cond)
+ li.rewind();
+ while ((item= li++))
+ item->clear_extraction_flag();
+ }
+ }
+ else if (!((this->*checker) (arg)))
+ set_extraction_flag(NO_EXTRACTION_FL);
+}
+
+
+/**
+ @brief
+ Build condition extractable from this condition for pushdown
+
+ @param thd the thread handle
+ @param checker the checker callback function to be applied to the
+ equal items of multiple equality items
+ @param arg parameter to be passed to the checker
+
+ @details
+ This method finds out what condition that can be pushed down can be
+ extracted from this condition. If such condition C exists the
+ method builds the item for it. The method uses the flag NO_EXTRACTION_FL
+ set by the preliminary call of the method check_pushable_cond() to figure
+ out whether a subformula is pushable or not.
+ In the case when this item is a multiple equality a checker method is
+ called to find the equal fields to build a new equality that can be
+ pushed down.
+ @note
+ The built condition C is always implied by the condition cond
+ (cond => C). The method tries to build the most restrictive such
+ condition (i.e. for any other condition C' such that cond => C'
+ we have C => C').
+ @note
+ The build item is not ready for usage: substitution for the field items
+ has to be done and it has to be re-fixed.
+ @note
+ This method is called for pushdown conditions into materialized
+ derived tables/views optimization.
+ Item::pushable_equality_checker_for_derived() is passed as the actual
+ callback function.
+ Also it is called for pushdown conditions into materialized IN subqueries.
+ Item::pushable_equality_checker_for_subquery() is passed as the actual
+ callback function.
+
+ @retval
+ the built condition pushable into if such a condition exists
+ NULL if there is no such a condition
+*/
+
+Item *Item::build_pushable_cond(THD *thd,
+ Pushdown_checker checker,
+ uchar *arg)
+{
+ bool is_multiple_equality= type() == Item::FUNC_ITEM &&
+ ((Item_func*) this)->functype() == Item_func::MULT_EQUAL_FUNC;
+
+ if (get_extraction_flag() == NO_EXTRACTION_FL)
+ return 0;
+
+ if (type() == Item::COND_ITEM)
+ {
+ bool cond_and= false;
+ Item_cond *new_cond;
+ if (((Item_cond*) this)->functype() == Item_func::COND_AND_FUNC)
+ {
+ cond_and= true;
+ new_cond= new (thd->mem_root) Item_cond_and(thd);
+ }
+ else
+ new_cond= new (thd->mem_root) Item_cond_or(thd);
+ if (!new_cond)
+ return 0;
+ List_iterator<Item> li(*((Item_cond*) this)->argument_list());
+ Item *item;
+ bool is_fix_needed= false;
+
+ while ((item=li++))
+ {
+ if (item->get_extraction_flag() == NO_EXTRACTION_FL)
+ {
+ if (!cond_and)
+ return 0;
+ continue;
+ }
+ Item *fix= item->build_pushable_cond(thd, checker, arg);
+ if (!fix && !cond_and)
+ return 0;
+ if (!fix)
+ continue;
+
+ if (fix->type() == Item::COND_ITEM &&
+ ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC)
+ is_fix_needed= true;
+
+ if (new_cond->argument_list()->push_back(fix, thd->mem_root))
+ return 0;
+ }
+ if (is_fix_needed && new_cond->fix_fields(thd, 0))
+ return 0;
+
+ switch (new_cond->argument_list()->elements)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return new_cond->argument_list()->head();
+ default:
+ return new_cond;
+ }
+ }
+ else if (is_multiple_equality)
+ {
+ Item *new_cond= NULL;
+ int i= 0;
+ Item_equal *item_equal= (Item_equal *) this;
+ Item *left_item = item_equal->get_const();
+ Item_equal_fields_iterator it(*item_equal);
+ Item *item;
+ Item *right_item;
+ if (!left_item)
+ {
+ while ((item=it++))
+ {
+ left_item= ((item->*checker) (arg)) ? item : NULL;
+ if (left_item)
+ break;
+ }
+ }
+ if (!left_item)
+ return 0;
+ while ((item=it++))
+ {
+ right_item= ((item->*checker) (arg)) ? item : NULL;
+ if (!right_item)
+ continue;
+ Item_func_eq *eq= 0;
+ Item *left_item_clone= left_item->build_clone(thd);
+ Item *right_item_clone= item->build_clone(thd);
+ if (left_item_clone && right_item_clone)
+ {
+ left_item_clone->set_item_equal(NULL);
+ right_item_clone->set_item_equal(NULL);
+ eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone,
+ left_item_clone);
+ }
+ if (eq)
+ {
+ i++;
+ switch (i)
+ {
+ case 1:
+ new_cond= eq;
+ break;
+ case 2:
+ new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq);
+ break;
+ default:
+ if (((Item_cond_and*)new_cond)->argument_list()->push_back(eq,
+ thd->mem_root))
+ return 0;
+ break;
+ }
+ }
+ }
+ if (new_cond && new_cond->fix_fields(thd, &new_cond))
+ return 0;
+ return new_cond;
+ }
+ else if (get_extraction_flag() != NO_EXTRACTION_FL)
+ return build_clone(thd);
+ return 0;
+}
+
+
static
Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
{
@@ -7735,18 +7579,18 @@ Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
}
static
-Grouping_tmp_field *find_matching_grouping_field(Item *item,
- st_select_lex *sel)
+Field_pair *find_matching_grouping_field(Item *item,
+ st_select_lex *sel)
{
DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
(item->type() == Item::REF_ITEM &&
((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
- List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields);
- Grouping_tmp_field *gr_field;
+ List_iterator<Field_pair> li(sel->grouping_tmp_fields);
+ Field_pair *gr_field;
Item_field *field_item= (Item_field *) (item->real_item());
while ((gr_field= li++))
{
- if (field_item->field == gr_field->tmp_field)
+ if (field_item->field == gr_field->field)
return gr_field;
}
Item_equal *item_equal= item->get_item_equal();
@@ -7760,7 +7604,7 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item,
li.rewind();
while ((gr_field= li++))
{
- if (field_item->field == gr_field->tmp_field)
+ if (field_item->field == gr_field->field)
return gr_field;
}
}
@@ -7769,26 +7613,25 @@ Grouping_tmp_field *find_matching_grouping_field(Item *item,
}
-Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
- uchar *arg)
+Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg)
{
st_select_lex *sel= (st_select_lex *)arg;
- Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
+ Field_pair *gr_field= find_matching_grouping_field(this, sel);
if (gr_field)
- return gr_field->producing_item->build_clone(thd);
+ return gr_field->corresponding_item->build_clone(thd);
return this;
}
Item *
-Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd,
- uchar *arg)
+Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd,
+ uchar *arg)
{
if (!item_equal)
return this;
st_select_lex *sel= (st_select_lex *)arg;
- Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
- return gr_field->producing_item->build_clone(thd);
+ Field_pair *gr_field= find_matching_grouping_field(this, sel);
+ return gr_field->corresponding_item->build_clone(thd);
}
void Item_field::print(String *str, enum_query_type query_type)
@@ -7824,7 +7667,7 @@ Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg,
/*
This constructor used to create some internals references over fixed items
*/
- if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
+ if ((set_properties_only= (ref && *ref && (*ref)->is_fixed())))
set_properties();
}
@@ -7873,7 +7716,7 @@ Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
/*
This constructor is used to create some internal references over fixed items
*/
- if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
+ if ((set_properties_only= (ref && *ref && (*ref)->is_fixed())))
set_properties();
}
@@ -7999,7 +7842,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
- DBUG_ASSERT(*ref && (*ref)->fixed);
+ DBUG_ASSERT(*ref && (*ref)->is_fixed());
prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
@@ -8122,7 +7965,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
goto error;
}
/* Should be checked in resolve_ref_in_select_and_group(). */
- DBUG_ASSERT(*ref && (*ref)->fixed);
+ DBUG_ASSERT(*ref && (*ref)->is_fixed());
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this, this);
/*
@@ -8147,13 +7990,13 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
*/
if (!((*ref)->type() == REF_ITEM &&
((Item_ref *)(*ref))->ref_type() == OUTER_REF) &&
- (((*ref)->with_sum_func && name.str &&
- !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
+ (((*ref)->with_sum_func() && name.str &&
+ !(current_sel->get_linkage() != GLOBAL_OPTIONS_TYPE &&
current_sel->having_fix_field)) ||
- !(*ref)->fixed))
+ !(*ref)->is_fixed()))
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0),
- name.str, ((*ref)->with_sum_func?
+ name.str, ((*ref)->with_sum_func() ?
"reference to group function":
"forward reference in item list"));
goto error;
@@ -8179,7 +8022,7 @@ void Item_ref::set_properties()
We have to remember if we refer to a sum function, to ensure that
split_sum_func() doesn't try to change the reference.
*/
- with_sum_func= (*ref)->with_sum_func;
+ copy_with_sum_func(*ref);
with_param= (*ref)->with_param;
with_window_func= (*ref)->with_window_func;
with_field= (*ref)->with_field;
@@ -8602,10 +8445,10 @@ Item_cache_wrapper::~Item_cache_wrapper()
Item_cache_wrapper::Item_cache_wrapper(THD *thd, Item *item_arg):
Item_result_field(thd), orig_item(item_arg), expr_cache(NULL), expr_value(NULL)
{
- DBUG_ASSERT(orig_item->fixed);
+ DBUG_ASSERT(orig_item->is_fixed());
Type_std_attributes::set(orig_item);
maybe_null= orig_item->maybe_null;
- with_sum_func= orig_item->with_sum_func;
+ copy_with_sum_func(orig_item);
with_param= orig_item->with_param;
with_field= orig_item->with_field;
name= item_arg->name;
@@ -8664,7 +8507,7 @@ void Item_cache_wrapper::print(String *str, enum_query_type query_type)
bool Item_cache_wrapper::fix_fields(THD *thd __attribute__((unused)),
Item **it __attribute__((unused)))
{
- DBUG_ASSERT(orig_item->fixed);
+ DBUG_ASSERT(orig_item->is_fixed());
DBUG_ASSERT(fixed);
return FALSE;
}
@@ -8994,7 +8837,7 @@ int Item_cache_wrapper::save_in_field(Field *to, bool no_conversions)
Item* Item_cache_wrapper::get_tmp_table_item(THD *thd)
{
- if (!orig_item->with_sum_func && !orig_item->const_item())
+ if (!orig_item->with_sum_func() && !orig_item->const_item())
return new (thd->mem_root) Item_temptable_field(thd, result_field);
return copy_or_same(thd);
}
@@ -9024,7 +8867,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
/* view fild reference must be defined */
DBUG_ASSERT(*ref);
/* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */
- if ((*ref)->fixed)
+ if ((*ref)->is_fixed())
{
Item *ref_item= (*ref)->real_item();
if (ref_item->type() == Item::FIELD_ITEM)
@@ -9310,7 +9153,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items)
if (arg->fix_fields_if_needed(thd, &arg))
goto error;
-
real_arg= arg->real_item();
if (real_arg->type() != FIELD_ITEM)
{
@@ -9526,7 +9368,7 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
{
DBUG_ASSERT(fixed == 0);
/* We should only check that arg is in first table */
- if (!arg->fixed)
+ if (!arg->is_fixed())
{
bool res;
TABLE_LIST *orig_next_table= context->last_name_resolution_table;
@@ -9738,7 +9580,7 @@ void Item_trigger_field::cleanup()
Since special nature of Item_trigger_field we should not do most of
things from Item_field::cleanup() or Item_ident::cleanup() here.
*/
- Item::cleanup();
+ Item_fixed_hybrid::cleanup();
}
@@ -9799,73 +9641,14 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
{
- Item_result res_type=item_cmp_type(field->result_type(),
- item->result_type());
- /*
- We have to check field->cmp_type() instead of res_type,
- as result_type() - and thus res_type - can never be TIME_RESULT (yet).
- */
- if (field->cmp_type() == TIME_RESULT)
+ Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison());
+ if (cmp.aggregate_for_comparison(item->type_handler_for_comparison()))
{
- MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
- if (field->type() == MYSQL_TYPE_TIME)
- {
- field->get_time(&field_time);
- item->get_time(&item_time);
- }
- else
- {
- field->get_date(&field_time, TIME_INVALID_DATES);
- item->get_date(&item_time, TIME_INVALID_DATES);
- if (item_time.time_type == MYSQL_TIMESTAMP_TIME)
- if (time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
- return 1;
- }
- return my_time_compare(&field_time, item_time_cmp);
- }
- if (res_type == STRING_RESULT)
- {
- char item_buff[MAX_FIELD_WIDTH];
- char field_buff[MAX_FIELD_WIDTH];
-
- String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin);
- String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
- String *item_result= item->val_str(&item_tmp);
- /*
- Some implementations of Item::val_str(String*) actually modify
- the field Item::null_value, hence we can't check it earlier.
- */
- if (item->null_value)
- return 0;
- String *field_result= field->val_str(&field_tmp);
- return sortcmp(field_result, item_result, field->charset());
- }
- if (res_type == INT_RESULT)
- return 0; // Both are of type int
- if (res_type == DECIMAL_RESULT)
- {
- my_decimal item_buf, *item_val,
- field_buf, *field_val;
- item_val= item->val_decimal(&item_buf);
- if (item->null_value)
- return 0;
- field_val= field->val_decimal(&field_buf);
- return my_decimal_cmp(field_val, item_val);
- }
- /*
- The patch for Bug#13463415 started using this function for comparing
- BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
- Prefixing the auto variables with volatile fixes the problem....
- */
- volatile double result= item->val_real();
- if (item->null_value)
+ // At fix_fields() time we checked that "field" and "item" are comparable
+ DBUG_ASSERT(0);
return 0;
- volatile double field_result= field->val_real();
- if (field_result < result)
- return -1;
- else if (field_result > result)
- return 1;
- return 0;
+ }
+ return cmp.type_handler()->stored_field_cmp_to_item(thd, field, item);
}
@@ -9928,7 +9711,6 @@ bool Item_cache_int::cache_value()
String *Item_cache_int::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
str->set_int(value, unsigned_flag, default_charset());
@@ -9938,7 +9720,6 @@ String *Item_cache_int::val_str(String *str)
my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
@@ -9947,7 +9728,6 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
double Item_cache_int::val_real()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0.0;
return (double) value;
@@ -9955,7 +9735,6 @@ double Item_cache_int::val_real()
longlong Item_cache_int::val_int()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return value;
@@ -9995,82 +9774,6 @@ Item_cache_temporal::Item_cache_temporal(THD *thd, const Type_handler *handler)
}
-longlong Item_cache_temporal::val_datetime_packed()
-{
- DBUG_ASSERT(fixed == 1);
- if (Item_cache_temporal::field_type() == MYSQL_TYPE_TIME)
- return Item::val_datetime_packed(); // TIME-to-DATETIME conversion needed
- if ((!value_cached && !cache_value()) || null_value)
- {
- null_value= TRUE;
- return 0;
- }
- return value;
-}
-
-
-longlong Item_cache_temporal::val_time_packed()
-{
- DBUG_ASSERT(fixed == 1);
- if (Item_cache_temporal::field_type() != MYSQL_TYPE_TIME)
- return Item::val_time_packed(); // DATETIME-to-TIME conversion needed
- if ((!value_cached && !cache_value()) || null_value)
- {
- null_value= TRUE;
- return 0;
- }
- return value;
-}
-
-
-String *Item_cache_temporal::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- if (!has_value())
- {
- null_value= true;
- return NULL;
- }
- return val_string_from_date(str);
-}
-
-
-my_decimal *Item_cache_temporal::val_decimal(my_decimal *decimal_value)
-{
- DBUG_ASSERT(fixed == 1);
- if ((!value_cached && !cache_value()) || null_value)
- {
- null_value= true;
- return NULL;
- }
- return val_decimal_from_date(decimal_value);
-}
-
-
-longlong Item_cache_temporal::val_int()
-{
- DBUG_ASSERT(fixed == 1);
- if ((!value_cached && !cache_value()) || null_value)
- {
- null_value= true;
- return 0;
- }
- return val_int_from_date();
-}
-
-
-double Item_cache_temporal::val_real()
-{
- DBUG_ASSERT(fixed == 1);
- if ((!value_cached && !cache_value()) || null_value)
- {
- null_value= true;
- return 0;
- }
- return val_real_from_date();
-}
-
-
bool Item_cache_temporal::cache_value()
{
if (!example)
@@ -10185,7 +9888,6 @@ bool Item_cache_real::cache_value()
double Item_cache_real::val_real()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0.0;
return value;
@@ -10193,7 +9895,6 @@ double Item_cache_real::val_real()
longlong Item_cache_real::val_int()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return (longlong) rint(value);
@@ -10202,7 +9903,6 @@ longlong Item_cache_real::val_int()
String* Item_cache_real::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
str->set_real(value, decimals, default_charset());
@@ -10212,7 +9912,6 @@ String* Item_cache_real::val_str(String *str)
my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
@@ -10247,38 +9946,22 @@ bool Item_cache_decimal::cache_value()
double Item_cache_decimal::val_real()
{
- DBUG_ASSERT(fixed);
- double res;
- if (!has_value())
- return 0.0;
- my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
- return res;
+ return !has_value() ? 0.0 : decimal_value.to_double();
}
longlong Item_cache_decimal::val_int()
{
- DBUG_ASSERT(fixed);
- longlong res;
- if (!has_value())
- return 0;
- my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
- return res;
+ return !has_value() ? 0 : decimal_value.to_longlong(unsigned_flag);
}
String* Item_cache_decimal::val_str(String *str)
{
- DBUG_ASSERT(fixed);
- if (!has_value())
- return NULL;
- my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
- &decimal_value);
- my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
- return str;
+ return !has_value() ? NULL :
+ decimal_value.to_string_round(str, decimals, &decimal_value);
}
my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
{
- DBUG_ASSERT(fixed);
if (!has_value())
return NULL;
return &decimal_value;
@@ -10295,9 +9978,8 @@ Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd)
new_item= (Item*) new (thd->mem_root) Item_null(thd);
else
{
- my_decimal decimal_value;
- my_decimal *result= val_decimal(&decimal_value);
- new_item= (Item*) new (thd->mem_root) Item_decimal(thd, result);
+ VDec tmp(this);
+ new_item= (Item*) new (thd->mem_root) Item_decimal(thd, tmp.ptr());
}
return new_item;
}
@@ -10330,7 +10012,6 @@ bool Item_cache_str::cache_value()
double Item_cache_str::val_real()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0.0;
return value ? double_from_string_with_check(value) : 0.0;
@@ -10339,7 +10020,6 @@ double Item_cache_str::val_real()
longlong Item_cache_str::val_int()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return value ? longlong_from_string_with_check(value) : 0;
@@ -10348,7 +10028,6 @@ longlong Item_cache_str::val_int()
String* Item_cache_str::val_str(String *str)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return value;
@@ -10357,7 +10036,6 @@ String* Item_cache_str::val_str(String *str)
my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return NULL;
return value ? decimal_from_string_with_check(decimal_val, value) : 0;
@@ -10550,7 +10228,7 @@ bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
void Item_result_field::cleanup()
{
DBUG_ENTER("Item_result_field::cleanup()");
- Item::cleanup();
+ Item_fixed_hybrid::cleanup();
result_field= 0;
DBUG_VOID_RETURN;
}
diff --git a/sql/item.h b/sql/item.h
index 48b060095af..c013781f30f 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -99,7 +99,10 @@ class sp_head;
class Protocol;
struct TABLE_LIST;
void item_init(void); /* Init item functions */
+class Item_basic_value;
+class Item_result_field;
class Item_field;
+class Item_ref;
class Item_param;
class user_var_entry;
class JOIN;
@@ -107,6 +110,7 @@ struct KEY_FIELD;
struct SARGABLE_PARAM;
class RANGE_OPT_PARAM;
class SEL_TREE;
+class With_sum_func_cache;
enum precedence {
LOWEST_PRECEDENCE,
@@ -595,6 +599,7 @@ typedef bool (Item::*Item_processor) (void *arg);
typedef bool (Item::*Item_analyzer) (uchar **argp);
typedef Item* (Item::*Item_transformer) (THD *thd, uchar *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
+typedef bool (Item::*Pushdown_checker) (uchar *arg);
struct st_cond_statistic;
@@ -627,6 +632,85 @@ public:
String_copier_for_item(THD *thd): m_thd(thd) { }
};
+
+/**
+ A helper class describing what kind of Item created a temporary field.
+ - If m_field is set, then the temporary field was created from Field
+ (e.g. when the Item was Item_field, or Item_ref pointing to Item_field)
+ - If m_default_field is set, then there is a usable DEFAULT value.
+ (e.g. when the Item is Item_field)
+ - If m_item_result_field is set, then the temporary field was created
+ from certain sub-types of Item_result_field (e.g. Item_func)
+ See create_tmp_field() in sql_select.cc for details.
+*/
+
+class Tmp_field_src
+{
+ Field *m_field;
+ Field *m_default_field;
+ Item_result_field *m_item_result_field;
+public:
+ Tmp_field_src()
+ :m_field(0),
+ m_default_field(0),
+ m_item_result_field(0)
+ { }
+ Field *field() const { return m_field; }
+ Field *default_field() const { return m_default_field; }
+ Item_result_field *item_result_field() const { return m_item_result_field; }
+ void set_field(Field *field) { m_field= field; }
+ void set_default_field(Field *field) { m_default_field= field; }
+ void set_item_result_field(Item_result_field *item)
+ { m_item_result_field= item; }
+};
+
+
+/**
+ Parameters for create_tmp_field_ex().
+ See create_tmp_field() in sql_select.cc for details.
+*/
+
+class Tmp_field_param
+{
+ bool m_group;
+ bool m_modify_item;
+ bool m_table_cant_handle_bit_fields;
+ bool m_make_copy_field;
+public:
+ Tmp_field_param(bool group,
+ bool modify_item,
+ bool table_cant_handle_bit_fields,
+ bool make_copy_field)
+ :m_group(group),
+ m_modify_item(modify_item),
+ m_table_cant_handle_bit_fields(table_cant_handle_bit_fields),
+ m_make_copy_field(make_copy_field)
+ { }
+ bool group() const { return m_group; }
+ bool modify_item() const { return m_modify_item; }
+ bool table_cant_handle_bit_fields() const
+ { return m_table_cant_handle_bit_fields; }
+ bool make_copy_field() const { return m_make_copy_field; }
+ void set_modify_item(bool to) { m_modify_item= to; }
+};
+
+
+class Item_const
+{
+public:
+ virtual ~Item_const() {}
+ virtual const Type_all_attributes *get_type_all_attributes_from_const() const= 0;
+ virtual bool const_is_null() const { return false; }
+ virtual const longlong *const_ptr_longlong() const { return NULL; }
+ virtual const double *const_ptr_double() const { return NULL; }
+ virtual const my_decimal *const_ptr_my_decimal() const { return NULL; }
+ virtual const MYSQL_TIME *const_ptr_mysql_time() const { return NULL; }
+ virtual const String *const_ptr_string() const { return NULL; }
+};
+
+
+/****************************************************************************/
+
class Item: public Value_source,
public Type_all_attributes
{
@@ -651,16 +735,26 @@ public:
static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM,
- WINDOW_FUNC_ITEM, STRING_ITEM,
- INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM,
- COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM,
- PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
- FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
+ WINDOW_FUNC_ITEM,
+ /*
+ NOT NULL literal-alike constants, which do not change their
+ value during an SQL statement execution, but can optionally
+ change their value between statements:
+ - Item_literal - real NOT NULL constants
+ - Item_param - can change between statements
+ - Item_splocal - can change between statements
+ - Item_user_var_as_out_param - hack
+ Note, Item_user_var_as_out_param actually abuses the type code.
+ It should be moved out of the Item tree eventually.
+ */
+ CONST_ITEM,
+ NULL_ITEM, // Item_null or Item_param bound to NULL
+ 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, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
- XPATH_NODESET, XPATH_NODESET_CMP,
- VIEW_FIXER_ITEM, EXPR_CACHE_ITEM,
- DATE_ITEM};
+ PARAM_ITEM, TRIGGER_FIELD_ITEM,
+ EXPR_CACHE_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@@ -702,11 +796,34 @@ protected:
*/
Field *tmp_table_field_from_field_type(TABLE *table)
{
+ DBUG_ASSERT(is_fixed());
const Type_handler *h= type_handler()->type_handler_for_tmp_table(this);
return h->make_and_init_table_field(&name, Record_addr(maybe_null),
*this, table);
}
+ /**
+ Create a temporary field for a simple Item, which does not
+ need any special action after the field creation:
+ - is not an Item_field descendant (and not a reference to Item_field)
+ - is not an Item_result_field descendant
+ - does not need to copy any DEFAULT value to the result Field
+ - does not need to set Field::is_created_from_null_item for the result
+ See create_tmp_field_ex() for details on parameters and return values.
+ */
+ Field *create_tmp_field_ex_simple(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(!param->make_copy_field());
+ DBUG_ASSERT(!is_result_field());
+ DBUG_ASSERT(type() != NULL_ITEM);
+ return tmp_table_field_from_field_type(table);
+ }
Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
+ Field *tmp_table_field_from_field_type_maybe_null(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param,
+ bool is_explicit_null);
void push_note_converted_to_negative_complement(THD *thd);
void push_note_converted_to_positive_complement(THD *thd);
@@ -714,21 +831,21 @@ protected:
/* Helper methods, to get an Item value from another Item */
double val_real_from_item(Item *item)
{
- DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(is_fixed());
double value= item->val_real();
null_value= item->null_value;
return value;
}
longlong val_int_from_item(Item *item)
{
- DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(is_fixed());
longlong value= item->val_int();
null_value= item->null_value;
return value;
}
String *val_str_from_item(Item *item, String *str)
{
- DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(is_fixed());
String *res= item->val_str(str);
if (res)
res->set_charset(collation.collation);
@@ -738,7 +855,7 @@ protected:
}
my_decimal *val_decimal_from_item(Item *item, my_decimal *decimal_value)
{
- DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(is_fixed());
my_decimal *value= item->val_decimal(decimal_value);
if ((null_value= item->null_value))
value= NULL;
@@ -750,6 +867,7 @@ protected:
null_value= MY_TEST(rc || item->null_value);
return rc;
}
+public:
/*
This method is used if the item was not null but convertion to
TIME/DATE/DATETIME failed. We return a zero date if allowed,
@@ -757,12 +875,12 @@ protected:
*/
bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
-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); }
+ virtual Item_func *get_item_func() { return NULL; }
const MY_LOCALE *locale_from_val_str();
@@ -782,14 +900,12 @@ public:
bool in_rollup; /* If used in GROUP BY list
of a query with ROLLUP */
bool null_value; /* if item is null */
- bool with_sum_func; /* True if item contains a sum func */
bool with_param; /* True if contains an SP parameter */
bool with_window_func; /* True if item contains a window func */
/**
True if any item except Item_sum contains a field. Set during parsing.
*/
bool with_field;
- bool fixed; /* If item fixed with fix_fields */
bool is_autogenerated_name; /* indicate was name of this Item
autogenerated or set by user */
// alloc & destruct is done as start of select on THD::mem_root
@@ -819,7 +935,7 @@ public:
bool fix_fields_if_needed(THD *thd, Item **ref)
{
- return fixed ? false : fix_fields(thd, ref);
+ return is_fixed() ? false : fix_fields(thd, ref);
}
bool fix_fields_if_needed_for_scalar(THD *thd, Item **ref)
{
@@ -833,7 +949,27 @@ public:
{
return fix_fields_if_needed_for_scalar(thd, ref);
}
- virtual bool fix_fields(THD *, Item **);
+ /*
+ By default we assume that an Item is fixed by the contstructor.
+ */
+ virtual bool fix_fields(THD *, Item **)
+ {
+ /*
+ This should not normally be called, because usually before
+ fix_fields() we check is_fixed() to be false.
+ But historically we allow fix_fields() to be called for Items
+ who return basic_const_item()==true.
+ */
+ DBUG_ASSERT(is_fixed());
+ DBUG_ASSERT(basic_const_item());
+ return false;
+ }
+ virtual bool is_fixed() const { return true; }
+ virtual void unfix_fields()
+ {
+ DBUG_ASSERT(0);
+ }
+
/*
Fix after some tables has been pulled out. Basically re-calculate all
attributes that are dependent on the tables.
@@ -853,7 +989,10 @@ public:
but rather uses intermediate type conversion items. Then the method is
supposed to be applied recursively.
*/
- virtual inline void quick_fix_field() { fixed= 1; }
+ virtual void quick_fix_field()
+ {
+ DBUG_ASSERT(0);
+ }
bool save_in_value(struct st_value *value)
{
@@ -882,6 +1021,21 @@ public:
return type_handler()->field_type();
}
virtual const Type_handler *type_handler() const= 0;
+ /**
+ Detects if an Item has a fixed data type which is known
+ even before fix_fields().
+ Currently it's important only to find Items with a fixed boolean
+ data type. More item types can be marked in the future as having
+ a fixed data type (e.g. all literals, all fixed type functions, etc).
+
+ @retval NULL if the Item type is not known before fix_fields()
+ @retval the pointer to the data type handler, if the data type
+ is known before fix_fields().
+ */
+ virtual const Type_handler *fixed_type_handler() const
+ {
+ return NULL;
+ }
const Type_handler *type_handler_for_comparison() const
{
return type_handler()->type_handler_for_comparison();
@@ -890,13 +1044,9 @@ public:
{
return type_handler();
}
- virtual const Type_handler *cast_to_int_type_handler() const
- {
- return type_handler();
- }
- virtual const Type_handler *type_handler_for_system_time() const
+ const Type_handler *cast_to_int_type_handler() const
{
- return real_type_handler();
+ return real_type_handler()->cast_to_int_type_handler();
}
/* result_type() of an item specifies how the value should be returned */
Item_result result_type() const
@@ -952,6 +1102,10 @@ public:
return type_handler()->Item_get_cache(thd, this);
}
virtual enum Type type() const =0;
+ bool is_of_type(Type t, Item_result cmp) const
+ {
+ return type() == t && cmp_type() == cmp;
+ }
/*
real_type() is the type of base item. This is same as type() for
most items, except Item_ref() and Item_cache_wrapper() where it
@@ -1048,7 +1202,6 @@ public:
{
return cast_to_int_type_handler()->Item_val_int_unsigned_typecast(this);
}
- longlong val_int_unsigned_typecast_from_decimal();
longlong val_int_unsigned_typecast_from_int();
longlong val_int_unsigned_typecast_from_str();
/*
@@ -1214,7 +1367,7 @@ public:
{
return type_handler()->Item_val_bool(this);
}
- virtual String *val_nodeset(String*) { return 0; }
+ virtual String *val_raw(String*) { return 0; }
/*
save_val() is method of val_* family which stores value in the given
@@ -1229,28 +1382,15 @@ public:
/* 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);
- String *val_string_from_date(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);
- my_decimal *val_decimal_from_date(my_decimal *decimal_value);
- my_decimal *val_decimal_from_time(my_decimal *decimal_value);
- longlong val_int_from_decimal();
- longlong val_int_from_date();
longlong val_int_from_real()
{
- DBUG_ASSERT(fixed == 1);
+ DBUG_ASSERT(is_fixed());
return Converter_double_to_longlong_with_warn(val_real(), false).result();
}
longlong val_int_from_str(int *error);
- double val_real_from_decimal();
- double val_real_from_date();
-
- // 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, bool no_conversions);
int save_date_in_field(Field *field, bool no_conversions);
@@ -1310,6 +1450,14 @@ public:
a constant expression. Used in the optimizer to propagate basic constants.
*/
virtual bool basic_const_item() const { return 0; }
+ /*
+ Test if "this" is an ORDER position (rather than an expression).
+ Notes:
+ - can be called before fix_fields().
+ - local SP variables (even of integer types) are always expressions, not
+ positions. (And they can't be used before fix_fields is called for them).
+ */
+ virtual bool is_order_clause_position() const { return false; }
/* cloning of constant items (0 if it is not const) */
virtual Item *clone_item(THD *thd) { return 0; }
virtual Item* build_clone(THD *thd) { return get_copy(thd); }
@@ -1464,58 +1612,20 @@ public:
Item **ref, uint flags);
virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 0;
bool get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_year(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_real(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_decimal(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_string(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_time(MYSQL_TIME *ltime)
{ return get_date(ltime, Time::flags_for_get_date()); }
- /*
- Get time with automatic DATE/DATETIME to TIME conversion,
- by subtracting CURRENT_DATE.
-
- Performce a reverse operation to CAST(time AS DATETIME)
- Suppose:
- - we have a set of items (typically with the native MYSQL_TYPE_TIME type)
- whose item->get_date() return TIME1 value, and
- - CAST(AS DATETIME) for the same Items return DATETIME1,
- after applying time-to-datetime conversion to TIME1.
-
- then all items (typically of the native MYSQL_TYPE_{DATE|DATETIME} types)
- whose get_date() return DATETIME1 must also return TIME1 from
- get_time_with_conversion()
-
- @param thd - the thread, its variables.old_mode is checked
- to decide if use simple YYYYMMDD truncation (old mode),
- or perform full DATETIME-to-TIME conversion with
- CURRENT_DATE subtraction.
- @param[out] ltime - store the result here
- @param fuzzydate - flags to be used for the get_date() call.
- Normally, should include TIME_TIME_ONLY, to let
- the called low-level routines, e.g. str_to_date(),
- know that we prefer TIME rather that DATE/DATETIME
- and do less conversion outside of the low-level
- routines.
-
- @returns true - on error, e.g. get_date() returned NULL value,
- or get_date() returned DATETIME/DATE with non-zero
- YYYYMMDD part.
- @returns false - on success
- */
- bool get_time_with_conversion(THD *thd, MYSQL_TIME *ltime,
- ulonglong fuzzydate);
// Get a DATE or DATETIME value in numeric packed format for comparison
virtual longlong val_datetime_packed()
{
- ulonglong fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES;
- Datetime dt(current_thd, this, fuzzydate);
- return dt.is_valid_datetime() ? pack_time(dt.get_mysql_time()) : 0;
+ ulonglong fuzzydate= Datetime::comparison_flags_for_get_date();
+ return Datetime(current_thd, this, fuzzydate).to_packed();
}
// Get a TIME value in numeric packed format for comparison
virtual longlong val_time_packed()
{
- Time tm(this, Time::comparison_flags_for_get_date());
- return tm.is_valid_time() ? pack_time(tm.get_mysql_time()) : 0;
+ return Time(this, Time::comparison_flags_for_get_date()).to_packed();
}
longlong val_datetime_packed_result();
longlong val_time_packed_result()
@@ -1525,13 +1635,6 @@ public:
return get_date_result(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
}
- // Get a temporal value in packed DATE/DATETIME or TIME format
- longlong val_temporal_packed(enum_field_types f_type)
- {
- return f_type == MYSQL_TYPE_TIME ? val_time_packed() :
- val_datetime_packed();
- }
- bool get_seconds(ulonglong *sec, ulong *sec_part);
virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return get_date(ltime,fuzzydate); }
/*
@@ -1548,35 +1651,7 @@ public:
*/
virtual void update_null_value ()
{
- switch (cmp_type()) {
- case INT_RESULT:
- (void) val_int();
- break;
- case REAL_RESULT:
- (void) val_real();
- break;
- case DECIMAL_RESULT:
- {
- my_decimal tmp;
- (void) val_decimal(&tmp);
- }
- break;
- case TIME_RESULT:
- {
- MYSQL_TIME ltime;
- (void) get_temporal_with_sql_mode(&ltime);
- }
- break;
- case STRING_RESULT:
- {
- StringBuffer<MAX_FIELD_WIDTH> tmp;
- (void) val_str(&tmp);
- }
- break;
- case ROW_RESULT:
- DBUG_ASSERT(0);
- null_value= true;
- }
+ return type_handler()->Item_update_null_value(this);
}
/*
@@ -1594,10 +1669,9 @@ public:
set field of temporary table for Item which can be switched on temporary
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_type() { return false; }
virtual bool is_json_type() { return false; }
+ virtual bool is_bool_literal() const { return false; }
/* This is to handle printing of default values */
virtual bool need_parentheses_in_default() { return false; }
virtual void save_in_result_field(bool no_conversions) {}
@@ -1708,7 +1782,15 @@ public:
or can be converted to such an exression using equalities.
Not to be used for AND/OR formulas.
*/
- virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; }
+ virtual bool excl_dep_on_grouping_fields(st_select_lex *sel)
+ { return false; }
+ /*
+ TRUE if the expression depends only on fields from the left part of
+ IN subquery or can be converted to such an expression using equalities.
+ Not to be used for AND/OR formulas.
+ */
+ virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+ { return false; }
virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; }
virtual bool find_function_processor (void *arg) { return 0; }
@@ -1868,11 +1950,17 @@ public:
return Type_handler::type_handler_long_or_longlong(max_char_length());
}
- virtual Field *create_tmp_field(bool group, TABLE *table)
- {
- return tmp_table_field_from_field_type(table);
- }
-
+ /**
+ Create field for temporary table.
+ @param table Temporary table
+ @param [OUT] src Who created the fields
+ @param param Create parameters
+ @retval NULL (on error)
+ @retval a pointer to a newly create Field (on success)
+ */
+ virtual Field *create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)= 0;
virtual Item_field *field_for_view_update() { return 0; }
virtual Item *neg_transformer(THD *thd) { return NULL; }
@@ -1884,8 +1972,12 @@ public:
{ return this; }
virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg)
{ return this; }
- virtual Item *derived_grouping_field_transformer_for_where(THD *thd,
- uchar *arg)
+ virtual Item *grouping_field_transformer_for_where(THD *thd, uchar *arg)
+ { return this; }
+ /* Now is not used. */
+ virtual Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg)
+ { return this; }
+ virtual Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg)
{ return this; }
virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg)
{ return this; }
@@ -1939,6 +2031,7 @@ public:
delete this;
}
+ virtual const Item_const *get_item_const() const { return NULL; }
virtual Item_splocal *get_item_splocal() { return 0; }
virtual Rewritable_query_parameter *get_rewritable_query_parameter()
{ return 0; }
@@ -2012,13 +2105,16 @@ public:
/*
Return TRUE if the item points to a column of an outer-joined table.
*/
- virtual bool is_outer_field() const { DBUG_ASSERT(fixed); return FALSE; }
+ virtual bool is_outer_field() const { DBUG_ASSERT(is_fixed()); return FALSE; }
/**
Checks if this item or any of its decendents contains a subquery. This is a
replacement of the former Item::has_subquery() and Item::with_subselect.
*/
- virtual bool with_subquery() const { DBUG_ASSERT(fixed); return false; }
+ virtual bool with_subquery() const { DBUG_ASSERT(is_fixed()); return false; }
+
+ virtual bool with_sum_func() const { return false; }
+ virtual With_sum_func_cache* get_with_sum_func_cache() { return NULL; }
Item* set_expr_cache(THD *thd);
@@ -2082,6 +2178,33 @@ public:
{
marker &= ~EXTRACTION_MASK;
}
+ void check_pushable_cond(Pushdown_checker excl_dep_func, uchar *arg);
+ bool pushable_cond_checker_for_derived(uchar *arg)
+ {
+ return excl_dep_on_table(*((table_map *)arg));
+ }
+ bool pushable_cond_checker_for_subquery(uchar *arg)
+ {
+ return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg);
+ }
+ Item *get_corresponding_field_in_insubq(Item_in_subselect *subq_pred);
+ Item *build_pushable_cond(THD *thd,
+ Pushdown_checker checker,
+ uchar *arg);
+ /*
+ Checks if this item depends only on the arg table
+ */
+ bool pushable_equality_checker_for_derived(uchar *arg)
+ {
+ return (used_tables() == *((table_map *)arg));
+ }
+ /*
+ Checks if this item consists in the left part of arg IN subquery predicate
+ */
+ bool pushable_equality_checker_for_subquery(uchar *arg)
+ {
+ return get_corresponding_field_in_insubq((Item_in_subselect *)arg);
+ }
};
MEM_ROOT *get_thd_memroot(THD *thd);
@@ -2096,6 +2219,66 @@ inline Item* get_item_copy (THD *thd, T* item)
}
+#ifndef DBUG_OFF
+/**
+ A helper class to print the data type and the value for an Item
+ in debug builds.
+*/
+class DbugStringItemTypeValue: public StringBuffer<128>
+{
+public:
+ DbugStringItemTypeValue(THD *thd, const Item *item)
+ {
+ append('(');
+ append(item->type_handler()->name().ptr());
+ append(')');
+ const_cast<Item*>(item)->print(this, QT_EXPLAIN);
+ }
+};
+#endif
+
+class With_sum_func_cache
+{
+protected:
+ bool m_with_sum_func; // True if the owner item contains a sum func
+public:
+ With_sum_func_cache()
+ :m_with_sum_func(false)
+ { }
+ With_sum_func_cache(const Item *a)
+ :m_with_sum_func(a->with_sum_func())
+ { }
+ With_sum_func_cache(const Item *a, const Item *b)
+ :m_with_sum_func(a->with_sum_func() || b->with_sum_func())
+ { }
+ With_sum_func_cache(const Item *a, const Item *b, const Item *c)
+ :m_with_sum_func(a->with_sum_func() || b->with_sum_func() ||
+ c->with_sum_func())
+ { }
+ With_sum_func_cache(const Item *a, const Item *b, const Item *c,
+ const Item *d)
+ :m_with_sum_func(a->with_sum_func() || b->with_sum_func() ||
+ c->with_sum_func() || d->with_sum_func())
+ { }
+ With_sum_func_cache(const Item *a, const Item *b, const Item *c,
+ const Item *d, const Item *e)
+ :m_with_sum_func(a->with_sum_func() || b->with_sum_func() ||
+ c->with_sum_func() || d->with_sum_func() ||
+ e->with_sum_func())
+ { }
+ void set_with_sum_func() { m_with_sum_func= true; }
+ void reset_with_sum_func() { m_with_sum_func= false; }
+ void copy_with_sum_func(const Item *item)
+ {
+ m_with_sum_func= item->with_sum_func();
+ }
+ void join_with_sum_func(const Item *item)
+ {
+ m_with_sum_func|= item->with_sum_func();
+ }
+};
+
+
/*
This class is a replacement for the former member Item::with_subselect.
Determines if the descendant Item is a subselect or some of
@@ -2210,6 +2393,17 @@ protected:
}
return true;
}
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+ {
+ for (uint i= 0; i < arg_count; i++)
+ {
+ if (args[i]->const_item())
+ continue;
+ if (!args[i]->excl_dep_on_in_subq_left_part(subq_pred))
+ return false;
+ }
+ return true;
+ }
public:
Item_args(void)
:args(NULL), arg_count(0)
@@ -2261,6 +2455,30 @@ public:
{
args[arg_count++]= item;
}
+ /**
+ Extract row elements from the given position.
+ For example, for this input: (1,2),(3,4),(5,6)
+ pos=0 will extract (1,3,5)
+ pos=1 will extract (2,4,6)
+ @param thd - current thread, to allocate memory on its mem_root
+ @param rows - an array of compatible ROW-type items
+ @param pos - the element position to extract
+ */
+ bool alloc_and_extract_row_elements(THD *thd, const Item_args *rows, uint pos)
+ {
+ DBUG_ASSERT(rows->argument_count() > 0);
+ DBUG_ASSERT(rows->arguments()[0]->cols() > pos);
+ if (alloc_arguments(thd, rows->argument_count()))
+ return true;
+ for (uint i= 0; i < rows->argument_count(); i++)
+ {
+ DBUG_ASSERT(rows->arguments()[0]->cols() == rows->arguments()[i]->cols());
+ Item *arg= rows->arguments()[i]->element_index(pos);
+ add_argument(arg);
+ }
+ DBUG_ASSERT(argument_count() == rows->argument_count());
+ return false;
+ }
inline Item **arguments() const { return args; }
inline uint argument_count() const { return arg_count; }
inline void remove_arguments() { arg_count=0; }
@@ -2295,27 +2513,39 @@ public:
class Item_string;
-/**
- A common class for Item_basic_constant and Item_param
-*/
-class Item_basic_value :public Item
+class Item_fixed_hybrid: 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
+public:
+ bool fixed; // If item was fixed with fix_fields
+public:
+ Item_fixed_hybrid(THD *thd): Item(thd), fixed(false)
+ { }
+ Item_fixed_hybrid(THD *thd, Item_fixed_hybrid *item)
+ :Item(thd, item), fixed(item->fixed)
+ { }
+ bool fix_fields(THD *thd, Item **ref)
{
- return basic_const_item() && type() == type_arg;
+ DBUG_ASSERT(!fixed);
+ fixed= true;
+ return false;
}
- bool str_eq(const String *value,
- const String *other, CHARSET_INFO *cs, bool binary_cmp) const
+ void cleanup()
{
- return binary_cmp ?
- value->bin_eq(other) :
- collation.collation == cs && value->eq(other, collation.collation);
+ Item::cleanup();
+ fixed= false;
}
+ void quick_fix_field() { fixed= true; }
+ void unfix_fields() { fixed= false; }
+ bool is_fixed() const { return fixed; }
+};
+
+/**
+ A common class for Item_basic_constant and Item_param
+*/
+class Item_basic_value :public Item,
+ public Item_const
+{
protected:
// Value metadata, e.g. to make string processing easier
class Metadata: private MY_STRING_METADATA
@@ -2352,66 +2582,40 @@ protected:
fix_charset_and_length(str.charset(), dv, Metadata(&str));
}
Item_basic_value(THD *thd): Item(thd) {}
- /*
- 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
+public:
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
{
- 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);
+
+ /*
+ create_tmp_field_ex() for this type of Items is called for:
+ - CREATE TABLE ... SELECT
+ - In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const';
+ - In CURSORS:
+ DECLARE c CURSOR FOR SELECT 'test';
+ OPEN c;
+ */
+ return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ type() == Item::NULL_ITEM);
}
+ bool eq(const Item *item, bool binary_cmp) const;
+ const Type_all_attributes *get_type_all_attributes_from_const() const
+ { return this; }
};
class Item_basic_constant :public Item_basic_value
{
- table_map used_table_map;
public:
- Item_basic_constant(THD *thd): Item_basic_value(thd), used_table_map(0) {};
- void set_used_tables(table_map map) { used_table_map= map; }
- table_map used_tables() const { return used_table_map; }
- bool check_vcol_func_processor(void *arg) { return FALSE;}
+ Item_basic_constant(THD *thd): Item_basic_value(thd) {};
+ bool check_vcol_func_processor(void *arg) { return false; }
+ const Item_const *get_item_const() const { return this; }
virtual Item_basic_constant *make_string_literal_concat(THD *thd,
const LEX_CSTRING *)
{
DBUG_ASSERT(0);
return this;
}
- /* to prevent drop fixed flag (no need parent cleanup call) */
- void cleanup()
- {
- /*
- Restore the original field name as it might not have been allocated
- in the statement memory. If the name is auto generated, it must be
- done again between subsequent executions of a prepared statement.
- */
- if (orig_name)
- {
- name.str= orig_name;
- name.length= strlen(orig_name);
- }
- }
};
@@ -2422,7 +2626,7 @@ public:
- CASE expression (Item_case_expr);
*****************************************************************************/
-class Item_sp_variable :public Item
+class Item_sp_variable :public Item_fixed_hybrid
{
protected:
/*
@@ -2462,6 +2666,11 @@ public:
inline bool const_item() const;
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ return create_tmp_field_ex_simple(table, src, param);
+ }
inline int save_in_field(Field *field, bool no_conversions);
inline bool send(Protocol *protocol, st_value *buffer);
bool check_vcol_func_processor(void *arg)
@@ -2565,6 +2774,20 @@ public:
*/
Field *create_field_for_create_select(TABLE *table)
{ return create_table_field_from_handler(table); }
+
+ bool is_valid_limit_clause_variable_with_error() const
+ {
+ /*
+ In case if the variable has an anchored data type, e.g.:
+ DECLARE a TYPE OF t1.a;
+ type_handler() is set to &type_handler_null and this
+ function detects such variable as not valid in LIMIT.
+ */
+ if (type_handler()->is_limit_clause_valid_type())
+ return true;
+ my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
+ return false;
+ }
};
@@ -2711,11 +2934,10 @@ inline enum Item::Type Item_case_expr::type() const
extract a common base with class Item_ref, too.
*/
-class Item_name_const : public Item
+class Item_name_const : public Item_fixed_hybrid
{
Item *value_item;
Item *name_item;
- bool valid_args;
public:
Item_name_const(THD *thd, Item *name_arg, Item *val);
@@ -2740,6 +2962,17 @@ public:
return TRUE;
}
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ /*
+ We can get to here when using a CURSOR for a query with NAME_CONST():
+ DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
+ OPEN c;
+ */
+ return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ type() == Item::NULL_ITEM);
+ }
int save_in_field(Field *field, bool no_conversions)
{
return value_item->save_in_field(field, no_conversions);
@@ -2757,12 +2990,24 @@ public:
{ return get_item_copy<Item_name_const>(thd, this); }
};
-class Item_num: public Item_basic_constant
+
+class Item_literal: public Item_basic_constant
{
public:
- Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); }
+ Item_literal(THD *thd): Item_basic_constant(thd)
+ { }
+ enum Type type() const { return CONST_ITEM; }
+ bool check_partition_func_processor(void *int_arg) { return false;}
+ bool const_item() const { return true; }
+ bool basic_const_item() const { return true; }
+};
+
+
+class Item_num: public Item_literal
+{
+public:
+ Item_num(THD *thd): Item_literal(thd) { collation.set_numeric(); }
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
- bool check_partition_func_processor(void *int_arg) { return FALSE;}
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
return type_handler()->Item_get_date(this, ltime, fuzzydate);
@@ -2774,24 +3019,26 @@ public:
class st_select_lex;
-class Item_result_field :public Item /* Item with result field */
+class Item_result_field :public Item_fixed_hybrid /* Item with result field */
{
public:
Field *result_field; /* Save result here */
- Item_result_field(THD *thd): Item(thd), result_field(0) {}
+ Item_result_field(THD *thd): Item_fixed_hybrid(thd), result_field(0) {}
// Constructor used for Item_sum/Item_cond_and/or (see Item comment)
Item_result_field(THD *thd, Item_result_field *item):
- Item(thd, item), result_field(item->result_field)
+ Item_fixed_hybrid(thd, item), result_field(item->result_field)
{}
~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param);
+ void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param);
/*
This implementation of used_tables() used by Item_avg_field and
Item_variance_field which work when only temporary table left, so theu
return table map of the temporary table.
*/
table_map used_tables() const { return 1; }
- void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return true; }
void save_in_result_field(bool no_conversions)
{
@@ -2884,6 +3131,12 @@ public:
Type_std_attributes::set(par_field->type_std_attributes());
}
enum Type type() const { return FIELD_ITEM; }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
double val_real() { return field->val_real(); }
longlong val_int() { return field->val_int(); }
String *val_str(String *str) { return field->val_str(str); }
@@ -2989,16 +3242,17 @@ public:
const Type_handler *handler= field->type_handler();
return handler->type_handler_for_item_field();
}
- const Type_handler *cast_to_int_type_handler() const
- {
- return field->type_handler()->cast_to_int_type_handler();
- }
const Type_handler *real_type_handler() const
{
if (field->is_created_from_null_item)
return &type_handler_null;
return field->type_handler();
}
+ Field *create_tmp_field_from_item_field(TABLE *new_table,
+ Item_ref *orig_item,
+ const Tmp_field_param *param);
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param);
TYPELIB *get_typelib() const { return field->get_typelib(); }
enum_monotonicity_info get_monotonicity_info() const
{
@@ -3016,13 +3270,7 @@ public:
TABLE *tab= field->table;
tab->covering_keys.intersect(field->part_of_key);
if (tab->read_set)
- bitmap_fast_test_and_set(tab->read_set, field->field_index);
- /*
- Do not mark a self-referecing virtual column.
- Such virtual columns are reported as invalid.
- */
- if (field->vcol_info && tab->vcol_set)
- tab->mark_virtual_col(field);
+ tab->mark_column_with_deps(field);
}
}
void update_used_tables()
@@ -3099,10 +3347,13 @@ public:
virtual Item *update_value_transformer(THD *thd, uchar *select_arg);
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
- Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg);
+ Item *grouping_field_transformer_for_where(THD *thd, uchar *arg);
+ Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg);
+ Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg);
virtual void print(String *str, enum_query_type query_type);
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
bool cleanup_excluding_fields_processor(void *arg)
{ return field ? 0 : cleanup_processor(arg); }
bool cleanup_excluding_const_fields_processor(void *arg)
@@ -3207,11 +3458,9 @@ public:
max_length= 0;
name.str= name_par ? name_par : "NULL";
name.length= strlen(name.str);
- fixed= 1;
collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII);
}
enum Type type() const { return NULL_ITEM; }
- bool eq(const Item *item, bool binary_cmp) const { return null_eq(item); }
double val_real();
longlong val_int();
String *val_str(String *str);
@@ -3223,6 +3472,7 @@ public:
const Type_handler *type_handler() const { return &type_handler_null; }
bool basic_const_item() const { return 1; }
Item *clone_item(THD *thd);
+ bool const_is_null() const { return true; }
bool is_null() { return 1; }
virtual inline void print(String *str, enum_query_type query_type)
@@ -3248,6 +3498,12 @@ public:
{
return result_field->type();
}
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
void save_in_result_field(bool no_conversions)
{
save_in_field(result_field, no_conversions);
@@ -3315,8 +3571,8 @@ class Item_param :public Item_basic_value,
All Item_param::set_xxx() make sure to do so.
In the state with an assigned value:
- Item_param::basic_const_item() returns true
- - Item::type() returns NULL_ITEM, INT_ITEM, REAL_ITEM, DECIMAL_ITEM,
- DATE_ITEM, STRING_ITEM, depending on the value assigned.
+ - Item::type() returns NULL_ITEM or CONST_ITEM,
+ depending on the value assigned.
So in this state Item_param behaves in many cases like a literal.
When Item_param::cleanup() is called:
@@ -3339,14 +3595,6 @@ class Item_param :public Item_basic_value,
DEFAULT_VALUE, IGNORE_VALUE
} state;
- enum Type item_type;
-
- void fix_type(Type type)
- {
- item_type= type;
- fixed= true;
- }
-
void fix_temporal(uint32 max_length_arg, uint decimals_arg);
struct CONVERSION_INFO
@@ -3445,7 +3693,6 @@ class Item_param :public Item_basic_value,
PValue value;
const String *value_query_val_str(THD *thd, String* str) const;
- bool value_eq(const Item *item, bool binary_cmp) const;
Item *value_clone_item(THD *thd);
bool can_return_value() const;
@@ -3469,9 +3716,57 @@ public:
enum Type type() const
{
- DBUG_ASSERT(fixed || state == NO_VALUE);
- return item_type;
+ // Don't pretend to be a constant unless value for this item is set.
+ switch (state) {
+ case NO_VALUE: return PARAM_ITEM;
+ case NULL_VALUE: return NULL_ITEM;
+ case SHORT_DATA_VALUE: return CONST_ITEM;
+ case LONG_DATA_VALUE: return CONST_ITEM;
+ case DEFAULT_VALUE: return PARAM_ITEM;
+ case IGNORE_VALUE: return PARAM_ITEM;
+ }
+ DBUG_ASSERT(0);
+ return PARAM_ITEM;
+ }
+
+ bool is_order_clause_position() const
+ {
+ return state == SHORT_DATA_VALUE &&
+ type_handler()->is_order_clause_position_type();
+ }
+
+ const Item_const *get_item_const() const
+ {
+ switch (state) {
+ case SHORT_DATA_VALUE:
+ case LONG_DATA_VALUE:
+ case NULL_VALUE:
+ return this;
+ case IGNORE_VALUE:
+ case DEFAULT_VALUE:
+ case NO_VALUE:
+ break;
+ }
+ return NULL;
+ }
+
+ bool const_is_null() const { return state == NULL_VALUE; }
+ bool can_return_const_value(Item_result type) const
+ {
+ return can_return_value() &&
+ value.type_handler()->cmp_type() == type &&
+ type_handler()->cmp_type() == type;
}
+ const longlong *const_ptr_longlong() const
+ { return can_return_const_value(INT_RESULT) ? &value.integer : NULL; }
+ const double *const_ptr_double() const
+ { return can_return_const_value(REAL_RESULT) ? &value.real : NULL; }
+ const my_decimal *const_ptr_my_decimal() const
+ { return can_return_const_value(DECIMAL_RESULT) ? &value.m_decimal : NULL; }
+ const MYSQL_TIME *const_ptr_mysql_time() const
+ { return can_return_const_value(TIME_RESULT) ? &value.time : NULL; }
+ const String *const_ptr_string() const
+ { return can_return_const_value(STRING_RESULT) ? &value.m_string : NULL; }
double val_real()
{
@@ -3566,8 +3861,14 @@ public:
so no one will use parameters value in fix_fields still
parameter is constant during execution.
*/
+ bool const_item() const
+ {
+ return state != NO_VALUE;
+ }
virtual table_map used_tables() const
- { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
+ {
+ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT;
+ }
virtual void print(String *str, enum_query_type query_type);
bool is_null()
{ DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
@@ -3597,12 +3898,6 @@ public:
*/
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
Item *clone_item(THD *thd);
- /*
- Implement by-value equality evaluation if parameter value
- is set and is a basic constant (integer, real or string).
- Otherwise return FALSE.
- */
- bool eq(const Item *item, bool binary_cmp) const;
void set_param_type_and_swap_value(Item_param *from);
Rewritable_query_parameter *get_rewritable_query_parameter()
@@ -3640,50 +3935,44 @@ public:
longlong value;
Item_int(THD *thd, int32 i,size_t length= MY_INT32_NUM_DECIMAL_DIGITS):
Item_num(thd), value((longlong) i)
- { max_length=(uint32)length; fixed= 1; }
+ { max_length=(uint32)length; }
Item_int(THD *thd, longlong i,size_t length= MY_INT64_NUM_DECIMAL_DIGITS):
Item_num(thd), value(i)
- { max_length=(uint32)length; fixed= 1; }
+ { max_length=(uint32)length; }
Item_int(THD *thd, ulonglong i, size_t length= MY_INT64_NUM_DECIMAL_DIGITS):
Item_num(thd), value((longlong)i)
- { max_length=(uint32)length; fixed= 1; unsigned_flag= 1; }
+ { max_length=(uint32)length; unsigned_flag= 1; }
Item_int(THD *thd, const char *str_arg,longlong i,size_t length):
Item_num(thd), value(i)
{
max_length=(uint32)length;
name.str= str_arg; name.length= safe_strlen(name.str);
- fixed= 1;
}
Item_int(THD *thd, const char *str_arg,longlong i,size_t length, bool flag):
Item_num(thd), value(i)
{
max_length=(uint32)length;
name.str= str_arg; name.length= safe_strlen(name.str);
- fixed= 1;
unsigned_flag= flag;
}
Item_int(THD *thd, const char *str_arg, size_t length=64);
- enum Type type() const { return INT_ITEM; }
const Type_handler *type_handler() const
{ return type_handler_long_or_longlong(); }
- Field *create_tmp_field(bool group, TABLE *table)
- { return tmp_table_field_from_field_type(table); }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table); }
- longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- longlong val_int_min() const { DBUG_ASSERT(fixed == 1); return value; }
- double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ const longlong *const_ptr_longlong() const { return &value; }
+ longlong val_int() { return value; }
+ longlong val_int_min() const { return value; }
+ double val_real() { 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; }
+ bool is_order_clause_position() const { return true; }
Item *clone_item(THD *thd);
virtual void print(String *str, enum_query_type query_type);
Item *neg(THD *thd);
uint decimal_precision() const
{ return (uint) (max_length - MY_TEST(value < 0)); }
- bool eq(const Item *item, bool binary_cmp) const
- { return int_eq(value, item); }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_int>(thd, this); }
};
@@ -3699,8 +3988,20 @@ class Item_bool :public Item_int
public:
Item_bool(THD *thd, const char *str_arg, longlong i):
Item_int(thd, str_arg, i, 1) {}
- bool is_bool_type() { return true; }
+ Item_bool(THD *thd, bool i) :Item_int(thd, (longlong) i, 1) { }
+ bool is_bool_literal() const { return true; }
Item *neg_transformer(THD *thd);
+ const Type_handler *type_handler() const
+ { return &type_handler_bool; }
+ const Type_handler *fixed_type_handler() const
+ { return &type_handler_bool; }
+ void quick_fix_field()
+ {
+ /*
+ We can get here when Item_bool is created instead of a constant
+ predicate at various condition optimization stages in sql_select.
+ */
+ }
};
@@ -3710,8 +4011,7 @@ public:
Item_uint(THD *thd, const char *str_arg, size_t length);
Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {}
Item_uint(THD *thd, const char *str_arg, longlong i, uint length);
- double val_real()
- { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); }
+ double val_real() { return ulonglong2double((ulonglong)value); }
String *val_str(String*);
Item *clone_item(THD *thd);
virtual void print(String *str, enum_query_type query_type);
@@ -3750,24 +4050,26 @@ public:
CHARSET_INFO *charset);
Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
uint decimal_par, uint length);
- Item_decimal(THD *thd, my_decimal *value_par);
+ Item_decimal(THD *thd, const my_decimal *value_par);
Item_decimal(THD *thd, longlong val, bool unsig);
Item_decimal(THD *thd, double val, int precision, int scale);
Item_decimal(THD *thd, const uchar *bin, int precision, int scale);
- enum Type type() const { return DECIMAL_ITEM; }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
- longlong val_int();
- double val_real();
- String *val_str(String*);
+ longlong val_int() { return decimal_value.to_longlong(unsigned_flag); }
+ double val_real() { return decimal_value.to_double(); }
+ String *val_str(String *to) { return decimal_value.to_string(to); }
my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
+ const my_decimal *const_ptr_my_decimal() const { return &decimal_value; }
int save_in_field(Field *field, bool no_conversions);
- bool basic_const_item() const { return 1; }
Item *clone_item(THD *thd);
- virtual void print(String *str, enum_query_type query_type);
+ virtual void print(String *str, enum_query_type query_type)
+ {
+ decimal_value.to_string(&str_value);
+ str->append(str_value);
+ }
Item *neg(THD *thd);
uint decimal_precision() const { return decimal_value.precision(); }
- bool eq(const Item *, bool binary_cmp) const;
void set_decimal_value(my_decimal *value_par);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_decimal>(thd, this); }
@@ -3787,21 +4089,18 @@ public:
name.length= safe_strlen(str);
decimals=(uint8) decimal_par;
max_length= length;
- fixed= 1;
}
Item_float(THD *thd, double value_par, uint decimal_par):
Item_num(thd), presentation(0), value(value_par)
{
decimals= (uint8) decimal_par;
- fixed= 1;
}
int save_in_field(Field *field, bool no_conversions);
- enum Type type() const { return REAL_ITEM; }
const Type_handler *type_handler() const { return &type_handler_double; }
- double val_real() { DBUG_ASSERT(fixed == 1); return value; }
+ const double *const_ptr_double() const { return &value; }
+ double val_real() { return value; }
longlong val_int()
{
- DBUG_ASSERT(fixed == 1);
if (value <= (double) LONGLONG_MIN)
{
return LONGLONG_MIN;
@@ -3814,12 +4113,9 @@ public:
}
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
- bool basic_const_item() const { return 1; }
Item *clone_item(THD *thd);
Item *neg(THD *thd);
virtual void print(String *str, enum_query_type query_type);
- bool eq(const Item *item, bool binary_cmp) const
- { return real_eq(value, item); }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_float>(thd, this); }
};
@@ -3846,14 +4142,12 @@ public:
};
-class Item_string :public Item_basic_constant
+class Item_string :public Item_literal
{
protected:
void fix_from_value(Derivation dv, const Metadata metadata)
{
fix_charset_and_length(str_value.charset(), dv, metadata);
- // it is constant => can be used without fix_fields (and frequently used)
- fixed= 1;
}
void fix_and_set_name_from_value(THD *thd, Derivation dv,
const Metadata metadata)
@@ -3864,41 +4158,41 @@ protected:
protected:
/* Just create an item and do not fill string representation */
Item_string(THD *thd, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE):
- Item_basic_constant(thd)
+ Item_literal(thd)
{
collation.set(cs, dv);
max_length= 0;
set_name(thd, NULL, 0, system_charset_info);
decimals= NOT_FIXED_DEC;
- fixed= 1;
}
public:
- Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg):
- Item_basic_constant(thd)
+ Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg)
+ :Item_literal(thd)
{
collation.set(csi, DERIVATION_COERCIBLE);
set_name(thd, NULL, 0, system_charset_info);
decimals= NOT_FIXED_DEC;
- fixed= 1;
str_value.copy(str_arg, length_arg, csi);
max_length= str_value.numchars() * csi->mbmaxlen;
}
// Constructors with the item name set from its value
Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs,
- Derivation dv, uint repertoire): Item_basic_constant(thd)
+ Derivation dv, uint repertoire)
+ :Item_literal(thd)
{
str_value.set_or_copy_aligned(str, length, cs);
fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire));
}
Item_string(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE):
- Item_basic_constant(thd)
+ CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
+ :Item_literal(thd)
{
str_value.set_or_copy_aligned(str, length, cs);
fix_and_set_name_from_value(thd, dv, Metadata(&str_value));
}
Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors,
- Derivation dv, uint repertoire): Item_basic_constant(thd)
+ Derivation dv, uint repertoire)
+ :Item_literal(thd)
{
if (str_value.copy(str, tocs, conv_errors))
str_value.set("", 0, tocs); // EOM ?
@@ -3907,16 +4201,16 @@ public:
}
// Constructors with an externally provided item name
Item_string(THD *thd, const char *name_par, const char *str, size_t length,
- CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE):
- Item_basic_constant(thd)
+ CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
+ :Item_literal(thd)
{
str_value.set_or_copy_aligned(str, length, cs);
fix_from_value(dv, Metadata(&str_value));
set_name(thd, name_par,safe_strlen(name_par), system_charset_info);
}
Item_string(THD *thd, const char *name_par, const char *str, size_t length,
- CHARSET_INFO *cs, Derivation dv, uint repertoire):
- Item_basic_constant(thd)
+ CHARSET_INFO *cs, Derivation dv, uint repertoire)
+ :Item_literal(thd)
{
str_value.set_or_copy_aligned(str, length, cs);
fix_from_value(dv, Metadata(&str_value, repertoire));
@@ -3926,12 +4220,14 @@ public:
{
str_value.print(to);
}
- enum Type type() const { return STRING_ITEM; }
double val_real();
longlong val_int();
+ const String *const_ptr_string() const
+ {
+ return &str_value;
+ }
String *val_str(String*)
{
- DBUG_ASSERT(fixed == 1);
return (String*) &str_value;
}
my_decimal *val_decimal(my_decimal *);
@@ -3941,11 +4237,6 @@ public:
}
int save_in_field(Field *field, bool no_conversions);
const Type_handler *type_handler() const { return &type_handler_varchar; }
- bool basic_const_item() const { return 1; }
- bool eq(const Item *item, bool binary_cmp) const
- {
- return str_eq(&str_value, item, binary_cmp);
- }
Item *clone_item(THD *thd);
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
@@ -3957,7 +4248,6 @@ public:
max_length= str_value.numchars() * collation.collation->mbmaxlen;
}
virtual void print(String *str, enum_query_type query_type);
- bool check_partition_func_processor(void *int_arg) {return FALSE;}
/**
Return TRUE if character-set-introducer was explicitly specified in the
@@ -3986,34 +4276,6 @@ public:
String *check_well_formed_result(bool send_error)
{ return Item::check_well_formed_result(&str_value, send_error); }
- enum_field_types odbc_temporal_literal_type(const LEX_CSTRING *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
- }
Item_basic_constant *make_string_literal_concat(THD *thd,
const LEX_CSTRING *);
Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr);
@@ -4200,35 +4462,27 @@ public:
/**
Item_hex_constant -- a common class for hex literals: X'HHHH' and 0xHHHH
*/
-class Item_hex_constant: public Item_basic_constant
+class Item_hex_constant: public Item_literal
{
private:
void hex_string_init(THD *thd, const char *str, size_t str_length);
public:
- Item_hex_constant(THD *thd): Item_basic_constant(thd)
+ Item_hex_constant(THD *thd): Item_literal(thd)
{
hex_string_init(thd, "", 0);
}
Item_hex_constant(THD *thd, const char *str, size_t str_length):
- Item_basic_constant(thd)
+ Item_literal(thd)
{
hex_string_init(thd, str, str_length);
}
- enum Type type() const { return VARBIN_ITEM; }
const Type_handler *type_handler() const { return &type_handler_varchar; }
virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
return const_charset_converter(thd, tocs, true);
}
- bool check_partition_func_processor(void *int_arg) {return FALSE;}
- bool basic_const_item() const { return 1; }
- bool eq(const Item *item, bool binary_cmp) const
- {
- return item->basic_const_item() && item->type() == type() &&
- item->cast_to_int_type_handler() == cast_to_int_type_handler() &&
- str_value.bin_eq(&((Item_hex_constant*)item)->str_value);
- }
- String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
+ const String *const_ptr_string() const { return &str_value; }
+ String *val_str(String*) { return &str_value; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
return type_handler()->Item_get_date(this, ltime, fuzzydate);
@@ -4247,22 +4501,18 @@ public:
Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {}
Item_hex_hybrid(THD *thd, const char *str, size_t str_length):
Item_hex_constant(thd, str, str_length) {}
+ const Type_handler *type_handler() const { return &type_handler_hex_hybrid; }
uint decimal_precision() const;
double val_real()
{
- DBUG_ASSERT(fixed == 1);
return (double) (ulonglong) Item_hex_hybrid::val_int();
}
longlong val_int()
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
return longlong_from_hex_hybrid(str_value.ptr(), str_value.length());
}
my_decimal *val_decimal(my_decimal *decimal_value)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
longlong value= Item_hex_hybrid::val_int();
int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
return decimal_value;
@@ -4272,14 +4522,6 @@ public:
field->set_notnull();
return field->store_hex_hybrid(str_value.ptr(), str_value.length());
}
- const Type_handler *cast_to_int_type_handler() const
- {
- return &type_handler_longlong;
- }
- const Type_handler *type_handler_for_system_time() const
- {
- return &type_handler_longlong;
- }
void print(String *str, enum_query_type query_type);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_hex_hybrid>(thd, this); }
@@ -4303,12 +4545,10 @@ public:
Item_hex_constant(thd, str, str_length) {}
longlong val_int()
{
- DBUG_ASSERT(fixed == 1);
return longlong_from_string_with_check(&str_value);
}
double val_real()
{
- DBUG_ASSERT(fixed == 1);
return double_from_string_with_check(&str_value);
}
my_decimal *val_decimal(my_decimal *decimal_value)
@@ -4334,7 +4574,7 @@ public:
};
-class Item_temporal_literal :public Item_basic_constant
+class Item_temporal_literal :public Item_literal
{
protected:
MYSQL_TIME cached_time;
@@ -4344,37 +4584,21 @@ public:
@param ltime DATE value.
*/
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime)
- :Item_basic_constant(thd)
+ :Item_literal(thd)
{
collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
decimals= 0;
cached_time= *ltime;
}
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg):
- Item_basic_constant(thd)
+ Item_literal(thd)
{
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;
-
- bool check_partition_func_processor(void *int_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); }
+ const MYSQL_TIME *const_ptr_mysql_time() const { return &cached_time; }
int save_in_field(Field *field, bool no_conversions)
{ return save_date_in_field(field, no_conversions); }
};
@@ -4390,7 +4614,6 @@ public:
:Item_temporal_literal(thd, 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.
@@ -4403,6 +4626,10 @@ public:
const Type_handler *type_handler() const { return &type_handler_newdate; }
void print(String *str, enum_query_type query_type);
Item *clone_item(THD *thd);
+ longlong val_int() { return Date(this).to_longlong(); }
+ double val_real() { return Date(this).to_double(); }
+ String *val_str(String *to) { return Date(this).to_string(to); }
+ my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_date_literal>(thd, this); }
@@ -4419,11 +4646,14 @@ public:
Item_temporal_literal(thd, ltime, dec_arg)
{
max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0);
- fixed= 1;
}
const Type_handler *type_handler() const { return &type_handler_time2; }
void print(String *str, enum_query_type query_type);
Item *clone_item(THD *thd);
+ longlong val_int() { return Time(this).to_longlong(); }
+ double val_real() { return Time(this).to_double(); }
+ String *val_str(String *to) { return Time(this).to_string(to, decimals); }
+ my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_time_literal>(thd, this); }
@@ -4440,13 +4670,22 @@ public:
Item_temporal_literal(thd, 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;
}
const Type_handler *type_handler() const { return &type_handler_datetime2; }
void print(String *str, enum_query_type query_type);
Item *clone_item(THD *thd);
+ longlong val_int() { return Datetime(this).to_longlong(); }
+ double val_real() { return Datetime(this).to_double(); }
+ String *val_str(String *to)
+ {
+ return Datetime(this).to_string(to, decimals);
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ return Datetime(this).to_decimal(to);
+ }
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_datetime_literal>(thd, this); }
@@ -4697,8 +4936,10 @@ struct st_sp_security_context;
class Item_sp
{
-public:
+protected:
+ // Can be NULL in some non-SELECT queries
Name_resolution_context *context;
+public:
sp_name *m_name;
sp_head *m_sp;
TABLE *dummy_table;
@@ -4720,9 +4961,15 @@ public:
bool execute_impl(THD *thd, Item **args, uint arg_count);
bool init_result_field(THD *thd, uint max_length, uint maybe_null,
bool *null_value, LEX_CSTRING *name);
+ void process_error(THD *thd)
+ {
+ if (context)
+ context->process_error(thd);
+ }
};
-class Item_ref :public Item_ident
+class Item_ref :public Item_ident,
+ protected With_sum_func_cache
{
protected:
void set_properties();
@@ -4758,7 +5005,8 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
- :Item_ident(thd, item), set_properties_only(0), ref(item->ref) {}
+ :Item_ident(thd, item), With_sum_func_cache(*item),
+ set_properties_only(0), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
enum Type real_type() const { return ref ? (*ref)->type() :
REF_ITEM; }
@@ -4796,6 +5044,8 @@ public:
Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd);
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param);
table_map used_tables() const;
void update_used_tables();
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
@@ -4925,6 +5175,8 @@ public:
}
bool excl_dep_on_grouping_fields(st_select_lex *sel)
{ return (*ref)->excl_dep_on_grouping_fields(sel); }
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+ { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); }
bool cleanup_excluding_fields_processor(void *arg)
{
Item *item= real_item();
@@ -4941,6 +5193,8 @@ public:
return 0;
return cleanup_processor(arg);
}
+ bool with_sum_func() const { return m_with_sum_func; }
+ With_sum_func_cache* get_with_sum_func_cache() { return this; }
};
@@ -5028,7 +5282,8 @@ class Expression_cache_tracker;
*/
class Item_cache_wrapper :public Item_result_field,
- public With_subquery_cache
+ public With_subquery_cache,
+ protected With_sum_func_cache
{
private:
/* Pointer on the cached expression */
@@ -5056,6 +5311,8 @@ public:
enum Type type() const { return EXPR_CACHE_ITEM; }
enum Type real_type() const { return orig_item->type(); }
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
+ bool with_sum_func() const { return m_with_sum_func; }
+ With_sum_func_cache* get_with_sum_func_cache() { return this; }
bool set_cache(THD *thd);
Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root);
@@ -5231,10 +5488,12 @@ public:
}
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
Item *derived_field_transformer_for_having(THD *thd, uchar *arg);
Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
- Item *derived_grouping_field_transformer_for_where(THD *thd,
- uchar *arg);
+ Item *grouping_field_transformer_for_where(THD *thd, uchar *arg);
+ Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg);
+ Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg);
void save_val(Field *to)
{
@@ -5500,12 +5759,12 @@ protected:
*/
Item_copy(THD *thd, Item *i): Item(thd)
{
+ DBUG_ASSERT(i->is_fixed());
item= i;
null_value=maybe_null=item->maybe_null;
Type_std_attributes::set(item);
name= item->name;
set_handler(item->type_handler());
- fixed= item->fixed;
}
public:
@@ -5533,6 +5792,12 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
void make_send_field(THD *thd, Send_field *field)
{ item->make_send_field(thd, field); }
table_map used_tables() const { return (table_map) 1L; }
@@ -5676,7 +5941,7 @@ public:
longlong val_int();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
- return get_date_from_decimal(ltime, fuzzydate);
+ return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this);
}
void copy();
Item *get_copy(THD *thd)
@@ -6015,7 +6280,7 @@ public:
for any value.
*/
-class Item_cache: public Item_basic_constant,
+class Item_cache: public Item,
public Type_handler_hybrid_field_type
{
protected:
@@ -6034,25 +6299,27 @@ protected:
cache_value() will set this flag to TRUE.
*/
bool value_cached;
+
+ table_map used_table_map;
public:
Item_cache(THD *thd):
- Item_basic_constant(thd),
+ Item(thd),
Type_handler_hybrid_field_type(&type_handler_string),
example(0), cached_field(0),
- value_cached(0)
+ value_cached(0),
+ used_table_map(0)
{
- fixed= 1;
maybe_null= 1;
null_value= 1;
}
protected:
Item_cache(THD *thd, const Type_handler *handler):
- Item_basic_constant(thd),
+ Item(thd),
Type_handler_hybrid_field_type(handler),
example(0), cached_field(0),
- value_cached(0)
+ value_cached(0),
+ used_table_map(0)
{
- fixed= 1;
maybe_null= 1;
null_value= 1;
}
@@ -6067,10 +6334,18 @@ public:
cached_field= ((Item_field *)item)->field;
return 0;
};
+
+ void set_used_tables(table_map map) { used_table_map= map; }
+ table_map used_tables() const { return used_table_map; }
enum Type type() const { return CACHE_ITEM; }
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ return create_tmp_field_ex_simple(table, src, param);
+ }
virtual void keep_array() {}
virtual void print(String *str, enum_query_type query_type);
@@ -6101,7 +6376,7 @@ public:
void cleanup()
{
clear();
- Item_basic_constant::cleanup();
+ Item::cleanup();
}
/**
Check if saved item has a non-NULL value.
@@ -6153,7 +6428,11 @@ public:
{ return convert_to_basic_const_item(thd); }
Item *derived_field_transformer_for_where(THD *thd, uchar *arg)
{ return convert_to_basic_const_item(thd); }
- Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg)
+ Item *grouping_field_transformer_for_where(THD *thd, uchar *arg)
+ { return convert_to_basic_const_item(thd); }
+ Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg)
+ { return convert_to_basic_const_item(thd); }
+ Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg)
{ return convert_to_basic_const_item(thd); }
};
@@ -6185,9 +6464,13 @@ public:
class Item_cache_year: public Item_cache_int
{
public:
- Item_cache_year(THD *thd): Item_cache_int(thd, &type_handler_year) { }
+ Item_cache_year(THD *thd, const Type_handler *handler)
+ :Item_cache_int(thd, handler) { }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_year(ltime, fuzzydate); }
+ {
+ return null_value=
+ VYear(this).to_mysql_time_with_warn(ltime, fuzzydate, NULL);
+ }
};
@@ -6196,12 +6479,6 @@ class Item_cache_temporal: public Item_cache_int
protected:
Item_cache_temporal(THD *thd, const Type_handler *handler);
public:
- String* val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
- longlong val_int();
- longlong val_datetime_packed();
- longlong val_time_packed();
- double val_real();
bool cache_value();
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
int save_in_field(Field *field, bool no_conversions);
@@ -6226,6 +6503,31 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_time>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed()
+ {
+ ulonglong fuzzy= Datetime::comparison_flags_for_get_date();
+ return has_value() ? Datetime(current_thd, this, fuzzy).to_longlong() : 0;
+ }
+ longlong val_time_packed()
+ {
+ return has_value() ? value : 0;
+ }
+ longlong val_int()
+ {
+ return has_value() ? Time(this).to_longlong() : 0;
+ }
+ double val_real()
+ {
+ return has_value() ? Time(this).to_double() : 0;
+ }
+ String *val_str(String *to)
+ {
+ return has_value() ? Time(this).to_string(to, decimals) : NULL;
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ return has_value() ? Time(this).to_decimal(to) : NULL;
+ }
};
@@ -6237,6 +6539,30 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_datetime>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed()
+ {
+ return has_value() ? value : 0;
+ }
+ longlong val_time_packed()
+ {
+ return Time(this, Time::comparison_flags_for_get_date()).to_packed();
+ }
+ longlong val_int()
+ {
+ return has_value() ? Datetime(this).to_longlong() : 0;
+ }
+ double val_real()
+ {
+ return has_value() ? Datetime(this).to_double() : 0;
+ }
+ String *val_str(String *to)
+ {
+ return has_value() ? Datetime(this).to_string(to, decimals) : NULL;
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ return has_value() ? Datetime(this).to_decimal(to) : NULL;
+ }
};
@@ -6248,6 +6574,24 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_date>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed()
+ {
+ return has_value() ? value : 0;
+ }
+ longlong val_time_packed()
+ {
+ return Time(this, Time::comparison_flags_for_get_date()).to_packed();
+ }
+ longlong val_int() { return has_value() ? Date(this).to_longlong() : 0; }
+ double val_real() { return has_value() ? Date(this).to_double() : 0; }
+ String *val_str(String *to)
+ {
+ return has_value() ? Date(this).to_string(to) : NULL;
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ return has_value() ? Date(this).to_decimal(to) : NULL;
+ }
};
@@ -6283,7 +6627,7 @@ public:
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_decimal(ltime, fuzzydate); }
+ { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)
@@ -6441,7 +6785,7 @@ public:
Type_handler_hybrid_field_type(item->real_type_handler()),
enum_set_typelib(0)
{
- DBUG_ASSERT(item->fixed);
+ DBUG_ASSERT(item->is_fixed());
maybe_null= item->maybe_null;
}
Item_type_holder(THD *thd,
@@ -6476,7 +6820,8 @@ public:
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
- Field *create_tmp_field(bool group, TABLE *table)
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
{
return Item_type_holder::real_type_handler()->
make_and_init_table_field(&name, Record_addr(maybe_null),
@@ -6616,4 +6961,39 @@ inline void Virtual_column_info::print(String* str)
expr->print_for_table_def(str);
}
+inline bool TABLE::mark_column_with_deps(Field *field)
+{
+ bool res;
+ if (!(res= bitmap_fast_test_and_set(read_set, field->field_index)))
+ {
+ if (field->vcol_info)
+ mark_virtual_column_deps(field);
+ }
+ return res;
+}
+
+inline bool TABLE::mark_virtual_column_with_deps(Field *field)
+{
+ bool res;
+ DBUG_ASSERT(field->vcol_info);
+ if (!(res= bitmap_fast_test_and_set(read_set, field->field_index)))
+ mark_virtual_column_deps(field);
+ return res;
+}
+
+inline void TABLE::mark_virtual_column_deps(Field *field)
+{
+ DBUG_ASSERT(field->vcol_info);
+ DBUG_ASSERT(field->vcol_info->expr);
+ field->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0);
+}
+
+inline void TABLE::use_all_stored_columns()
+{
+ bitmap_set_all(read_set);
+ if (Field **vf= vfield)
+ for (; *vf; vf++)
+ bitmap_clear_bit(read_set, (*vf)->field_index);
+}
+
#endif /* SQL_ITEM_INCLUDED */
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 4d03462d7c3..3467fda79c7 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -225,16 +225,15 @@ Cached_item_decimal::Cached_item_decimal(Item *it)
bool Cached_item_decimal::cmp()
{
- my_decimal tmp;
- my_decimal *ptmp= item->val_decimal(&tmp);
- if (null_value != item->null_value ||
- (!item->null_value && my_decimal_cmp(&value, ptmp)))
+ VDec tmp(item);
+ if (null_value != tmp.is_null() ||
+ (!tmp.is_null() && tmp.cmp(&value)))
{
- null_value= item->null_value;
+ null_value= tmp.is_null();
/* Save only not null values */
if (!null_value)
{
- my_decimal2decimal(ptmp, &value);
+ my_decimal2decimal(tmp.ptr(), &value);
return TRUE;
}
return FALSE;
@@ -245,17 +244,9 @@ bool Cached_item_decimal::cmp()
int Cached_item_decimal::cmp_read_only()
{
- my_decimal tmp;
- my_decimal *ptmp= item->val_decimal(&tmp);
+ VDec tmp(item);
if (null_value)
- {
- if (item->null_value)
- return 0;
- else
- return -1;
- }
- if (item->null_value)
- return 1;
- return my_decimal_cmp(&value, ptmp);
+ return tmp.is_null() ? 0 : -1;
+ return tmp.is_null() ? 1 : value.cmp(tmp.ptr());
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 4a7a44b3399..fb6d99b9498 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -34,29 +34,6 @@
#include "sql_time.h" // make_truncated_value_warning
#include "sql_base.h" // dynamic_column_error_message
-/**
- find an temporal type (item) that others will be converted to
- for the purpose of comparison.
-
- this is the type that will be used in warnings like
- "Incorrect <<TYPE>> value".
-*/
-static Item *find_date_time_item(Item **args, uint nargs, uint col)
-{
- Item *date_arg= 0, **arg, **arg_end;
- for (arg= args, arg_end= args + nargs; arg != arg_end ; arg++)
- {
- Item *item= arg[0]->element_index(col);
- if (item->cmp_type() != TIME_RESULT)
- continue;
- if (item->field_type() == MYSQL_TYPE_DATETIME)
- return item;
- if (!date_arg)
- date_arg= item;
- }
- return date_arg;
-}
-
/*
Compare row signature of two expressions
@@ -818,17 +795,15 @@ int Arg_comparator::compare_real()
int Arg_comparator::compare_decimal()
{
- my_decimal decimal1;
- my_decimal *val1= (*a)->val_decimal(&decimal1);
- if (!(*a)->null_value)
+ VDec val1(*a);
+ if (!val1.is_null())
{
- my_decimal decimal2;
- my_decimal *val2= (*b)->val_decimal(&decimal2);
- if (!(*b)->null_value)
+ VDec val2(*b);
+ if (!val2.is_null())
{
if (set_null)
owner->null_value= 0;
- return my_decimal_cmp(val1, val2);
+ return val1.cmp(val2);
}
}
if (set_null)
@@ -847,12 +822,10 @@ int Arg_comparator::compare_e_real()
int Arg_comparator::compare_e_decimal()
{
- my_decimal decimal1, decimal2;
- my_decimal *val1= (*a)->val_decimal(&decimal1);
- my_decimal *val2= (*b)->val_decimal(&decimal2);
- if ((*a)->null_value || (*b)->null_value)
- return MY_TEST((*a)->null_value && (*b)->null_value);
- return MY_TEST(my_decimal_cmp(val1, val2) == 0);
+ VDec val1(*a), val2(*b);
+ if (val1.is_null() || val2.is_null())
+ return MY_TEST(val1.is_null() && val2.is_null());
+ return MY_TEST(val1.cmp(val2) == 0);
}
@@ -1292,7 +1265,7 @@ bool Item_in_optimizer::fix_left(THD *thd)
used_tables_cache= args[0]->used_tables();
}
eval_not_null_tables(NULL);
- with_sum_func= args[0]->with_sum_func;
+ copy_with_sum_func(args[0]);
with_param= args[0]->with_param || args[1]->with_param;
with_field= args[0]->with_field;
if ((const_item_cache= args[0]->const_item()))
@@ -1300,11 +1273,11 @@ bool Item_in_optimizer::fix_left(THD *thd)
cache->store(args[0]);
cache->cache_value();
}
- if (args[1]->fixed)
+ if (args[1]->is_fixed())
{
/* to avoid overriding is called to update left expression */
used_tables_and_const_cache_join(args[1]);
- with_sum_func= with_sum_func || args[1]->with_sum_func;
+ join_with_sum_func(args[1]);
}
DBUG_RETURN(0);
}
@@ -1340,7 +1313,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
if (args[1]->maybe_null)
maybe_null=1;
m_with_subquery= true;
- with_sum_func= with_sum_func || args[1]->with_sum_func;
+ join_with_sum_func(args[1]);
with_field= with_field || args[1]->with_field;
with_param= args[0]->with_param || args[1]->with_param;
used_tables_and_const_cache_join(args[1]);
@@ -1895,7 +1868,7 @@ bool Item_func_interval::fix_length_and_dec()
max_length= 2;
used_tables_and_const_cache_join(row);
not_null_tables_cache= row->not_null_tables();
- with_sum_func= with_sum_func || row->with_sum_func;
+ join_with_sum_func(row);
with_param= with_param || row->with_param;
with_field= with_field || row->with_field;
return FALSE;
@@ -1974,11 +1947,11 @@ longlong Item_func_interval::val_int()
((el->result_type() == DECIMAL_RESULT) ||
(el->result_type() == INT_RESULT)))
{
- my_decimal e_dec_buf, *e_dec= el->val_decimal(&e_dec_buf);
+ VDec e_dec(el);
/* Skip NULL ranges. */
- if (el->null_value)
+ if (e_dec.is_null())
continue;
- if (my_decimal_cmp(e_dec, dec) > 0)
+ if (e_dec.cmp(dec) > 0)
return i - 1;
}
else
@@ -2124,23 +2097,25 @@ bool Item_func_between::fix_length_and_dec_temporal(THD *thd)
}
-longlong Item_func_between::val_int_cmp_temporal()
+longlong Item_func_between::val_int_cmp_datetime()
{
- enum_field_types f_type= m_comparator.type_handler()->field_type();
- longlong value= args[0]->val_temporal_packed(f_type), a, b;
+ longlong value= args[0]->val_datetime_packed(), a, b;
if ((null_value= args[0]->null_value))
return 0;
- a= args[1]->val_temporal_packed(f_type);
- b= args[2]->val_temporal_packed(f_type);
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((value >= a && value <= b) != negated);
- if (args[1]->null_value && args[2]->null_value)
- null_value= true;
- else if (args[1]->null_value)
- null_value= value <= b; // not null if false range.
- else
- null_value= value >= a;
- return (longlong) (!null_value && negated);
+ a= args[1]->val_datetime_packed();
+ b= args[2]->val_datetime_packed();
+ return val_int_cmp_int_finalize(value, a, b);
+}
+
+
+longlong Item_func_between::val_int_cmp_time()
+{
+ longlong value= args[0]->val_time_packed(), a, b;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ a= args[1]->val_time_packed();
+ b= args[2]->val_time_packed();
+ return val_int_cmp_int_finalize(value, a, b);
}
@@ -2179,39 +2154,41 @@ longlong Item_func_between::val_int_cmp_int()
return 0; /* purecov: inspected */
a= args[1]->val_int();
b= args[2]->val_int();
+ return val_int_cmp_int_finalize(value, a, b);
+}
+
+
+bool Item_func_between::val_int_cmp_int_finalize(longlong value,
+ longlong a,
+ longlong b)
+{
if (!args[1]->null_value && !args[2]->null_value)
return (longlong) ((value >= a && value <= b) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value= true;
else if (args[1]->null_value)
- {
null_value= value <= b; // not null if false range.
- }
else
- {
null_value= value >= a;
- }
return (longlong) (!null_value && negated);
}
longlong Item_func_between::val_int_cmp_decimal()
{
- my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
- a_buf, *a_dec, b_buf, *b_dec;
- if ((null_value=args[0]->null_value))
+ VDec dec(args[0]);
+ if ((null_value= dec.is_null()))
return 0; /* purecov: inspected */
- a_dec= args[1]->val_decimal(&a_buf);
- b_dec= args[2]->val_decimal(&b_buf);
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
- my_decimal_cmp(dec, b_dec) <= 0) != negated);
- if (args[1]->null_value && args[2]->null_value)
+ VDec a_dec(args[1]), b_dec(args[2]);
+ if (!a_dec.is_null() && !b_dec.is_null())
+ return (longlong) ((dec.cmp(a_dec) >= 0 &&
+ dec.cmp(b_dec) <= 0) != negated);
+ if (a_dec.is_null() && b_dec.is_null())
null_value= true;
- else if (args[1]->null_value)
- null_value= (my_decimal_cmp(dec, b_dec) <= 0);
+ else if (a_dec.is_null())
+ null_value= (dec.cmp(b_dec) <= 0);
else
- null_value= (my_decimal_cmp(dec, a_dec) >= 0);
+ null_value= (dec.cmp(a_dec) >= 0);
return (longlong) (!null_value && negated);
}
@@ -3664,9 +3641,18 @@ void in_time::set(uint pos,Item *item)
buff->unsigned_flag= 1L;
}
-uchar *in_temporal::get_value_internal(Item *item, enum_field_types f_type)
+uchar *in_datetime::get_value(Item *item)
{
- tmp.val= item->val_temporal_packed(f_type);
+ tmp.val= item->val_datetime_packed();
+ if (item->null_value)
+ return 0;
+ tmp.unsigned_flag= 1L;
+ return (uchar*) &tmp;
+}
+
+uchar *in_time::get_value(Item *item)
+{
+ tmp.val= item->val_time_packed();
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@@ -3878,39 +3864,15 @@ bool cmp_item_row::alloc_comparators(THD *thd, uint cols)
void cmp_item_row::store_value(Item *item)
{
DBUG_ENTER("cmp_item_row::store_value");
- THD *thd= current_thd;
- if (!alloc_comparators(thd, item->cols()))
+ DBUG_ASSERT(comparators);
+ DBUG_ASSERT(n == item->cols());
+ item->bring_value();
+ item->null_value= 0;
+ for (uint i=0; i < n; i++)
{
- item->bring_value();
- item->null_value= 0;
- for (uint i=0; i < n; i++)
- {
- if (!comparators[i])
- {
- /**
- Comparators for the row elements that have temporal data types
- are installed at initialization time by prepare_comparators().
- Here we install comparators for the other data types.
- There is a bug in the below code. See MDEV-11511.
- When performing:
- (predicant0,predicant1) IN ((value00,value01),(value10,value11))
- It uses only the data type and the collation of the predicant
- elements only. It should be fixed to aggregate the data type and
- the collation for all elements at the N-th positions of the
- predicate and all values:
- - predicate0, value00, value01
- - predicate1, value10, value11
- */
- Item *elem= item->element_index(i);
- const Type_handler *handler= elem->type_handler();
- DBUG_ASSERT(elem->cmp_type() != TIME_RESULT);
- if (!(comparators[i]=
- handler->make_cmp_item(thd, elem->collation.collation)))
- break; // new failed
- }
- comparators[i]->store_value(item->element_index(i));
- item->null_value|= item->element_index(i)->null_value;
- }
+ DBUG_ASSERT(comparators[i]);
+ comparators[i]->store_value(item->element_index(i));
+ item->null_value|= item->element_index(i)->null_value;
}
DBUG_VOID_RETURN;
}
@@ -4003,9 +3965,8 @@ int cmp_item_decimal::cmp_not_null(const Value *val)
int cmp_item_decimal::cmp(Item *arg)
{
- my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
- return (m_null_value || arg->null_value) ?
- UNKNOWN : (my_decimal_cmp(&value, tmp) != 0);
+ VDec tmp(arg);
+ return m_null_value || tmp.is_null() ? UNKNOWN : (tmp.cmp(&value) != 0);
}
@@ -4022,14 +3983,6 @@ cmp_item* cmp_item_decimal::make_same()
}
-void cmp_item_temporal::store_value_internal(Item *item,
- enum_field_types f_type)
-{
- value= item->val_temporal_packed(f_type);
- m_null_value= item->null_value;
-}
-
-
int cmp_item_datetime::cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
@@ -4290,25 +4243,84 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd)
}
-/**
- Historically this code installs comparators at initialization time
- for temporal ROW elements only. All other comparators are installed later,
- during the first store_value(). This causes the bug MDEV-11511.
- See also comments in cmp_item_row::store_value().
-*/
-bool cmp_item_row::prepare_comparators(THD *thd, Item **args, uint arg_count)
+bool cmp_item_row::
+ aggregate_row_elements_for_comparison(THD *thd,
+ Type_handler_hybrid_field_type *cmp,
+ Item_args *tmp,
+ const char *funcname,
+ uint col,
+ uint level)
{
+ DBUG_EXECUTE_IF("cmp_item",
+ {
+ for (uint i= 0 ; i < tmp->argument_count(); i++)
+ {
+ Item *arg= tmp->arguments()[i];
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "DBUG: %s[%d,%d] handler=%s",
+ String_space(level).c_ptr(), col, i,
+ arg->type_handler()->name().ptr());
+ }
+ }
+ );
+ bool err= cmp->aggregate_for_comparison(funcname, tmp->arguments(),
+ tmp->argument_count(), true);
+ DBUG_EXECUTE_IF("cmp_item",
+ {
+ if (!err)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "DBUG: %s=> handler=%s",
+ String_space(level).c_ptr(),
+ cmp->type_handler()->name().ptr());
+ }
+ );
+ return err;
+}
+
+
+bool cmp_item_row::prepare_comparators(THD *thd, const char *funcname,
+ const Item_args *args, uint level)
+{
+ DBUG_EXECUTE_IF("cmp_item",
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "DBUG: %sROW(%d args) level=%d",
+ String_space(level).c_ptr(),
+ args->argument_count(), level););
+ DBUG_ASSERT(args->argument_count() > 0);
+ if (alloc_comparators(thd, args->arguments()[0]->cols()))
+ return true;
+ DBUG_ASSERT(n == args->arguments()[0]->cols());
for (uint col= 0; col < n; col++)
{
- Item *date_arg= find_date_time_item(args, arg_count, col);
- if (date_arg)
+ Item_args tmp;
+ Type_handler_hybrid_field_type cmp;
+
+ if (tmp.alloc_and_extract_row_elements(thd, args, col) ||
+ aggregate_row_elements_for_comparison(thd, &cmp, &tmp,
+ funcname, col, level + 1))
+ return true;
+
+ /*
+ There is a legacy bug (MDEV-11511) in the code below,
+ which should be fixed eventually.
+ When performing:
+ (predicant0,predicant1) IN ((value00,value01),(value10,value11))
+ It uses only the data type and the collation of the predicant
+ elements only. It should be fixed to take into account the data type and
+ the collation for all elements at the N-th positions of the
+ predicate and all values:
+ - predicate0, value00, value01
+ - predicate1, value10, value11
+ */
+ Item *item0= args->arguments()[0]->element_index(col);
+ CHARSET_INFO *collation= item0->collation.collation;
+ if (!(comparators[col]= cmp.type_handler()->make_cmp_item(thd, collation)))
+ return true;
+ if (cmp.type_handler() == &type_handler_row)
{
- // TODO: do like the scalar comparators do
- const Type_handler *h= date_arg->type_handler();
- comparators[col]= h->field_type() == MYSQL_TYPE_TIME ?
- (cmp_item *) new (thd->mem_root) cmp_item_time() :
- (cmp_item *) new (thd->mem_root) cmp_item_datetime();
- if (!comparators[col])
+ // Prepare comparators for ROW elements recursively
+ cmp_item_row *row= static_cast<cmp_item_row*>(comparators[col]);
+ if (row->prepare_comparators(thd, funcname, &tmp, level + 1))
return true;
}
}
@@ -4318,19 +4330,10 @@ bool cmp_item_row::prepare_comparators(THD *thd, Item **args, uint arg_count)
bool Item_func_in::fix_for_row_comparison_using_bisection(THD *thd)
{
- uint cols= args[0]->cols();
if (unlikely(!(array= new (thd->mem_root) in_row(thd, arg_count-1, 0))))
return true;
cmp_item_row *cmp= &((in_row*)array)->tmp;
- if (cmp->alloc_comparators(thd, cols) ||
- cmp->prepare_comparators(thd, args, arg_count))
- return true;
- /*
- Only DATETIME items comparators were initialized.
- Call store_value() to setup others.
- */
- cmp->store_value(args[0]);
- if (unlikely(thd->is_fatal_error)) // OOM
+ if (cmp->prepare_comparators(thd, func_name(), this, 0))
return true;
fix_in_vector();
return false;
@@ -4369,8 +4372,7 @@ bool Item_func_in::fix_for_row_comparison_using_cmp_items(THD *thd)
DBUG_ASSERT(get_comparator_type_handler(0) == &type_handler_row);
DBUG_ASSERT(get_comparator_cmp_item(0));
cmp_item_row *cmp_row= (cmp_item_row*) get_comparator_cmp_item(0);
- return cmp_row->alloc_comparators(thd, args[0]->cols()) ||
- cmp_row->prepare_comparators(thd, args, arg_count);
+ return cmp_row->prepare_comparators(thd, func_name(), this, 0);
}
@@ -4641,7 +4643,7 @@ Item_cond::fix_fields(THD *thd, Item **ref)
const_item_cache= FALSE;
}
- with_sum_func|= item->with_sum_func;
+ join_with_sum_func(item);
with_param|= item->with_param;
with_field|= item->with_field;
m_with_subquery|= item->with_subquery();
@@ -6295,76 +6297,53 @@ void Item_equal::add_const(THD *thd, Item *c)
equal_items.push_front(c, thd->mem_root);
return;
}
- Item *const_item= get_const();
- switch (Item_equal::compare_type_handler()->cmp_type()) {
- case TIME_RESULT:
- {
- enum_field_types f_type= context_field->field_type();
- longlong value0= c->val_temporal_packed(f_type);
- longlong value1= const_item->val_temporal_packed(f_type);
- cond_false= c->null_value || const_item->null_value || value0 != value1;
- break;
- }
- case STRING_RESULT:
- {
- String *str1, *str2;
- /*
- Suppose we have an expression (with a string type field) like this:
- WHERE field=const1 AND field=const2 ...
-
- For all pairs field=constXXX we know that:
-
- - Item_func_eq::fix_length_and_dec() performed collation and character
- set aggregation and added character set converters when needed.
- Note, the case like:
- WHERE field=const1 COLLATE latin1_bin AND field=const2
- is not handled here, because the field would be replaced to
- Item_func_set_collation, which cannot get into Item_equal.
- So all constXXX that are handled by Item_equal
- already have compatible character sets with "field".
-
- - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees
- that the comparison collation of all equalities handled by Item_equal
- match the the collation of the field.
-
- Therefore, at Item_equal::add_const() time all constants constXXX
- should be directly comparable to each other without an additional
- character set conversion.
- It's safe to do val_str() for "const_item" and "c" and compare
- them according to the collation of the *field*.
-
- So in a script like this:
- CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx);
- INSERT INTO t1 VALUES ('a'),('A');
- SELECT * FROM t1 WHERE a='a' AND a='A';
- Item_equal::add_const() effectively rewrites the condition to:
- SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A';
- and then to:
- SELECT * FROM t1 WHERE a='a'; // if the two constants were equal
- // e.g. in case of latin1_swedish_ci
- or to:
- SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal
- // e.g. in case of latin1_bin
-
- Note, both "const_item" and "c" can return NULL, e.g.:
- SELECT * FROM t1 WHERE a=NULL AND a='const';
- SELECT * FROM t1 WHERE a='const' AND a=NULL;
- SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2)
- */
- cond_false= !(str1= const_item->val_str(&cmp_value1)) ||
- !(str2= c->val_str(&cmp_value2)) ||
- !str1->eq(str2, compare_collation());
- break;
- }
- default:
- {
- Item_func_eq *func= new (thd->mem_root) Item_func_eq(thd, c, const_item);
- if (func->set_cmp_func())
- return;
- func->quick_fix_field();
- cond_false= !func->val_int();
- }
- }
+
+ /*
+ Suppose we have an expression (with a string type field) like this:
+ WHERE field=const1 AND field=const2 ...
+
+ For all pairs field=constXXX we know that:
+
+ - Item_func_eq::fix_length_and_dec() performed collation and character
+ set aggregation and added character set converters when needed.
+ Note, the case like:
+ WHERE field=const1 COLLATE latin1_bin AND field=const2
+ is not handled here, because the field would be replaced to
+ Item_func_set_collation, which cannot get into Item_equal.
+ So all constXXX that are handled by Item_equal
+ already have compatible character sets with "field".
+
+ - Also, Field_str::test_if_equality_guarantees_uniqueness() guarantees
+ that the comparison collation of all equalities handled by Item_equal
+ match the the collation of the field.
+
+ Therefore, at Item_equal::add_const() time all constants constXXX
+ should be directly comparable to each other without an additional
+ character set conversion.
+ It's safe to do val_str() for "const_item" and "c" and compare
+ them according to the collation of the *field*.
+
+ So in a script like this:
+ CREATE TABLE t1 (a VARCHAR(10) COLLATE xxx);
+ INSERT INTO t1 VALUES ('a'),('A');
+ SELECT * FROM t1 WHERE a='a' AND a='A';
+ Item_equal::add_const() effectively rewrites the condition to:
+ SELECT * FROM t1 WHERE a='a' AND 'a' COLLATE xxx='A';
+ and then to:
+ SELECT * FROM t1 WHERE a='a'; // if the two constants were equal
+ // e.g. in case of latin1_swedish_ci
+ or to:
+ SELECT * FROM t1 WHERE FALSE; // if the two constants were not equal
+ // e.g. in case of latin1_bin
+
+ Note, both "const_item" and "c" can return NULL, e.g.:
+ SELECT * FROM t1 WHERE a=NULL AND a='const';
+ SELECT * FROM t1 WHERE a='const' AND a=NULL;
+ SELECT * FROM t1 WHERE a='const' AND a=(SELECT MAX(a) FROM t2)
+ */
+
+ cond_false= !Item_equal::compare_type_handler()->Item_eq_value(thd, this, c,
+ get_const());
if (with_const && equal_items.elements == 1)
cond_true= TRUE;
if (cond_false || cond_true)
@@ -6669,7 +6648,7 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
not_null_tables_cache|= tmp_table_map;
- DBUG_ASSERT(!item->with_sum_func && !item->with_subquery());
+ DBUG_ASSERT(!item->with_sum_func() && !item->with_subquery());
if (item->maybe_null)
maybe_null= 1;
if (!item->get_item_equal())
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index b34bf1dde19..db1075b1936 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -152,7 +152,8 @@ public:
class SEL_ARG;
struct KEY_PART;
-class Item_bool_func :public Item_int_func
+class Item_bool_func :public Item_int_func,
+ public Type_cmp_attributes
{
protected:
/*
@@ -215,9 +216,9 @@ public:
Item_bool_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {}
Item_bool_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { }
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
- const Type_handler *type_handler() const { return &type_handler_long; }
- bool is_bool_type() { return true; }
- virtual CHARSET_INFO *compare_collation() const { return NULL; }
+ const Type_handler *type_handler() const { return &type_handler_bool; }
+ const Type_handler *fixed_type_handler() const { return &type_handler_bool; }
+ CHARSET_INFO *compare_collation() const { return NULL; }
bool fix_length_and_dec() { decimals=0; max_length=1; return FALSE; }
uint decimal_precision() const { return 1; }
bool need_parentheses_in_default() { return true; }
@@ -891,6 +892,7 @@ class Item_func_between :public Item_func_opt_neg
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value);
+ bool val_int_cmp_int_finalize(longlong value, longlong a, longlong b);
public:
String value0,value1,value2;
Item_func_between(THD *thd, Item *a, Item *b, Item *c):
@@ -931,7 +933,8 @@ public:
{ return get_item_copy<Item_func_between>(thd, this); }
longlong val_int_cmp_string();
- longlong val_int_cmp_temporal();
+ longlong val_int_cmp_datetime();
+ longlong val_int_cmp_time();
longlong val_int_cmp_int();
longlong val_int_cmp_real();
longlong val_int_cmp_decimal();
@@ -954,7 +957,7 @@ public:
{
if (agg_arg_charsets_for_comparison(cmp_collation, args, 2))
return TRUE;
- fix_char_length(2);
+ fix_char_length(2); // returns "1" or "0" or "-1"
return FALSE;
}
Item *get_copy(THD *thd)
@@ -1282,7 +1285,11 @@ public:
{ reset_first_arg_if_needed(); return this; }
Item *derived_field_transformer_for_where(THD *thd, uchar *arg)
{ reset_first_arg_if_needed(); return this; }
- Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg)
+ Item *grouping_field_transformer_for_where(THD *thd, uchar *arg)
+ { reset_first_arg_if_needed(); return this; }
+ Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg)
+ { reset_first_arg_if_needed(); return this; }
+ Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg)
{ reset_first_arg_if_needed(); return this; }
};
@@ -1410,8 +1417,6 @@ public:
*/
class in_temporal :public in_longlong
{
-protected:
- uchar *get_value_internal(Item *item, enum_field_types f_type);
public:
/* Cache for the left item. */
@@ -1424,8 +1429,6 @@ public:
Item_datetime *dt= static_cast<Item_datetime*>(item);
dt->set(val->val, type_handler()->mysql_timestamp_type());
}
- uchar *get_value(Item *item)
- { return get_value_internal(item, type_handler()->field_type()); }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
@@ -1437,6 +1440,7 @@ public:
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
+ uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_datetime2; }
};
@@ -1448,6 +1452,7 @@ public:
:in_temporal(thd, elements)
{}
void set(uint pos,Item *item);
+ uchar *get_value(Item *item);
const Type_handler *type_handler() const { return &type_handler_time2; }
};
@@ -1622,7 +1627,6 @@ class cmp_item_temporal: public cmp_item_scalar
{
protected:
longlong value;
- void store_value_internal(Item *item, enum_field_types type);
public:
cmp_item_temporal() {}
int compare(cmp_item *ci);
@@ -1637,7 +1641,8 @@ public:
{ }
void store_value(Item *item)
{
- store_value_internal(item, MYSQL_TYPE_DATETIME);
+ value= item->val_datetime_packed();
+ m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
@@ -1653,7 +1658,8 @@ public:
{ }
void store_value(Item *item)
{
- store_value_internal(item, MYSQL_TYPE_TIME);
+ value= item->val_time_packed();
+ m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
@@ -2419,12 +2425,19 @@ class cmp_item_row :public cmp_item
{
cmp_item **comparators;
uint n;
+ bool alloc_comparators(THD *thd, uint n);
+ bool aggregate_row_elements_for_comparison(THD *thd,
+ Type_handler_hybrid_field_type *cmp,
+ Item_args *tmp,
+ const char *funcname,
+ uint col,
+ uint level);
public:
cmp_item_row(): comparators(0), n(0) {}
~cmp_item_row();
void store_value(Item *item);
- bool alloc_comparators(THD *thd, uint n);
- bool prepare_comparators(THD *, Item **args, uint arg_count);
+ bool prepare_comparators(THD *, const char *funcname,
+ const Item_args *args, uint level);
int cmp(Item *arg);
int cmp_not_null(const Value *val)
{
@@ -2505,9 +2518,8 @@ public:
{
Field *field=((Item_field*) args[0]->real_item())->field;
- if (((field->type() == MYSQL_TYPE_DATE) ||
- (field->type() == MYSQL_TYPE_DATETIME)) &&
- (field->flags & NOT_NULL_FLAG))
+ if ((field->flags & NOT_NULL_FLAG) &&
+ field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero())
return true;
}
return false;
@@ -3082,7 +3094,6 @@ class Item_equal: public Item_bool_func
const Type_handler *m_compare_handler;
CHARSET_INFO *m_compare_collation;
- String cmp_value1, cmp_value2;
public:
COND_EQUAL *upper_levels; /* multiple equalities of upper and levels */
@@ -3140,6 +3151,8 @@ public:
{
return used_tables() & tab_map;
}
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred);
+
friend class Item_equal_fields_iterator;
bool count_sargable_conds(void *arg);
friend class Item_equal_iterator<List_iterator_fast,Item>;
@@ -3291,11 +3304,8 @@ public:
inline bool is_cond_and(Item *item)
{
- if (item->type() != Item::COND_ITEM)
- return FALSE;
-
- Item_cond *cond_item= (Item_cond*) item;
- return (cond_item->functype() == Item_func::COND_AND_FUNC);
+ Item_func *func_item= item->get_item_func();
+ return func_item && func_item->functype() == Item_func::COND_AND_FUNC;
}
class Item_cond_or :public Item_cond
@@ -3396,11 +3406,8 @@ public:
inline bool is_cond_or(Item *item)
{
- if (item->type() != Item::COND_ITEM)
- return FALSE;
-
- Item_cond *cond_item= (Item_cond*) item;
- return (cond_item->functype() == Item_func::COND_OR_FUNC);
+ Item_func *func_item= item->get_item_func();
+ return func_item && func_item->functype() == Item_func::COND_OR_FUNC;
}
Item *and_expressions(Item *a, Item *b, Item **org_item);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index ab91e378be3..87bf69f3c96 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -3487,12 +3487,11 @@ Create_sp_func::create_with_db(THD *thd, LEX_CSTRING *db, LEX_CSTRING *name,
sph->add_used_routine(lex, thd, qname);
if (pkgname.m_name.length)
sp_handler_package_body.add_used_routine(lex, thd, &pkgname);
+ Name_resolution_context *ctx= lex->current_context();
if (arg_count > 0)
- func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
- qname, sph, *item_list);
+ func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph, *item_list);
else
- func= new (thd->mem_root) Item_func_sp(thd, lex->current_context(),
- qname, sph);
+ func= new (thd->mem_root) Item_func_sp(thd, ctx, qname, sph);
lex->safe_to_cache_query= 0;
return func;
@@ -3637,7 +3636,7 @@ Create_func_addtime Create_func_addtime::s_singleton;
Item*
Create_func_addtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
- return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, 0, 0);
+ return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, false);
}
@@ -6104,7 +6103,26 @@ Create_func_name_const Create_func_name_const::s_singleton;
Item*
Create_func_name_const::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
- return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+ if (!arg1->basic_const_item())
+ goto err;
+
+ if (arg2->basic_const_item())
+ return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+
+ if (arg2->type() == Item::FUNC_ITEM)
+ {
+ Item_func *value_func= (Item_func *) arg2;
+ if (value_func->functype() != Item_func::COLLATE_FUNC &&
+ value_func->functype() != Item_func::NEG_FUNC)
+ goto err;
+
+ if (!value_func->key_item()->basic_const_item())
+ goto err;
+ return new (thd->mem_root) Item_name_const(thd, arg1, arg2);
+ }
+err:
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST");
+ return NULL;
}
@@ -6658,7 +6676,7 @@ Create_func_subtime Create_func_subtime::s_singleton;
Item*
Create_func_subtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
- return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, 0, 1);
+ return new (thd->mem_root) Item_func_add_time(thd, arg1, arg2, true);
}
@@ -7433,84 +7451,6 @@ find_qualified_function_builder(THD *thd)
}
-static bool
-have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
-{
- return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0;
-}
-
-
-/**
- Builder for datetime literals:
- TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'.
- @param thd The current thread
- @param str Character literal
- @param length Length of str
- @param type Type of literal (TIME, DATE or DATETIME)
- @param send_error Whether to generate an error on failure
-*/
-
-Item *create_temporal_literal(THD *thd,
- const char *str, size_t length,
- CHARSET_INFO *cs,
- enum_field_types type,
- bool send_error)
-{
- MYSQL_TIME_STATUS status;
- MYSQL_TIME ltime;
- Item *item= NULL;
- sql_mode_t flags= sql_mode_for_dates(thd);
-
- switch(type)
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- if (!str_to_datetime(cs, str, length, &ltime, flags, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATE && !status.warnings)
- item= new (thd->mem_root) Item_date_literal(thd, &ltime);
- break;
- case MYSQL_TYPE_DATETIME:
- if (!str_to_datetime(cs, str, length, &ltime, flags, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_DATETIME &&
- !have_important_literal_warnings(&status))
- item= new (thd->mem_root) Item_datetime_literal(thd, &ltime,
- status.precision);
- break;
- case MYSQL_TYPE_TIME:
- if (!str_to_time(cs, str, length, &ltime, 0, &status) &&
- ltime.time_type == MYSQL_TIMESTAMP_TIME &&
- !have_important_literal_warnings(&status))
- item= new (thd->mem_root) Item_time_literal(thd, &ltime,
- status.precision);
- break;
- default:
- DBUG_ASSERT(0);
- }
-
- if (likely(item))
- {
- if (status.warnings) // e.g. a note on nanosecond truncation
- {
- ErrConvString err(str, length, cs);
- make_truncated_value_warning(thd,
- Sql_condition::time_warn_level(status.warnings),
- &err, ltime.time_type, 0);
- }
- return item;
- }
-
- if (send_error)
- {
- const char *typestr=
- (type == MYSQL_TYPE_DATE) ? "DATE" :
- (type == MYSQL_TYPE_TIME) ? "TIME" : "DATETIME";
- ErrConvString err(str, length, thd->variables.character_set_client);
- my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr());
- }
- return NULL;
-}
-
-
static List<Item> *create_func_dyncol_prepare(THD *thd,
DYNCALL_CREATE_DEF **dfs,
List<DYNCALL_CREATE_DEF> &list)
diff --git a/sql/item_create.h b/sql/item_create.h
index 5983a092cdc..4fb3c07c4ae 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -191,21 +191,6 @@ protected:
#endif
-Item *create_temporal_literal(THD *thd,
- const char *str, size_t length,
- CHARSET_INFO *cs,
- enum_field_types type,
- bool send_error);
-inline
-Item *create_temporal_literal(THD *thd, const String *str,
- enum_field_types type,
- bool send_error)
-{
- return create_temporal_literal(thd,
- str->ptr(), str->length(), str->charset(),
- type, send_error);
-}
-
struct Native_func_registry
{
LEX_CSTRING name;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 5693484ad3b..fa14bc58f2e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -145,7 +145,7 @@ void Item_func::sync_with_sum_func_and_with_field(List<Item> &list)
Item *item;
while ((item= li++))
{
- with_sum_func|= item->with_sum_func;
+ join_with_sum_func(item);
with_window_func|= item->with_window_func;
with_field|= item->with_field;
with_param|= item->with_param;
@@ -367,7 +367,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
if (item->maybe_null)
maybe_null=1;
- with_sum_func= with_sum_func || item->with_sum_func;
+ join_with_sum_func(item);
with_param= with_param || item->with_param;
with_window_func= with_window_func || item->with_window_func;
with_field= with_field || item->with_field;
@@ -391,7 +391,7 @@ Item_func::quick_fix_field()
{
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- if (!(*arg)->fixed)
+ if (!(*arg)->is_fixed())
(*arg)->quick_fix_field();
}
}
@@ -737,7 +737,7 @@ void Item_func::signal_divide_by_null()
Item *Item_func::get_tmp_table_item(THD *thd)
{
- if (!with_sum_func && !const_item())
+ if (!Item_func::with_sum_func() && !const_item())
return new (thd->mem_root) Item_temptable_field(thd, result_field);
return copy_or_same(thd);
}
@@ -809,50 +809,6 @@ bool Item_func_plus::fix_length_and_dec(void)
}
-String *Item_func_hybrid_field_type::val_str_from_decimal_op(String *str)
-{
- my_decimal decimal_value, *val;
- if (!(val= decimal_op_with_null_check(&decimal_value)))
- return 0; // null is set
- DBUG_ASSERT(!null_value);
- my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
- str->set_charset(collation.collation);
- my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
- return str;
-}
-
-double Item_func_hybrid_field_type::val_real_from_decimal_op()
-{
- my_decimal decimal_value, *val;
- if (!(val= decimal_op_with_null_check(&decimal_value)))
- return 0.0; // null is set
- double result;
- my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
- return result;
-}
-
-longlong Item_func_hybrid_field_type::val_int_from_decimal_op()
-{
- my_decimal decimal_value, *val;
- if (!(val= decimal_op_with_null_check(&decimal_value)))
- return 0; // null is set
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
- return result;
-}
-
-bool Item_func_hybrid_field_type::get_date_from_decimal_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
-{
- my_decimal value, *res;
- if (!(res= decimal_op_with_null_check(&value)) ||
- decimal_to_datetime_with_warn(res, ltime, fuzzydate,
- field_name_or_null()))
- return make_zero_mysql_time(ltime, fuzzydate);
- return (null_value= 0);
-}
-
-
String *Item_func_hybrid_field_type::val_str_from_int_op(String *str)
{
longlong nr= int_op();
@@ -884,8 +840,7 @@ bool Item_func_hybrid_field_type::get_date_from_int_op(MYSQL_TIME *ltime,
longlong value= int_op();
bool neg= !unsigned_flag && value < 0;
if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
- ltime, fuzzydate,
- field_name_or_null()))
+ ltime, fuzzydate, NULL))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
}
@@ -919,8 +874,7 @@ bool Item_func_hybrid_field_type::get_date_from_real_op(MYSQL_TIME *ltime,
ulonglong fuzzydate)
{
double value= real_op();
- if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
- field_name_or_null()))
+ if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate, NULL))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
}
@@ -1051,47 +1005,15 @@ void Item_func_unsigned::print(String *str, enum_query_type query_type)
}
-String *Item_decimal_typecast::val_str(String *str)
-{
- my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
- if (null_value)
- return NULL;
- my_decimal2string(E_DEC_FATAL_ERROR, tmp, 0, 0, 0, str);
- return str;
-}
-
-
-double Item_decimal_typecast::val_real()
-{
- my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
- double res;
- if (null_value)
- return 0.0;
- my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res);
- return res;
-}
-
-
-longlong Item_decimal_typecast::val_int()
-{
- my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
- longlong res;
- if (null_value)
- return 0;
- my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res);
- return res;
-}
-
-
my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
{
- my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
+ VDec tmp(args[0]);
bool sign;
uint precision;
- if ((null_value= args[0]->null_value))
+ if ((null_value= tmp.is_null()))
return NULL;
- my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
+ tmp.round_to(dec, decimals, HALF_UP);
sign= dec->sign();
if (unsigned_flag)
{
@@ -1275,17 +1197,13 @@ err:
my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
{
- my_decimal value1, *val1;
- my_decimal value2, *val2;
- val1= args[0]->val_decimal(&value1);
- if ((null_value= args[0]->null_value))
- return 0;
- val2= args[1]->val_decimal(&value2);
- if (!(null_value= (args[1]->null_value ||
+ VDec2_lazy val(args[0], args[1]);
+ if (!(null_value= (val.has_null() ||
check_decimal_overflow(my_decimal_add(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW,
decimal_value,
- val1, val2)) > 3)))
+ val.m_a.ptr(),
+ val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@@ -1415,18 +1333,13 @@ err:
my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
{
- my_decimal value1, *val1;
- my_decimal value2, *val2=
-
- val1= args[0]->val_decimal(&value1);
- if ((null_value= args[0]->null_value))
- return 0;
- val2= args[1]->val_decimal(&value2);
- if (!(null_value= (args[1]->null_value ||
- (check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
- ~E_DEC_OVERFLOW,
- decimal_value, val1,
- val2)) > 3))))
+ VDec2_lazy val(args[0], args[1]);
+ if (!(null_value= (val.has_null() ||
+ check_decimal_overflow(my_decimal_sub(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value,
+ val.m_a.ptr(),
+ val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@@ -1525,17 +1438,13 @@ err:
my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
{
- my_decimal value1, *val1;
- my_decimal value2, *val2;
- val1= args[0]->val_decimal(&value1);
- if ((null_value= args[0]->null_value))
- return 0;
- val2= args[1]->val_decimal(&value2);
- if (!(null_value= (args[1]->null_value ||
- (check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
- ~E_DEC_OVERFLOW,
- decimal_value, val1,
- val2)) > 3))))
+ VDec2_lazy val(args[0], args[1]);
+ if (!(null_value= (val.has_null() ||
+ check_decimal_overflow(my_decimal_mul(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW,
+ decimal_value,
+ val.m_a.ptr(),
+ val.m_b.ptr())) > 3)))
return decimal_value;
return 0;
}
@@ -1586,21 +1495,15 @@ double Item_func_div::real_op()
my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
- my_decimal value1, *val1;
- my_decimal value2, *val2;
int err;
-
- val1= args[0]->val_decimal(&value1);
- if ((null_value= args[0]->null_value))
- return 0;
- val2= args[1]->val_decimal(&value2);
- if ((null_value= args[1]->null_value))
+ VDec2_lazy val(args[0], args[1]);
+ if ((null_value= val.has_null()))
return 0;
if ((err= check_decimal_overflow(my_decimal_div(E_DEC_FATAL_ERROR &
~E_DEC_OVERFLOW &
~E_DEC_DIV_ZERO,
decimal_value,
- val1, val2,
+ val.m_a.ptr(), val.m_b.ptr(),
prec_increment))) > 3)
{
if (err == E_DEC_DIV_ZERO)
@@ -1690,20 +1593,14 @@ longlong Item_func_int_div::val_int()
if (args[0]->result_type() != INT_RESULT ||
args[1]->result_type() != INT_RESULT)
{
- my_decimal tmp;
- my_decimal *val0p= args[0]->val_decimal(&tmp);
- if ((null_value= args[0]->null_value))
+ VDec2_lazy val(args[0], args[1]);
+ if ((null_value= val.has_null()))
return 0;
- my_decimal val0= *val0p;
-
- my_decimal *val1p= args[1]->val_decimal(&tmp);
- if ((null_value= args[1]->null_value))
- return 0;
- my_decimal val1= *val1p;
int err;
+ my_decimal tmp;
if ((err= my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, &tmp,
- &val0, &val1, 0)) > 3)
+ val.m_a.ptr(), val.m_b.ptr(), 0)) > 3)
{
if (err == E_DEC_DIV_ZERO)
signal_divide_by_null();
@@ -1711,8 +1608,7 @@ longlong Item_func_int_div::val_int()
}
my_decimal truncated;
- const bool do_truncate= true;
- if (my_decimal_round(E_DEC_FATAL_ERROR, &tmp, 0, do_truncate, &truncated))
+ if (tmp.round_to(&truncated, 0, TRUNCATE))
DBUG_ASSERT(false);
longlong res;
@@ -1814,17 +1710,11 @@ double Item_func_mod::real_op()
my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value)
{
- my_decimal value1, *val1;
- my_decimal value2, *val2;
-
- val1= args[0]->val_decimal(&value1);
- if ((null_value= args[0]->null_value))
- return 0;
- val2= args[1]->val_decimal(&value2);
- if ((null_value= args[1]->null_value))
+ VDec2_lazy val(args[0], args[1]);
+ if ((null_value= val.has_null()))
return 0;
switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
- val1, val2)) {
+ val.m_a.ptr(), val.m_b.ptr())) {
case E_DEC_TRUNCATED:
case E_DEC_OK:
return decimal_value;
@@ -1894,10 +1784,10 @@ longlong Item_func_neg::int_op()
my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
{
- my_decimal val, *value= args[0]->val_decimal(&val);
- if (!(null_value= args[0]->null_value))
+ VDec value(args[0]);
+ if (!(null_value= value.is_null()))
{
- my_decimal2decimal(value, decimal_value);
+ my_decimal2decimal(value.ptr(), decimal_value);
my_decimal_neg(decimal_value);
return decimal_value;
}
@@ -1921,7 +1811,7 @@ void Item_func_neg::fix_length_and_dec_int()
longlong val= args[0]->val_int();
if ((ulonglong) val >= (ulonglong) LONGLONG_MIN &&
((ulonglong) val != (ulonglong) LONGLONG_MIN ||
- args[0]->type() != INT_ITEM))
+ !args[0]->is_of_type(CONST_ITEM, INT_RESULT)))
{
/*
Ensure that result is converted to DECIMAL, as longlong can't hold
@@ -1992,10 +1882,10 @@ longlong Item_func_abs::int_op()
my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
{
- my_decimal val, *value= args[0]->val_decimal(&val);
- if (!(null_value= args[0]->null_value))
+ VDec value(args[0]);
+ if (!(null_value= value.is_null()))
{
- my_decimal2decimal(value, decimal_value);
+ my_decimal2decimal(value.ptr(), decimal_value);
if (decimal_value->sign())
my_decimal_neg(decimal_value);
return decimal_value;
@@ -2317,25 +2207,15 @@ bool Item_func_int_val::fix_length_and_dec()
longlong Item_func_ceiling::int_op()
{
- longlong result;
switch (args[0]->result_type()) {
case INT_RESULT:
- result= args[0]->val_int();
- null_value= args[0]->null_value;
- break;
+ return val_int_from_item(args[0]);
case DECIMAL_RESULT:
- {
- my_decimal dec_buf, *dec;
- if ((dec= Item_func_ceiling::decimal_op(&dec_buf)))
- my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
- else
- result= 0;
+ return VDec_op(this).to_longlong(unsigned_flag);
+ default:
break;
}
- default:
- result= (longlong)Item_func_ceiling::real_op();
- };
- return result;
+ return (longlong) Item_func_ceiling::real_op();
}
@@ -2353,10 +2233,9 @@ double Item_func_ceiling::real_op()
my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
{
- my_decimal val, *value= args[0]->val_decimal(&val);
- if (!(null_value= (args[0]->null_value ||
- my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
- decimal_value) > 1)))
+ VDec value(args[0]);
+ if (!(null_value= (value.is_null() ||
+ value.round_to(decimal_value, 0, CEILING) > 1)))
return decimal_value;
return 0;
}
@@ -2364,25 +2243,19 @@ my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
longlong Item_func_floor::int_op()
{
- longlong result;
switch (args[0]->result_type()) {
case INT_RESULT:
- result= args[0]->val_int();
- null_value= args[0]->null_value;
- break;
+ return val_int_from_item(args[0]);
case DECIMAL_RESULT:
{
my_decimal dec_buf, *dec;
- if ((dec= Item_func_floor::decimal_op(&dec_buf)))
- my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
- else
- result= 0;
- break;
+ return (!(dec= Item_func_floor::decimal_op(&dec_buf))) ? 0 :
+ dec->to_longlong(unsigned_flag);
}
default:
- result= (longlong)Item_func_floor::real_op();
- };
- return result;
+ break;
+ }
+ return (longlong) Item_func_floor::real_op();
}
@@ -2400,10 +2273,9 @@ double Item_func_floor::real_op()
my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
{
- my_decimal val, *value= args[0]->val_decimal(&val);
- if (!(null_value= (args[0]->null_value ||
- my_decimal_floor(E_DEC_FATAL_ERROR, value,
- decimal_value) > 1)))
+ VDec value(args[0]);
+ if (!(null_value= (value.is_null() ||
+ value.round_to(decimal_value, 0, FLOOR) > 1)))
return decimal_value;
return 0;
}
@@ -2592,16 +2464,16 @@ longlong Item_func_round::int_op()
my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
{
- my_decimal val, *value= args[0]->val_decimal(&val);
+ VDec value(args[0]);
longlong dec= args[1]->val_int();
if (dec >= 0 || args[1]->unsigned_flag)
dec= MY_MIN((ulonglong) dec, decimals);
else if (dec < INT_MIN)
dec= INT_MIN;
- if (!(null_value= (args[0]->null_value || args[1]->null_value ||
- my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
- truncate, decimal_value) > 1)))
+ if (!(null_value= (value.is_null() || args[1]->null_value ||
+ value.round_to(decimal_value, (uint) dec,
+ truncate ? TRUNCATE : HALF_UP) > 1)))
return decimal_value;
return 0;
}
@@ -3021,14 +2893,14 @@ longlong Item_func_field::val_int()
}
else if (cmp_type == DECIMAL_RESULT)
{
- my_decimal dec_arg_buf, *dec_arg,
- dec_buf, *dec= args[0]->val_decimal(&dec_buf);
- if (args[0]->null_value)
+ VDec dec(args[0]);
+ if (dec.is_null())
return 0;
+ my_decimal dec_arg_buf;
for (uint i=1; i < arg_count; i++)
{
- dec_arg= args[i]->val_decimal(&dec_arg_buf);
- if (!args[i]->null_value && !my_decimal_cmp(dec_arg, dec))
+ my_decimal *dec_arg= args[i]->val_decimal(&dec_arg_buf);
+ if (!args[i]->null_value && !dec.cmp(dec_arg))
return (longlong) (i);
}
}
@@ -3281,6 +3153,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
}
uint i;
Item **arg,**arg_end;
+ With_sum_func_cache *with_sum_func_cache= func->get_with_sum_func_cache();
for (i=0, arg=arguments, arg_end=arguments+arg_count;
arg != arg_end ;
arg++,i++)
@@ -3304,7 +3177,8 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
func->collation.set(&my_charset_bin);
if (item->maybe_null)
func->maybe_null=1;
- func->with_sum_func= func->with_sum_func || item->with_sum_func;
+ if (with_sum_func_cache)
+ with_sum_func_cache->join_with_sum_func(item);
func->with_field= func->with_field || item->with_field;
func->with_param= func->with_param || item->with_param;
func->With_subquery_cache::join(item);
@@ -3608,32 +3482,6 @@ String *Item_func_udf_int::val_str(String *str)
}
-longlong Item_func_udf_decimal::val_int()
-{
- my_bool tmp_null_value;
- longlong result;
- my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
- null_value= tmp_null_value;
- if (null_value)
- return 0;
- my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
- return result;
-}
-
-
-double Item_func_udf_decimal::val_real()
-{
- my_bool tmp_null_value;
- double result;
- my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
- null_value= tmp_null_value;
- if (null_value)
- return 0.0;
- my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
- return result;
-}
-
-
my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
{
my_decimal *res;
@@ -3649,21 +3497,6 @@ my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
}
-String *Item_func_udf_decimal::val_str(String *str)
-{
- my_bool tmp_null_value;
- my_decimal dec_buf, *dec= udf.val_decimal(&tmp_null_value, &dec_buf);
- null_value= tmp_null_value;
- if (null_value)
- return 0;
- if (str->length() < DECIMAL_MAX_STR_LENGTH)
- str->length(DECIMAL_MAX_STR_LENGTH);
- my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
- my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
- return str;
-}
-
-
/* Default max_length is max argument length */
bool Item_func_udf_str::fix_length_and_dec()
@@ -3730,7 +3563,7 @@ longlong Item_master_pos_wait::val_int()
connection_name.length= con->length();
if (check_master_connection_name(&connection_name))
{
- my_error(ER_WRONG_ARGUMENTS, MYF(ME_JUST_WARNING),
+ my_error(ER_WRONG_ARGUMENTS, MYF(ME_WARNING),
"MASTER_CONNECTION_NAME");
goto err;
}
@@ -4441,7 +4274,7 @@ user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name,
if (!my_hash_inited(hash))
return 0;
if (!(entry = (user_var_entry*) my_malloc(size,
- MYF(MY_WME | ME_FATALERROR |
+ MYF(MY_WME | ME_FATAL |
MY_THREAD_SPECIFIC))))
return 0;
entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
@@ -4696,7 +4529,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, size_t length,
entry->value=0;
entry->value= (char*) my_realloc(entry->value, length,
MYF(MY_ALLOW_ZERO_PTR | MY_WME |
- ME_FATALERROR |
+ ME_FATAL |
MY_THREAD_SPECIFIC));
if (!entry->value)
return 1;
@@ -4761,11 +4594,7 @@ double user_var_entry::val_real(bool *null_value)
case INT_RESULT:
return (double) *(longlong*) value;
case DECIMAL_RESULT:
- {
- double result;
- my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result);
- return result;
- }
+ return ((my_decimal *)value)->to_double();
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
@@ -4790,11 +4619,7 @@ longlong user_var_entry::val_int(bool *null_value) const
case INT_RESULT:
return *(longlong*) value;
case DECIMAL_RESULT:
- {
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result);
- return result;
- }
+ return ((my_decimal *)value)->to_longlong(false);
case STRING_RESULT:
{
int error;
@@ -5531,10 +5356,9 @@ bool Item_func_get_user_var::set_value(THD *thd,
bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
{
- DBUG_ASSERT(fixed == 0);
+ DBUG_ASSERT(!is_fixed());
DBUG_ASSERT(thd->lex->exchange);
- if (Item::fix_fields(thd, ref) ||
- !(entry= get_variable(&thd->user_vars, &org_name, 1)))
+ if (!(entry= get_variable(&thd->user_vars, &org_name, 1)))
return TRUE;
entry->type= STRING_RESULT;
/*
@@ -5631,7 +5455,7 @@ void Item_func_get_system_var::update_null_value()
THD *thd= current_thd;
int save_no_errors= thd->no_errors;
thd->no_errors= TRUE;
- Item::update_null_value();
+ type_handler()->Item_update_null_value(this);
thd->no_errors= save_no_errors;
}
@@ -6471,7 +6295,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
(thd->lex->sql_command == SQLCOM_CREATE_VIEW))
{
Security_context *save_security_ctx= thd->security_ctx;
- if (context->security_ctx)
+ if (context && context->security_ctx)
thd->security_ctx= context->security_ctx;
/*
@@ -6486,7 +6310,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
if (res)
{
- context->process_error(thd);
+ process_error(thd);
DBUG_RETURN(res);
}
}
@@ -6503,7 +6327,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
if (!(m_sp= sp))
{
my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr());
- context->process_error(thd);
+ process_error(thd);
DBUG_RETURN(TRUE);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index af29e14fe3a..079775bb971 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -35,12 +35,11 @@ extern "C" /* Bug in BSDI include file */
#include <cmath>
-class Item_func :public Item_func_or_sum
+class Item_func :public Item_func_or_sum,
+ protected With_sum_func_cache
{
void sync_with_sum_func_and_with_field(List<Item> &list);
protected:
- String *val_str_from_val_str_ascii(String *str, String *str2);
-
virtual bool check_arguments() const
{
return check_argument_types_scalar(0, arg_count);
@@ -56,6 +55,7 @@ protected:
bool check_argument_types_can_return_text(uint start, uint end) const;
bool check_argument_types_can_return_date(uint start, uint end) const;
bool check_argument_types_can_return_time(uint start, uint end) const;
+ void print_cast_temporal(String *str, enum_query_type query_type);
public:
table_map not_null_tables_cache;
@@ -77,49 +77,56 @@ public:
EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC,
NEG_FUNC, GSYSVAR_FUNC, IN_OPTIMIZER_FUNC, DYNCOL_FUNC,
JSON_EXTRACT_FUNC };
+ static scalar_comparison_op functype_to_scalar_comparison_op(Functype type)
+ {
+ switch (type) {
+ case EQ_FUNC: return SCALAR_CMP_EQ;
+ case EQUAL_FUNC: return SCALAR_CMP_EQUAL;
+ case LT_FUNC: return SCALAR_CMP_LT;
+ case LE_FUNC: return SCALAR_CMP_LE;
+ case GE_FUNC: return SCALAR_CMP_GE;
+ case GT_FUNC: return SCALAR_CMP_GT;
+ default: break;
+ }
+ DBUG_ASSERT(0);
+ return SCALAR_CMP_EQ;
+ }
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
Item_func(THD *thd): Item_func_or_sum(thd)
{
- with_sum_func= 0;
with_field= 0;
with_param= 0;
}
- Item_func(THD *thd, Item *a): Item_func_or_sum(thd, a)
+ Item_func(THD *thd, Item *a)
+ :Item_func_or_sum(thd, a), With_sum_func_cache(a)
{
- with_sum_func= a->with_sum_func;
with_param= a->with_param;
with_field= a->with_field;
}
- Item_func(THD *thd, Item *a, Item *b):
- Item_func_or_sum(thd, a, b)
+ Item_func(THD *thd, Item *a, Item *b)
+ :Item_func_or_sum(thd, a, b), With_sum_func_cache(a, b)
{
- with_sum_func= a->with_sum_func || b->with_sum_func;
with_param= a->with_param || b->with_param;
with_field= a->with_field || b->with_field;
}
- Item_func(THD *thd, Item *a, Item *b, Item *c):
- Item_func_or_sum(thd, a, b, c)
+ Item_func(THD *thd, Item *a, Item *b, Item *c)
+ :Item_func_or_sum(thd, a, b, c), With_sum_func_cache(a, b, c)
{
- with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func;
with_field= a->with_field || b->with_field || c->with_field;
with_param= a->with_param || b->with_param || c->with_param;
}
- Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d):
- Item_func_or_sum(thd, a, b, c, d)
+ Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d)
+ :Item_func_or_sum(thd, a, b, c, d), With_sum_func_cache(a, b, c, d)
{
- with_sum_func= a->with_sum_func || b->with_sum_func ||
- c->with_sum_func || d->with_sum_func;
with_field= a->with_field || b->with_field ||
c->with_field || d->with_field;
with_param= a->with_param || b->with_param ||
c->with_param || d->with_param;
}
- Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e):
- Item_func_or_sum(thd, a, b, c, d, e)
+ Item_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e)
+ :Item_func_or_sum(thd, a, b, c, d, e), With_sum_func_cache(a, b, c, d, e)
{
- with_sum_func= a->with_sum_func || b->with_sum_func ||
- c->with_sum_func || d->with_sum_func || e->with_sum_func;
with_field= a->with_field || b->with_field ||
c->with_field || d->with_field || e->with_field;
with_param= a->with_param || b->with_param ||
@@ -131,11 +138,10 @@ public:
set_arguments(thd, list);
}
// Constructor used for Item_cond_and/or (see Item comment)
- Item_func(THD *thd, Item_func *item):
- Item_func_or_sum(thd, item),
+ Item_func(THD *thd, Item_func *item)
+ :Item_func_or_sum(thd, item), With_sum_func_cache(item),
not_null_tables_cache(item->not_null_tables_cache)
- {
- }
+ { }
bool fix_fields(THD *, Item **ref);
void cleanup()
{
@@ -181,6 +187,8 @@ public:
update_null_value();
return null_value;
}
+ String *val_str_from_val_str_ascii(String *str, String *str2);
+
void signal_divide_by_null();
friend class udf_handler;
Field *create_field_for_create_select(TABLE *table)
@@ -335,6 +343,11 @@ public:
return Item_args::excl_dep_on_grouping_fields(sel);
}
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+ {
+ return Item_args::excl_dep_on_in_subq_left_part(subq_pred);
+ }
+
/*
We assume the result of any function that has a TIMESTAMP argument to be
timezone-dependent, since a TIMESTAMP value in both numeric and string
@@ -377,6 +390,10 @@ public:
- or replaced to an Item_int_with_ref
*/
bool setup_args_and_comparator(THD *thd, Arg_comparator *cmp);
+
+ bool with_sum_func() const { return m_with_sum_func; }
+ With_sum_func_cache* get_with_sum_func_cache() { return this; }
+ Item_func *get_item_func() { return this; }
};
@@ -435,6 +452,193 @@ public:
};
+class Item_handled_func: public Item_func
+{
+public:
+ class Handler
+ {
+ public:
+ virtual ~Handler() { }
+ virtual String *val_str(Item_handled_func *, String *) const= 0;
+ virtual String *val_str_ascii(Item_handled_func *, String *) const= 0;
+ virtual double val_real(Item_handled_func *) const= 0;
+ virtual longlong val_int(Item_handled_func *) const= 0;
+ virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0;
+ virtual bool get_date(Item_handled_func *, MYSQL_TIME *, ulonglong fuzzydate) const= 0;
+ virtual const Type_handler *return_type_handler() const= 0;
+ virtual bool fix_length_and_dec(Item_handled_func *) const= 0;
+ };
+
+ /**
+ Abstract class for functions returning TIME, DATE, DATETIME or string values,
+ whose data type depends on parameters and is set at fix_fields time.
+ */
+ class Handler_temporal: public Handler
+ {
+ public:
+ String *val_str(Item_handled_func *item, String *to) const
+ {
+ StringBuffer<MAX_FIELD_WIDTH> ascii_buf;
+ return item->val_str_from_val_str_ascii(to, &ascii_buf);
+ }
+ };
+
+ /**
+ Abstract class for functions returning strings,
+ which are generated from get_date() results,
+ when get_date() can return different MYSQL_TIMESTAMP_XXX per row.
+ */
+ class Handler_temporal_string: public Handler_temporal
+ {
+ public:
+ const Type_handler *return_type_handler() const
+ {
+ return &type_handler_string;
+ }
+ double val_real(Item_handled_func *item) const
+ {
+ return Temporal_hybrid(item).to_double();
+ }
+ longlong val_int(Item_handled_func *item) const
+ {
+ return Temporal_hybrid(item).to_longlong();
+ }
+ my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
+ {
+ return Temporal_hybrid(item).to_decimal(to);
+ }
+ String *val_str_ascii(Item_handled_func *item, String *to) const
+ {
+ return Temporal_hybrid(item).to_string(to, item->decimals);
+ }
+ };
+
+
+ class Handler_date: public Handler_temporal
+ {
+ public:
+ const Type_handler *return_type_handler() const
+ {
+ return &type_handler_newdate;
+ }
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ item->fix_attributes_date();
+ return false;
+ }
+ double val_real(Item_handled_func *item) const
+ {
+ return Date(item).to_double();
+ }
+ longlong val_int(Item_handled_func *item) const
+ {
+ return Date(item).to_longlong();
+ }
+ my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
+ {
+ return Date(item).to_decimal(to);
+ }
+ String *val_str_ascii(Item_handled_func *item, String *to) const
+ {
+ return Date(item).to_string(to);
+ }
+ };
+
+
+ class Handler_time: public Handler_temporal
+ {
+ public:
+ const Type_handler *return_type_handler() const
+ {
+ return &type_handler_time2;
+ }
+ double val_real(Item_handled_func *item) const
+ {
+ return Time(item).to_double();
+ }
+ longlong val_int(Item_handled_func *item) const
+ {
+ return Time(item).to_longlong();
+ }
+ my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
+ {
+ return Time(item).to_decimal(to);
+ }
+ String *val_str_ascii(Item_handled_func *item, String *to) const
+ {
+ return Time(item).to_string(to, item->decimals);
+ }
+ };
+
+
+ class Handler_datetime: public Handler_temporal
+ {
+ public:
+ const Type_handler *return_type_handler() const
+ {
+ return &type_handler_datetime2;
+ }
+ double val_real(Item_handled_func *item) const
+ {
+ return Datetime(item).to_double();
+ }
+ longlong val_int(Item_handled_func *item) const
+ {
+ return Datetime(item).to_longlong();
+ }
+ my_decimal *val_decimal(Item_handled_func *item, my_decimal *to) const
+ {
+ return Datetime(item).to_decimal(to);
+ }
+ String *val_str_ascii(Item_handled_func *item, String *to) const
+ {
+ return Datetime(item).to_string(to, item->decimals);
+ }
+ };
+
+
+protected:
+ const Handler *m_func_handler;
+public:
+ Item_handled_func(THD *thd, Item *a)
+ :Item_func(thd, a), m_func_handler(NULL) { }
+ Item_handled_func(THD *thd, Item *a, Item *b)
+ :Item_func(thd, a, b), m_func_handler(NULL) { }
+ void set_func_handler(const Handler *handler)
+ {
+ m_func_handler= handler;
+ }
+ const Type_handler *type_handler() const
+ {
+ return m_func_handler->return_type_handler();
+ }
+ String *val_str(String *to)
+ {
+ return m_func_handler->val_str(this, to);
+ }
+ String *val_str_ascii(String *to)
+ {
+ return m_func_handler->val_str_ascii(this, to);
+ }
+ double val_real()
+ {
+ return m_func_handler->val_real(this);
+ }
+ longlong val_int()
+ {
+ return m_func_handler->val_int(this);
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ return m_func_handler->val_decimal(this, to);
+ }
+ bool get_date(MYSQL_TIME *to, ulonglong fuzzydate)
+ {
+ return m_func_handler->get_date(this, to, fuzzydate);
+ }
+};
+
+
/**
Functions that at fix_fields() time determine the returned field type,
trying to preserve the exact data type of the arguments.
@@ -476,12 +680,6 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
DBUG_ASSERT((res != NULL) ^ null_value);
return res;
}
- my_decimal *decimal_op_with_null_check(my_decimal *decimal_buffer)
- {
- my_decimal *res= decimal_op(decimal_buffer);
- DBUG_ASSERT((res != NULL) ^ null_value);
- return res;
- }
bool make_zero_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate)
{
bzero(ltime, sizeof(*ltime));
@@ -494,10 +692,6 @@ public:
{
return str_op_with_null_check(&str_value);
}
- my_decimal *val_decimal_from_decimal_op(my_decimal *dec)
- {
- return decimal_op_with_null_check(dec);
- }
longlong val_int_from_int_op()
{
return int_op();
@@ -508,7 +702,6 @@ public:
}
// Value methods that involve conversion
- String *val_str_from_decimal_op(String *str);
String *val_str_from_real_op(String *str);
String *val_str_from_int_op(String *str);
String *val_str_from_date_op(String *str);
@@ -522,19 +715,16 @@ public:
longlong val_int_from_str_op();
longlong val_int_from_real_op();
- longlong val_int_from_decimal_op();
longlong val_int_from_date_op();
longlong val_int_from_time_op();
double val_real_from_str_op();
- double val_real_from_decimal_op();
double val_real_from_date_op();
double val_real_from_time_op();
double val_real_from_int_op();
bool get_date_from_str_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_real_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_from_decimal_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool get_date_from_int_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
public:
@@ -976,12 +1166,12 @@ public:
fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec,
unsigned_flag));
}
- String *val_str(String *str);
- double val_real();
- longlong val_int();
+ String *val_str(String *str) { return VDec(this).to_string(str); }
+ double val_real() { return VDec(this).to_double(); }
+ longlong val_int() { return VDec(this).to_longlong(unsigned_flag); }
my_decimal *val_decimal(my_decimal*);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_decimal(ltime, fuzzydate); }
+ { return VDec(this).to_datetime_with_warn(ltime, fuzzydate, this); }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
void fix_length_and_dec_generic() {}
bool fix_length_and_dec()
@@ -2001,6 +2191,18 @@ protected:
udf_handler udf;
bool is_expensive_processor(void *arg) { return TRUE; }
+ class VDec_udf: public Dec_ptr_and_buffer
+ {
+ public:
+ VDec_udf(Item_udf_func *func, udf_handler *udf)
+ {
+ my_bool tmp_null_value;
+ m_ptr= udf->val_decimal(&tmp_null_value, &m_buffer);
+ DBUG_ASSERT(is_null() == (tmp_null_value != 0));
+ func->null_value= is_null();
+ }
+ };
+
public:
Item_udf_func(THD *thd, udf_func *udf_arg):
Item_func(thd), udf(udf_arg) {}
@@ -2140,10 +2342,19 @@ public:
Item_udf_func(thd, udf_arg) {}
Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_udf_func(thd, udf_arg, list) {}
- longlong val_int();
- double val_real();
+ longlong val_int()
+ {
+ return VDec_udf(this, &udf).to_longlong(unsigned_flag);
+ }
+ double val_real()
+ {
+ return VDec_udf(this, &udf).to_double();
+ }
my_decimal *val_decimal(my_decimal *);
- String *val_str(String *str);
+ String *val_str(String *str)
+ {
+ return VDec_udf(this, &udf).to_string_round(str, decimals);
+ }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; }
Item *get_copy(THD *thd)
@@ -2374,8 +2585,8 @@ public:
Item_func_user_var(THD *thd, Item_func_user_var *item)
:Item_hybrid_func(thd, item),
m_var_entry(item->m_var_entry), name(item->name) { }
- Field *create_tmp_field(bool group, TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param);
Field *create_field_for_create_select(TABLE *table)
{ return create_table_field_from_handler(table); }
bool check_vcol_func_processor(void *arg);
@@ -2508,14 +2719,14 @@ public:
in List<Item> and desire to place this code somewhere near other functions
working with user variables.
*/
-class Item_user_var_as_out_param :public Item,
+class Item_user_var_as_out_param :public Item_fixed_hybrid,
public Load_data_outvar
{
LEX_CSTRING org_name;
user_var_entry *entry;
public:
Item_user_var_as_out_param(THD *thd, const LEX_CSTRING *a)
- :Item(thd)
+ :Item_fixed_hybrid(thd)
{
DBUG_ASSERT(a->length < UINT_MAX32);
org_name= *a;
@@ -2550,8 +2761,14 @@ public:
{
return 0;
}
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
/* We should return something different from FIELD_ITEM here */
- enum Type type() const { return STRING_ITEM;}
+ enum Type type() const { return CONST_ITEM;}
double val_real();
longlong val_int();
String *val_str(String *str);
@@ -2863,6 +3080,8 @@ public:
const Type_handler *type_handler() const;
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param);
Field *create_field_for_create_select(TABLE *table)
{
return result_type() != STRING_RESULT ?
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 4c2a2fa8b11..1f1b5a6ceed 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -916,7 +916,7 @@ String *Item_func_point::val_str(String *str)
if ((null_value= (args[0]->null_value ||
args[1]->null_value ||
- str->realloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
+ str->alloc(4/*SRID*/ + 1 + 4 + SIZEOF_STORED_DOUBLE * 2))))
return 0;
str->set_charset(&my_charset_bin);
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 0e727829ce7..e6c198fb8b2 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -512,7 +512,7 @@ public:
return TRUE;
for (unsigned int i= 0; i < arg_count; ++i)
{
- if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY)
+ if (args[i]->is_fixed() && args[i]->field_type() != MYSQL_TYPE_GEOMETRY)
{
String str;
args[i]->print(&str, QT_NO_DATA_EXPANSION);
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index 2cda8b25a8a..205f2c5d65f 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -1422,7 +1422,7 @@ null_return:
static int append_json_value(String *str, Item *item, String *tmp_val)
{
- if (item->is_bool_type())
+ if (item->type_handler()->is_bool_type())
{
longlong v_int= item->val_int();
const char *t_f;
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 8233ba00f06..665c900cb3a 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -60,7 +60,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref)
}
}
maybe_null|= item->maybe_null;
- with_sum_func= with_sum_func || item->with_sum_func;
+ join_with_sum_func(item);
with_window_func = with_window_func || item->with_window_func;
with_field= with_field || item->with_field;
m_with_subquery|= item->with_subquery();
@@ -91,7 +91,7 @@ void Item_row::cleanup()
{
DBUG_ENTER("Item_row::cleanup");
- Item::cleanup();
+ Item_fixed_hybrid::cleanup();
/* Reset to the original values */
used_tables_and_const_cache_init();
with_null= 0;
diff --git a/sql/item_row.h b/sql/item_row.h
index e0d54403730..278dc88479d 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -33,10 +33,11 @@
Item which stores (x,y,...) and ROW(x,y,...).
Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs.
*/
-class Item_row: public Item,
+class Item_row: public Item_fixed_hybrid,
private Item_args,
private Used_tables_and_const_cache,
- private With_subquery_cache
+ private With_subquery_cache,
+ private With_sum_func_cache
{
table_map not_null_tables_cache;
/**
@@ -45,17 +46,25 @@ class Item_row: public Item,
*/
bool with_null;
public:
- Item_row(THD *thd, List<Item> &list):
- Item(thd), Item_args(thd, list), not_null_tables_cache(0), with_null(0)
+ Item_row(THD *thd, List<Item> &list)
+ :Item_fixed_hybrid(thd), Item_args(thd, list),
+ not_null_tables_cache(0), with_null(0)
{ }
- Item_row(THD *thd, Item_row *row):
- Item(thd), Item_args(thd, static_cast<Item_args*>(row)), Used_tables_and_const_cache(),
+ Item_row(THD *thd, Item_row *row)
+ :Item_fixed_hybrid(thd), Item_args(thd, static_cast<Item_args*>(row)),
+ Used_tables_and_const_cache(),
+ With_sum_func_cache(*row),
not_null_tables_cache(0), with_null(0)
{ }
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ return NULL; // Check with Vicentiu why it's called for Item_row
+ }
void illegal_method_call(const char *);
bool is_null() { return null_value; }
void make_send_field(THD *thd, Send_field *)
@@ -92,6 +101,8 @@ public:
void cleanup();
void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields, uint flags);
+ bool with_sum_func() const { return m_with_sum_func; }
+ With_sum_func_cache* get_with_sum_func_cache() { return this; }
table_map used_tables() const { return used_tables_cache; };
bool const_item() const { return const_item_cache; };
void update_used_tables()
@@ -134,6 +145,11 @@ public:
return Item_args::excl_dep_on_grouping_fields(sel);
}
+ bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+ {
+ return Item_args::excl_dep_on_in_subq_left_part(subq_pred);
+ }
+
bool check_vcol_func_processor(void *arg) {return FALSE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_row>(thd, this); }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 51723a25dee..50fe1624d48 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -255,7 +255,7 @@ String *Item_func_sha2::val_str_ascii(String *str)
Since we're subverting the usual String methods, we must make sure that
the destination has space for the bytes we're about to write.
*/
- str->realloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */
+ str->alloc((uint) digest_length*2 + 1); /* Each byte as two nybbles */
/* Convert the large number to a string-hex representation. */
array_to_hex((char *) str->ptr(), digest_buf, (uint)digest_length);
@@ -762,7 +762,7 @@ String *Item_func_des_encrypt::val_str(String *str)
tail= 8 - (res_length % 8); // 1..8 marking extra length
res_length+=tail;
- if (tmp_arg.realloc(res_length))
+ if (tmp_arg.alloc(res_length))
goto error;
tmp_arg.length(0);
tmp_arg.append(res->ptr(), res->length());
@@ -770,7 +770,6 @@ String *Item_func_des_encrypt::val_str(String *str)
if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1))
goto error;
tmp_arg[res_length-1]=tail; // save extra length
- str->realloc(res_length+1);
str->length(res_length+1);
str->set_charset(&my_charset_bin);
(*str)[0]=(char) (128 | key_number);
@@ -1017,7 +1016,7 @@ String *Item_func_concat_ws::val_str(String *str)
{
uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len);
- if (tmp_value.realloc(new_len))
+ if (tmp_value.alloc(new_len))
goto null;
}
}
@@ -1072,8 +1071,7 @@ String *Item_func_reverse::val_str(String *str)
/* An empty string is a special case as the string pointer may be null */
if (!res->length())
return make_empty_result();
- if (str->alloced_length() < res->length() &&
- str->realloc(res->length()))
+ if (str->alloc(res->length()))
{
null_value= 1;
return 0;
@@ -2659,12 +2657,10 @@ String *Item_func_format::val_str_ascii(String *str)
if (args[0]->result_type() == DECIMAL_RESULT ||
args[0]->result_type() == INT_RESULT)
{
- my_decimal dec_val, rnd_dec, *res;
- res= args[0]->val_decimal(&dec_val);
- if ((null_value=args[0]->null_value))
+ VDec res(args[0]);
+ if ((null_value= res.is_null()))
return 0; /* purecov: inspected */
- my_decimal_round(E_DEC_FATAL_ERROR, res, dec, false, &rnd_dec);
- my_decimal2string(E_DEC_FATAL_ERROR, &rnd_dec, 0, 0, 0, str);
+ res.to_string_round(str, dec);
str_length= str->length();
}
else
@@ -4180,7 +4176,7 @@ String *Item_func_compress::val_str(String *str)
// Check new_size overflow: new_size <= res->length()
if (((uint32) (new_size+5) <= res->length()) ||
- str->realloc((uint32) new_size + 4 + 1))
+ str->alloc((uint32) new_size + 4 + 1))
{
null_value= 1;
return 0;
@@ -4252,7 +4248,7 @@ String *Item_func_uncompress::val_str(String *str)
max_allowed_packet));
goto err;
}
- if (str->realloc((uint32)new_size))
+ if (str->alloc((uint32)new_size))
goto err;
if ((err= uncompress((Byte*)str->ptr(), &new_size,
@@ -4281,7 +4277,7 @@ String *Item_func_uuid::val_str(String *str)
DBUG_ASSERT(fixed == 1);
uchar guid[MY_UUID_SIZE];
- str->realloc(MY_UUID_STRING_LENGTH+1);
+ str->alloc(MY_UUID_STRING_LENGTH+1);
str->length(MY_UUID_STRING_LENGTH);
str->set_charset(system_charset_info);
my_uuid(guid);
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 29af0b43d9d..7c4ab93dc80 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -67,11 +67,6 @@ public:
const Type_handler *type_handler() const { return string_type_handler(); }
void left_right_max_length();
bool fix_fields(THD *thd, Item **ref);
- void update_null_value()
- {
- StringBuffer<MAX_FIELD_WIDTH> tmp;
- (void) val_str(&tmp);
- }
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 1947a45186a..eef6755bc98 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -85,6 +85,9 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("enter", ("select_lex: %p this: %p",
select_lex, this));
+
+ select_lex->parent_lex->relink_hack(select_lex);
+
unit= select_lex->master_unit();
if (unit->item)
@@ -123,13 +126,6 @@ void Item_subselect::init(st_select_lex *select_lex,
else
engine= new subselect_single_select_engine(select_lex, result, this);
}
- {
- SELECT_LEX *upper= unit->outer_select();
- if (upper->parsing_place == IN_HAVING)
- upper->subquery_in_having= 1;
- /* The subquery is an expression cache candidate */
- upper->expr_cache_may_be_used[upper->parsing_place]= TRUE;
- }
DBUG_PRINT("info", ("engine: %p", engine));
DBUG_VOID_RETURN;
}
@@ -220,7 +216,8 @@ Item_subselect::~Item_subselect()
if (own_engine)
delete engine;
else
- engine->cleanup();
+ if (engine) // can be empty in case of EOM
+ engine->cleanup();
engine= NULL;
DBUG_VOID_RETURN;
}
@@ -244,6 +241,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
DBUG_ASSERT(unit->thd == thd);
+ {
+ SELECT_LEX *upper= unit->outer_select();
+ if (upper->parsing_place == IN_HAVING)
+ upper->subquery_in_having= 1;
+ /* The subquery is an expression cache candidate */
+ upper->expr_cache_may_be_used[upper->parsing_place]= TRUE;
+ }
+
status_var_increment(thd_param->status_var.feature_subquery);
DBUG_ASSERT(fixed == 0);
@@ -939,7 +944,7 @@ bool Item_subselect::const_item() const
Item *Item_subselect::get_tmp_table_item(THD *thd_arg)
{
- if (!with_sum_func && !const_item())
+ if (!Item_subselect::with_sum_func() && !const_item())
return new (thd->mem_root) Item_temptable_field(thd_arg, result_field);
return copy_or_same(thd_arg);
}
@@ -1142,7 +1147,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (!select_lex->master_unit()->is_unit_op() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
- !select_lex->item_list.head()->with_sum_func &&
+ !select_lex->item_list.head()->with_sum_func() &&
/*
We cant change name of Item_field or Item_ref, because it will
prevent it's correct resolving, but we should save name of
@@ -1407,6 +1412,8 @@ Item_exists_subselect::Item_exists_subselect(THD *thd,
emb_on_expr_nest(NULL), optimizer(0), exists_transformed(0)
{
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
+
+
init(select_lex, new (thd->mem_root) select_exists_subselect(thd, this));
max_columns= UINT_MAX;
null_value= FALSE; //can't be NULL
@@ -1449,6 +1456,7 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
DBUG_PRINT("info", ("in_strategy: %u", (uint)in_strategy));
+
left_expr_orig= left_expr= left_exp;
/* prepare to possible disassembling the item in convert_subq_to_sj() */
if (left_exp->type() == Item::ROW_ITEM)
@@ -2039,7 +2047,7 @@ bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex)
{
bool fix_res= 0;
DBUG_ASSERT(thd);
- if (!having->fixed)
+ if (!having->is_fixed())
{
select_lex->having_fix_field= 1;
fix_res= having->fix_fields(thd, 0);
@@ -2376,9 +2384,9 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item *item_having_part2= 0;
for (uint i= 0; i < cols_num; i++)
{
- DBUG_ASSERT((left_expr->fixed &&
+ DBUG_ASSERT((left_expr->is_fixed() &&
- select_lex->ref_pointer_array[i]->fixed) ||
+ select_lex->ref_pointer_array[i]->is_fixed()) ||
(select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
Item_ref::OUTER_REF));
@@ -2447,8 +2455,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
for (uint i= 0; i < cols_num; i++)
{
Item *item, *item_isnull;
- DBUG_ASSERT((left_expr->fixed &&
- select_lex->ref_pointer_array[i]->fixed) ||
+ DBUG_ASSERT((left_expr->is_fixed() &&
+ select_lex->ref_pointer_array[i]->is_fixed()) ||
(select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
Item_ref::OUTER_REF));
@@ -5802,14 +5810,14 @@ Ordered_key::cmp_keys_by_row_data(ha_rows a, ha_rows b)
if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[0], rowid_a))))
{
/* purecov: begin inspected */
- tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error
+ tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error
return 0;
/* purecov: end */
}
if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[1], rowid_b))))
{
/* purecov: begin inspected */
- tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error
+ tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error
return 0;
/* purecov: end */
}
@@ -5891,7 +5899,7 @@ int Ordered_key::cmp_key_with_search_key(rownum_t row_num)
if (unlikely((error= tbl->file->ha_rnd_pos(tbl->record[0], cur_rowid))))
{
/* purecov: begin inspected */
- tbl->file->print_error(error, MYF(ME_FATALERROR)); // Sets fatal_error
+ tbl->file->print_error(error, MYF(ME_FATAL)); // Sets fatal_error
return 0;
/* purecov: end */
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 363dbba4ddd..4980709b979 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -33,6 +33,7 @@ class subselect_hash_sj_engine;
class Item_bool_func2;
class Comp_creator;
class With_element;
+class Field_pair;
typedef class st_select_lex SELECT_LEX;
@@ -46,7 +47,8 @@ class Cached_item;
/* base class for subselects */
class Item_subselect :public Item_result_field,
- protected Used_tables_and_const_cache
+ protected Used_tables_and_const_cache,
+ protected With_sum_func_cache
{
bool value_assigned; /* value already assigned to subselect */
bool own_engine; /* the engine was not taken from other Item_subselect */
@@ -183,6 +185,8 @@ public:
}
bool fix_fields(THD *thd, Item **ref);
bool with_subquery() const { DBUG_ASSERT(fixed); return true; }
+ bool with_sum_func() const { return m_with_sum_func; }
+ With_sum_func_cache* get_with_sum_func_cache() { return this; }
bool mark_as_dependent(THD *thd, st_select_lex *select, Item *item);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
void recalc_used_tables(st_select_lex *new_parent, bool after_pullout);
@@ -395,7 +399,7 @@ public:
}
void no_rows_in_result();
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_bool; }
longlong val_int();
double val_real();
String *val_str(String*);
@@ -570,6 +574,8 @@ public:
*/
bool is_registered_semijoin;
+ List<Field_pair> corresponding_fields;
+
/*
Used to determine how this subselect item is represented in the item tree,
in case there is a need to locate it there and replace with something else.
@@ -621,7 +627,6 @@ public:
double val_real();
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
- void update_null_value () { (void) val_bool(); }
bool val_bool();
bool test_limit(st_select_lex_unit *unit);
void print(String *str, enum_query_type query_type);
@@ -741,6 +746,8 @@ public:
return 0;
};
+ bool pushdown_cond_for_in_subquery(THD *thd, Item *cond);
+
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
friend class Item_in_optimizer;
@@ -852,7 +859,6 @@ protected:
bool set_row(List<Item> &item_list, Item_cache **row);
};
-
class subselect_single_select_engine: public subselect_engine
{
bool prepared; /* simple subselect is prepared */
@@ -886,9 +892,10 @@ public:
friend class subselect_hash_sj_engine;
friend class Item_in_subselect;
- friend bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
- Item **join_where);
-
+ friend bool execute_degenerate_jtbm_semi_join(THD *thd,
+ TABLE_LIST *tbl,
+ Item_in_subselect *subq_pred,
+ List<Item> &eq_list);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 3163fb9ea2e..98a3f6116a6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -404,7 +404,7 @@ bool Item_sum::register_sum_func(THD *thd, Item **ref)
for (sl= thd->lex->current_select;
sl && sl != aggr_sel && sl->master_unit()->item;
sl= sl->master_unit()->outer_select() )
- sl->master_unit()->item->with_sum_func= 1;
+ sl->master_unit()->item->get_with_sum_func_cache()->set_with_sum_func();
}
thd->lex->current_select->mark_as_dependent(thd, aggr_sel, NULL);
@@ -484,7 +484,6 @@ void Item_sum::mark_as_sum_func()
cur_select->n_sum_items++;
cur_select->with_sum_func= 1;
const_item_cache= false;
- with_sum_func= 1;
with_field= 0;
window_func_sum_expr_flag= false;
}
@@ -890,7 +889,7 @@ bool Aggregator_distinct::setup(THD *thd)
item_sum->null_value= item_sum->maybe_null= 1;
item_sum->quick_group= 0;
- DBUG_ASSERT(item_sum->get_arg(0)->fixed);
+ DBUG_ASSERT(item_sum->get_arg(0)->is_fixed());
arg= item_sum->get_arg(0);
if (arg->const_item())
@@ -1237,9 +1236,11 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*) args[0])->field;
- if ((field= create_tmp_field_from_field(table->in_use, field, &name,
- table, NULL)))
- field->flags&= ~NOT_NULL_FLAG;
+ if ((field= field->create_tmp_field(table->in_use->mem_root, table, true)))
+ {
+ DBUG_ASSERT((field->flags & NOT_NULL_FLAG) == 0);
+ field->field_name= name;
+ }
DBUG_RETURN(field);
}
DBUG_RETURN(tmp_table_field_from_field_type(table));
@@ -1287,7 +1288,7 @@ Item_sum_sp::fix_fields(THD *thd, Item **ref)
if (!m_sp)
{
my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr());
- context->process_error(thd);
+ process_error(thd);
return TRUE;
}
@@ -1639,12 +1640,7 @@ longlong Item_sum_sum::val_int()
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
- {
- longlong result;
- my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
- &result);
- return result;
- }
+ return dec_buffs[curr_dec_buff].to_longlong(unsigned_flag);
return val_int_from_real();
}
@@ -1655,7 +1651,7 @@ double Item_sum_sum::val_real()
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
- my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
+ sum= dec_buffs[curr_dec_buff].to_double();
return sum;
}
@@ -1665,7 +1661,7 @@ String *Item_sum_sum::val_str(String *str)
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
- return val_string_from_decimal(str);
+ return VDec(this).to_string_round(str, decimals);
return val_string_from_real(str);
}
@@ -2031,7 +2027,7 @@ String *Item_sum_avg::val_str(String *str)
if (aggr)
aggr->endup();
if (result_type() == DECIMAL_RESULT)
- return val_string_from_decimal(str);
+ return VDec(this).to_string_round(str, decimals);
return val_string_from_real(str);
}
@@ -2748,11 +2744,11 @@ void Item_sum_hybrid::reset_field()
}
case DECIMAL_RESULT:
{
- my_decimal value_buff, *arg_dec= arg0->val_decimal(&value_buff);
+ VDec arg_dec(arg0);
if (maybe_null)
{
- if (arg0->null_value)
+ if (arg_dec.is_null())
result_field->set_null();
else
result_field->set_notnull();
@@ -2761,9 +2757,7 @@ void Item_sum_hybrid::reset_field()
We must store zero in the field as we will use the field value in
add()
*/
- if (!arg_dec) // Null
- arg_dec= &decimal_zero;
- result_field->store_decimal(arg_dec);
+ result_field->store_decimal(arg_dec.ptr_or(&decimal_zero));
break;
}
case ROW_RESULT:
@@ -2786,15 +2780,10 @@ void Item_sum_sum::reset_field()
DBUG_ASSERT (aggr->Aggrtype() != Aggregator::DISTINCT_AGGREGATOR);
if (result_type() == DECIMAL_RESULT)
{
- my_decimal value, *arg_val;
if (unlikely(direct_added))
- arg_val= &direct_sum_decimal;
+ result_field->store_decimal(&direct_sum_decimal);
else
- {
- if (!(arg_val= args[0]->val_decimal(&value)))
- arg_val= &decimal_zero; // Null
- }
- result_field->store_decimal(arg_val);
+ result_field->store_decimal(VDec(args[0]).ptr_or(&decimal_zero));
}
else
{
@@ -2847,15 +2836,9 @@ void Item_sum_avg::reset_field()
if (result_type() == DECIMAL_RESULT)
{
longlong tmp;
- my_decimal value, *arg_dec= args[0]->val_decimal(&value);
- if (args[0]->null_value)
- {
- arg_dec= &decimal_zero;
- tmp= 0;
- }
- else
- tmp= 1;
- my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
+ VDec value(args[0]);
+ tmp= value.is_null() ? 0 : 1;
+ value.to_binary(res, f_precision, f_scale);
res+= dec_bin_size;
int8store(res, tmp);
}
@@ -2922,9 +2905,8 @@ void Item_sum_sum::update_field()
{
if (!result_field->is_null())
{
- my_decimal field_value;
- my_decimal *field_val= result_field->val_decimal(&field_value);
- my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
+ my_decimal field_value(result_field);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, &field_value);
result_field->store_decimal(dec_buffs);
}
else
@@ -2991,15 +2973,14 @@ void Item_sum_avg::update_field()
if (result_type() == DECIMAL_RESULT)
{
- my_decimal value, *arg_val= args[0]->val_decimal(&value);
- if (!args[0]->null_value)
+ VDec tmp(args[0]);
+ if (!tmp.is_null())
{
binary2my_decimal(E_DEC_FATAL_ERROR, res,
dec_buffs + 1, f_precision, f_scale);
field_count= sint8korr(res + dec_bin_size);
- my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
- my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
- res, f_precision, f_scale);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, tmp.ptr(), dec_buffs + 1);
+ dec_buffs->to_binary(res, f_precision, f_scale);
res+= dec_bin_size;
field_count++;
int8store(res, field_count);
@@ -3194,9 +3175,7 @@ my_decimal *Item_avg_field_decimal::val_decimal(my_decimal *dec_buf)
if ((null_value= !count))
return 0;
- my_decimal dec_count, dec_field;
- binary2my_decimal(E_DEC_FATAL_ERROR,
- field->ptr, &dec_field, f_precision, f_scale);
+ my_decimal dec_count, dec_field(field->ptr, f_precision, f_scale);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&dec_field, &dec_count, prec_increment);
@@ -3310,24 +3289,6 @@ my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec)
}
-String *Item_sum_udf_decimal::val_str(String *str)
-{
- return val_string_from_decimal(str);
-}
-
-
-double Item_sum_udf_decimal::val_real()
-{
- return val_real_from_decimal();
-}
-
-
-longlong Item_sum_udf_decimal::val_int()
-{
- return val_int_from_decimal();
-}
-
-
my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
{
my_decimal *res;
@@ -4008,6 +3969,7 @@ bool Item_func_group_concat::setup(THD *thd)
if (!ref_pointer_array)
DBUG_RETURN(TRUE);
memcpy(ref_pointer_array, args, arg_count * sizeof(Item*));
+ DBUG_ASSERT(context);
if (setup_order(thd, Ref_ptr_array(ref_pointer_array, n_elems),
context->table_list, list, all_fields, *order))
DBUG_RETURN(TRUE);
diff --git a/sql/item_sum.h b/sql/item_sum.h
index b400ebd5f80..fe055673328 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -511,7 +511,12 @@ public:
}
virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
- Field *create_tmp_field(bool group, TABLE *table);
+ virtual Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ return create_tmp_field(param->group(), table);
+ }
virtual bool collect_outer_ref_processor(void *param);
bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref);
@@ -578,6 +583,8 @@ public:
void mark_as_window_func_sum_expr() { window_func_sum_expr_flag= true; }
bool is_window_func_sum_expr() { return window_func_sum_expr_flag; }
virtual void setup_caches(THD *thd) {};
+
+ bool with_sum_func() const { return true; }
};
@@ -1384,9 +1391,13 @@ public:
decimals= item->decimals;
max_length= item->max_length;
unsigned_flag= item->unsigned_flag;
- fixed= true;
}
table_map used_tables() const { return (table_map) 1L; }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ return create_tmp_field_ex_simple(table, src, param);
+ }
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
bool check_vcol_func_processor(void *arg)
{
@@ -1439,9 +1450,18 @@ public:
dec_bin_size(item->dec_bin_size)
{ }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
- double val_real() { return val_real_from_decimal(); }
- longlong val_int() { return val_int_from_decimal(); }
- String *val_str(String *str) { return val_string_from_decimal(str); }
+ double val_real()
+ {
+ return VDec(this).to_double();
+ }
+ longlong val_int()
+ {
+ return VDec(this).to_longlong(unsigned_flag);
+ }
+ String *val_str(String *str)
+ {
+ return VDec(this).to_string_round(str, decimals);
+ }
my_decimal *val_decimal(my_decimal *);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_avg_field_decimal>(thd, this); }
@@ -1645,9 +1665,18 @@ public:
Item_udf_sum(thd, udf_arg, list) {}
Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item)
:Item_udf_sum(thd, item) {}
- String *val_str(String *);
- double val_real();
- longlong val_int();
+ String *val_str(String *str)
+ {
+ return VDec(this).to_string_round(str, decimals);
+ }
+ double val_real()
+ {
+ return VDec(this).to_double();
+ }
+ longlong val_int()
+ {
+ return VDec(this).to_longlong(unsigned_flag);
+ }
my_decimal *val_decimal(my_decimal *);
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; }
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index d29181a3446..84db154566a 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -58,6 +58,29 @@
/** Day number for Dec 31st, 9999. */
#define MAX_DAY_NUMBER 3652424L
+
+Func_handler_date_add_interval_datetime_arg0_time
+ func_handler_date_add_interval_datetime_arg0_time;
+
+Func_handler_date_add_interval_datetime func_handler_date_add_interval_datetime;
+Func_handler_date_add_interval_date func_handler_date_add_interval_date;
+Func_handler_date_add_interval_time func_handler_date_add_interval_time;
+Func_handler_date_add_interval_string func_handler_date_add_interval_string;
+
+Func_handler_add_time_datetime func_handler_add_time_datetime_add(1);
+Func_handler_add_time_datetime func_handler_add_time_datetime_sub(-1);
+Func_handler_add_time_time func_handler_add_time_time_add(1);
+Func_handler_add_time_time func_handler_add_time_time_sub(-1);
+Func_handler_add_time_string func_handler_add_time_string_add(1);
+Func_handler_add_time_string func_handler_add_time_string_sub(-1);
+
+Func_handler_str_to_date_datetime_sec func_handler_str_to_date_datetime_sec;
+Func_handler_str_to_date_datetime_usec func_handler_str_to_date_datetime_usec;
+Func_handler_str_to_date_date func_handler_str_to_date_date;
+Func_handler_str_to_date_time_sec func_handler_str_to_date_time_sec;
+Func_handler_str_to_date_time_usec func_handler_str_to_date_time_usec;
+
+
/*
Date formats corresponding to compound %r and %T conversion specifiers
@@ -427,10 +450,10 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
{
if (!my_isspace(&my_charset_latin1,*val))
{
+ ErrConvString err(val_begin, length, &my_charset_bin);
make_truncated_value_warning(current_thd,
Sql_condition::WARN_LEVEL_WARN,
- val_begin, length,
- cached_timestamp_type, NullS);
+ &err, cached_timestamp_type, NullS);
break;
}
} while (++val != val_end);
@@ -1311,25 +1334,19 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
bzero((char*) interval,sizeof(*interval));
if (int_type == INTERVAL_SECOND && args->decimals)
{
- my_decimal decimal_value, *val;
- ulonglong second;
- ulong second_part;
- if (!(val= args->val_decimal(&decimal_value)))
+ VDec val(args);
+ if (val.is_null())
return true;
- interval->neg= my_decimal2seconds(val, &second, &second_part);
- if (second == LONGLONG_MAX)
+ Sec6 d(val.ptr());
+ interval->neg= d.neg();
+ if (d.sec() >= LONGLONG_MAX)
{
- THD *thd= current_thd;
- ErrConvDecimal err(val);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "DECIMAL",
- err.ptr());
+ ErrConvDecimal err(val.ptr());
+ current_thd->push_warning_truncated_wrong_value("seconds", err.ptr());
return true;
}
-
- interval->second= second;
- interval->second_part= second_part;
+ interval->second= d.sec();
+ interval->second_part= d.usec();
return false;
}
else if ((int) int_type <= INTERVAL_MICROSECOND)
@@ -1475,85 +1492,6 @@ bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
}
-String *Item_temporal_func::val_str(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- return val_string_from_date(str);
-}
-
-
-bool Item_temporal_hybrid_func::fix_temporal_type(MYSQL_TIME *ltime)
-{
- if (ltime->time_type < 0) /* MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_ERROR */
- return false;
-
- if (ltime->time_type != MYSQL_TIMESTAMP_TIME)
- goto date_or_datetime_value;
-
- /* Convert TIME to DATE or DATETIME */
- switch (field_type())
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- {
- MYSQL_TIME tmp;
- if (time_to_datetime_with_warn(current_thd, ltime, &tmp, 0))
- return (null_value= true);
- *ltime= tmp;
- if (field_type() == MYSQL_TYPE_DATE)
- datetime_to_date(ltime);
- return false;
- }
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
- return false;
- default:
- DBUG_ASSERT(0);
- return (null_value= true);
- }
-
-date_or_datetime_value:
- /* Convert DATE or DATETIME to TIME, DATE, or DATETIME */
- switch (field_type())
- {
- case MYSQL_TYPE_TIME:
- datetime_to_time(ltime);
- return false;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_TIMESTAMP:
- date_to_datetime(ltime);
- return false;
- case MYSQL_TYPE_DATE:
- datetime_to_date(ltime);
- return false;
- case MYSQL_TYPE_STRING: /* DATE_ADD, ADDTIME can return VARCHAR */
- return false;
- default:
- DBUG_ASSERT(0);
- return (null_value= true);
- }
- return false;
-}
-
-
-String *Item_temporal_hybrid_func::val_str_ascii(String *str)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (get_date(&ltime, 0) || fix_temporal_type(&ltime) ||
- (null_value= my_TIME_to_str(&ltime, str, decimals)))
- return (String *) 0;
-
- /* Check that the returned timestamp type matches to the function type */
- DBUG_ASSERT(field_type() == MYSQL_TYPE_STRING ||
- ltime.time_type == MYSQL_TIMESTAMP_NONE ||
- ltime.time_type == mysql_timestamp_type());
- return str;
-}
-
-
bool Item_func_from_days::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
longlong value=args[0]->val_int();
@@ -1699,7 +1637,7 @@ bool Item_func_now::fix_fields(THD *thd, Item **items)
func_name(), TIME_SECOND_PART_DIGITS);
return 1;
}
- return Item_temporal_func::fix_fields(thd, items);
+ return Item_datetimefunc::fix_fields(thd, items);
}
void Item_func_now::print(String *str, enum_query_type query_type)
@@ -1726,7 +1664,7 @@ int Item_func_now_local::save_in_field(Field *field, bool no_conversions)
return 0;
}
else
- return Item_temporal_func::save_in_field(field, no_conversions);
+ return Item_datetimefunc::save_in_field(field, no_conversions);
}
@@ -1796,52 +1734,12 @@ bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- bool sign;
- ulonglong sec;
- ulong sec_part;
-
- bzero((char *)ltime, sizeof(*ltime));
- ltime->time_type= MYSQL_TIMESTAMP_TIME;
-
- sign= args[0]->get_seconds(&sec, &sec_part);
-
- if ((null_value= args[0]->null_value))
- return 1;
-
- ltime->neg= sign;
- if (sec > TIME_MAX_VALUE_SECONDS)
- goto overflow;
-
- DBUG_ASSERT(sec_part <= TIME_MAX_SECOND_PART);
-
- ltime->hour= (uint) (sec/3600);
- ltime->minute= (uint) (sec % 3600) /60;
- ltime->second= (uint) sec % 60;
- ltime->second_part= sec_part;
-
- return 0;
-
-overflow:
- /* use check_time_range() to set ltime to the max value depending on dec */
- int unused;
- char buf[100];
- String tmp(buf, sizeof(buf), &my_charset_bin), *err= args[0]->val_str(&tmp);
-
- ltime->hour= TIME_MAX_HOUR+1;
- check_time_range(ltime, decimals, &unused);
- if (!err)
- {
- ErrConvInteger err2(sec, unsigned_flag);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &err2, MYSQL_TIMESTAMP_TIME, NullS);
- }
- else
- {
- ErrConvString err2(err);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &err2, MYSQL_TIMESTAMP_TIME, NullS);
- }
- return 0;
+ VSec6 sec(args[0], "seconds", LONGLONG_MAX);
+ if ((null_value= sec.is_null()))
+ return true;
+ if (sec.sec_to_time(ltime, decimals) && !sec.truncated())
+ sec.make_truncated_warning(current_thd, "seconds");
+ return false;
}
bool Item_func_date_format::fix_length_and_dec()
@@ -2051,21 +1949,17 @@ bool Item_func_from_unixtime::fix_length_and_dec()
bool Item_func_from_unixtime::get_date(MYSQL_TIME *ltime,
ulonglong fuzzy_date __attribute__((unused)))
{
- bool sign;
- ulonglong sec;
- ulong sec_part;
-
bzero((char *)ltime, sizeof(*ltime));
ltime->time_type= MYSQL_TIMESTAMP_TIME;
- sign= args[0]->get_seconds(&sec, &sec_part);
+ VSec6 sec(args[0], "unixtime", TIMESTAMP_MAX_VALUE);
+ DBUG_ASSERT(sec.sec() <= TIMESTAMP_MAX_VALUE);
- if (args[0]->null_value || sign || sec > TIMESTAMP_MAX_VALUE)
+ if (sec.is_null() || sec.truncated() || sec.neg())
return (null_value= 1);
- tz->gmt_sec_to_TIME(ltime, (my_time_t)sec);
-
- ltime->second_part= sec_part;
+ tz->gmt_sec_to_TIME(ltime, (my_time_t) sec.sec());
+ ltime->second_part= sec.usec();
return (null_value= 0);
}
@@ -2112,7 +2006,7 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
void Item_func_convert_tz::cleanup()
{
from_tz_cached= to_tz_cached= 0;
- Item_temporal_func::cleanup();
+ Item_datetimefunc::cleanup();
}
@@ -2143,81 +2037,44 @@ bool Item_date_add_interval::fix_length_and_dec()
MYSQL_TIME or DATETIME argument)
*/
arg0_field_type= args[0]->field_type();
- uint interval_dec= 0;
- if (int_type == INTERVAL_MICROSECOND ||
- (int_type >= INTERVAL_DAY_MICROSECOND &&
- int_type <= INTERVAL_SECOND_MICROSECOND))
- interval_dec= TIME_SECOND_PART_DIGITS;
- else if (int_type == INTERVAL_SECOND && args[1]->decimals > 0)
- interval_dec= MY_MIN(args[1]->decimals, TIME_SECOND_PART_DIGITS);
if (arg0_field_type == MYSQL_TYPE_DATETIME ||
arg0_field_type == MYSQL_TYPE_TIMESTAMP)
{
- uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec);
- set_handler(&type_handler_datetime);
- fix_attributes_datetime(dec);
+ set_func_handler(&func_handler_date_add_interval_datetime);
}
else if (arg0_field_type == MYSQL_TYPE_DATE)
{
if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
- {
- set_handler(&type_handler_newdate);
- fix_attributes_date();
- }
+ set_func_handler(&func_handler_date_add_interval_date);
else
- {
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(interval_dec);
- }
+ set_func_handler(&func_handler_date_add_interval_datetime);
}
else if (arg0_field_type == MYSQL_TYPE_TIME)
{
- uint dec= MY_MAX(args[0]->time_precision(), interval_dec);
if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH)
- {
- set_handler(&type_handler_time2);
- fix_attributes_time(dec);
- }
+ set_func_handler(&func_handler_date_add_interval_time);
else
- {
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(dec);
- }
+ set_func_handler(&func_handler_date_add_interval_datetime_arg0_time);
}
else
{
- uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec);
- set_handler(&type_handler_string);
- collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
- fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ set_func_handler(&func_handler_date_add_interval_string);
}
maybe_null= true;
- return FALSE;
+ return m_func_handler->fix_length_and_dec(this);
}
-bool Item_date_add_interval::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Func_handler_date_add_interval_datetime_arg0_time::
+ get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
{
- INTERVAL interval;
-
- if (args[0]->get_date(ltime,
- field_type() == MYSQL_TYPE_TIME ?
- TIME_TIME_ONLY : 0) ||
- get_interval_value(args[1], int_type, &interval))
- return (null_value=1);
-
- if (ltime->time_type != MYSQL_TIMESTAMP_TIME &&
- check_date_with_warn(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
- MYSQL_TIMESTAMP_ERROR))
- return (null_value=1);
-
- if (date_sub_interval)
- interval.neg = !interval.neg;
-
- if (date_add_interval(ltime, int_type, interval))
- return (null_value=1);
- return (null_value= 0);
+ THD *thd= current_thd;
+ // time_expr + INTERVAL {YEAR|QUARTER|MONTH|WEEK|YEAR_MONTH}
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_DATETIME_FUNCTION_OVERFLOW,
+ ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW), "time");
+ return (item->null_value= true);
}
@@ -2395,13 +2252,14 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
return 1;
}
-void Item_temporal_typecast::print(String *str, enum_query_type query_type)
+void Item_func::print_cast_temporal(String *str, enum_query_type query_type)
{
char buf[32];
str->append(STRING_WITH_LEN("cast("));
args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as "));
- str->append(cast_type());
+ const Name name= type_handler()->name();
+ str->append(name.ptr(), name.length());
if (decimals && decimals != NOT_FIXED_DEC)
{
str->append('(');
@@ -2670,17 +2528,14 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
DBUG_ASSERT(fixed == 1);
- long daynr= (long) args[1]->val_int();
- long year= (long) args[0]->val_int();
- long days;
+ long year, days, daynr= (long) args[1]->val_int();
- if (args[0]->null_value || args[1]->null_value ||
- year < 0 || year > 9999 || daynr <= 0)
+ VYear vyear(args[0]);
+ if (vyear.is_null() || args[1]->null_value || vyear.truncated() || daynr <= 0)
goto err;
- if (year < 100)
+ if ((year= (long) vyear.year()) < 100)
year= year_2000_handling(year);
-
days= calc_daynr(year,1,1) + daynr - 1;
if (get_date_from_daynr(days, &ltime->year, &ltime->month, &ltime->day))
goto err;
@@ -2719,101 +2574,24 @@ bool Item_func_add_time::fix_length_and_dec()
arg0_field_type= args[0]->field_type();
if (arg0_field_type == MYSQL_TYPE_DATE ||
arg0_field_type == MYSQL_TYPE_DATETIME ||
- arg0_field_type == MYSQL_TYPE_TIMESTAMP ||
- is_date)
+ arg0_field_type == MYSQL_TYPE_TIMESTAMP)
{
- uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision());
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(dec);
+ set_func_handler(sign > 0 ? &func_handler_add_time_datetime_add :
+ &func_handler_add_time_datetime_sub);
}
else if (arg0_field_type == MYSQL_TYPE_TIME)
{
- uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision());
- set_handler(&type_handler_time2);
- fix_attributes_time(dec);
+ set_func_handler(sign > 0 ? &func_handler_add_time_time_add :
+ &func_handler_add_time_time_sub);
}
else
{
- uint dec= MY_MAX(args[0]->decimals, args[1]->decimals);
- set_handler(&type_handler_string);
- collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
- fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ set_func_handler(sign > 0 ? &func_handler_add_time_string_add :
+ &func_handler_add_time_string_sub);
}
- maybe_null= true;
- return FALSE;
-}
-
-/**
- ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a
- time/datetime value
-
- t: time_or_datetime_expression
- a: time_expression
-
- Result: Time value or datetime value
-*/
-bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
-{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME l_time1, l_time2;
- bool is_time= 0;
- long days, microseconds;
- longlong seconds;
- int l_sign= sign;
-
- if (Item_func_add_time::field_type() == MYSQL_TYPE_DATETIME)
- {
- // TIMESTAMP function OR the first argument is DATE/DATETIME/TIMESTAMP
- if (get_arg0_date(&l_time1, 0) ||
- args[1]->get_time(&l_time2) ||
- l_time1.time_type == MYSQL_TIMESTAMP_TIME ||
- l_time2.time_type != MYSQL_TIMESTAMP_TIME)
- return (null_value= 1);
- }
- else
- {
- // ADDTIME function AND the first argument is TIME
- if (args[0]->get_time(&l_time1) ||
- args[1]->get_time(&l_time2) ||
- l_time2.time_type != MYSQL_TIMESTAMP_TIME)
- return (null_value= 1);
- is_time= (l_time1.time_type == MYSQL_TIMESTAMP_TIME);
- }
- if (l_time1.neg != l_time2.neg)
- l_sign= -l_sign;
-
- bzero(ltime, sizeof(*ltime));
-
- ltime->neg= calc_time_diff(&l_time1, &l_time2, -l_sign,
- &seconds, &microseconds);
-
- /*
- If first argument was negative and diff between arguments
- is non-zero we need to swap sign to get proper result.
- */
- if (l_time1.neg && (seconds || microseconds))
- ltime->neg= 1-ltime->neg; // Swap sign of result
-
- if (!is_time && ltime->neg)
- return (null_value= 1);
-
- days= (long) (seconds / SECONDS_IN_24H);
-
- calc_time_from_sec(ltime, (long)(seconds % SECONDS_IN_24H), microseconds);
-
- ltime->time_type= is_time ? MYSQL_TIMESTAMP_TIME : MYSQL_TIMESTAMP_DATETIME;
-
- if (!is_time)
- {
- if (get_date_from_daynr(days,&ltime->year,&ltime->month,&ltime->day) ||
- !ltime->day)
- return (null_value= 1);
- return (null_value= 0);
- }
-
- ltime->hour+= days*24;
- return (null_value= adjust_time_range_with_warn(ltime, decimals));
+ maybe_null= true;
+ return m_func_handler->fix_length_and_dec(this);
}
@@ -2863,12 +2641,11 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
bool overflow= 0;
longlong hour= args[0]->val_int();
longlong minute= args[1]->val_int();
- ulonglong second;
- ulong microsecond;
- bool neg= args[2]->get_seconds(&second, &microsecond);
+ VSec6 sec(args[2], "seconds", 59);
- if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
- minute < 0 || minute > 59 || neg || second > 59)
+ DBUG_ASSERT(sec.sec() <= 59);
+ if (args[0]->null_value || args[1]->null_value || sec.is_null() ||
+ minute < 0 || minute > 59 || sec.neg() || sec.truncated())
return (null_value= 1);
bzero(ltime, sizeof(*ltime));
@@ -2889,8 +2666,8 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
ltime->hour= (uint) ((hour < 0 ? -hour : hour));
ltime->minute= (uint) minute;
- ltime->second= (uint) second;
- ltime->second_part= microsecond;
+ ltime->second= (uint) sec.sec();
+ ltime->second_part= sec.usec();
}
else
{
@@ -2899,10 +2676,10 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
ltime->second= TIME_MAX_SECOND;
char buf[28];
char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10);
- int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u", (uint)minute, (uint)second);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- buf, len, MYSQL_TIMESTAMP_TIME,
- NullS);
+ int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u",
+ (uint) minute, (uint) sec.sec());
+ ErrConvString err(buf, len, &my_charset_bin);
+ current_thd->push_warning_truncated_wrong_value("time", err.ptr());
}
return (null_value= 0);
@@ -2929,8 +2706,8 @@ longlong Item_func_microsecond::val_int()
longlong Item_func_timestamp_diff::val_int()
{
MYSQL_TIME ltime1, ltime2;
- longlong seconds;
- long microseconds;
+ ulonglong seconds;
+ ulong microseconds;
long months= 0;
int neg= 1;
THD *thd= current_thd;
@@ -3009,21 +2786,21 @@ longlong Item_func_timestamp_diff::val_int()
case INTERVAL_MONTH:
return months*neg;
case INTERVAL_WEEK:
- return seconds / SECONDS_IN_24H / 7L * neg;
+ return ((longlong) (seconds / SECONDS_IN_24H / 7L)) * neg;
case INTERVAL_DAY:
- return seconds / SECONDS_IN_24H * neg;
+ return ((longlong) (seconds / SECONDS_IN_24H)) * neg;
case INTERVAL_HOUR:
- return seconds/3600L*neg;
+ return ((longlong) (seconds / 3600L)) * neg;
case INTERVAL_MINUTE:
- return seconds/60L*neg;
+ return ((longlong) (seconds / 60L)) * neg;
case INTERVAL_SECOND:
- return seconds*neg;
+ return ((longlong) seconds) * neg;
case INTERVAL_MICROSECOND:
/*
In MySQL difference between any two valid datetime values
in microseconds fits into longlong.
*/
- return (seconds*1000000L+microseconds)*neg;
+ return ((longlong) ((ulonglong) seconds * 1000000L + microseconds)) * neg;
default:
break;
}
@@ -3153,15 +2930,10 @@ void Item_func_get_format::print(String *str, enum_query_type query_type)
specifiers supported by extract_date_time() function.
@return
- One of date_time_format_types values:
- - DATE_TIME_MICROSECOND
- - DATE_TIME
- - DATE_ONLY
- - TIME_MICROSECOND
- - TIME_ONLY
+ A function handler corresponding the given format
*/
-static date_time_format_types
+static const Item_handled_func::Handler *
get_date_time_result_type(const char *format, uint length)
{
const char *time_part_frms= "HISThiklrs";
@@ -3188,21 +2960,21 @@ get_date_time_result_type(const char *format, uint length)
frac_second_used implies time_part_used, and thus we already
have all types of date-time components and can end our search.
*/
- return DATE_TIME_MICROSECOND;
+ return &func_handler_str_to_date_datetime_usec;
}
}
}
/* We don't have all three types of date-time components */
if (frac_second_used)
- return TIME_MICROSECOND;
+ return &func_handler_str_to_date_time_usec;
if (time_part_used)
{
if (date_part_used)
- return DATE_TIME;
- return TIME_ONLY;
+ return &func_handler_str_to_date_datetime_sec;
+ return &func_handler_str_to_date_time_sec;
}
- return DATE_ONLY;
+ return &func_handler_str_to_date_date;
}
@@ -3222,56 +2994,27 @@ bool Item_func_str_to_date::fix_length_and_dec()
internal_charset= &my_charset_utf8mb4_general_ci;
maybe_null= true;
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
+ set_func_handler(&func_handler_str_to_date_datetime_usec);
if ((const_item= args[1]->const_item()))
{
- char format_buff[64];
- String format_str(format_buff, sizeof(format_buff), &my_charset_bin);
+ StringBuffer<64> format_str;
String *format= args[1]->val_str(&format_str, &format_converter,
internal_charset);
- decimals= 0;
if (!args[1]->null_value)
- {
- date_time_format_types cached_format_type=
- get_date_time_result_type(format->ptr(), format->length());
- switch (cached_format_type) {
- case DATE_ONLY:
- set_handler(&type_handler_newdate);
- fix_attributes_date();
- break;
- case TIME_MICROSECOND:
- set_handler(&type_handler_time2);
- fix_attributes_time(TIME_SECOND_PART_DIGITS);
- break;
- case TIME_ONLY:
- set_handler(&type_handler_time2);
- fix_attributes_time(0);
- break;
- case DATE_TIME_MICROSECOND:
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
- break;
- case DATE_TIME:
- set_handler(&type_handler_datetime2);
- fix_attributes_datetime(0);
- break;
- }
- }
+ set_func_handler(get_date_time_result_type(format->ptr(), format->length()));
}
- cached_timestamp_type= mysql_timestamp_type();
- return FALSE;
+ return m_func_handler->fix_length_and_dec(this);
}
-bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_str_to_date::get_date_common(MYSQL_TIME *ltime,
+ ulonglong fuzzy_date,
+ timestamp_type tstype)
{
DATE_TIME_FORMAT date_time_format;
- char val_buff[64], format_buff[64];
- String val_string(val_buff, sizeof(val_buff), &my_charset_bin), *val;
- String format_str(format_buff, sizeof(format_buff), &my_charset_bin),
- *format;
+ StringBuffer<64> val_string, format_str;
+ String *val, *format;
val= args[0]->val_str(&val_string, &subject_converter, internal_charset);
format= args[1]->val_str(&format_str, &format_converter, internal_charset);
@@ -3281,19 +3024,9 @@ bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
date_time_format.format.str= (char*) format->ptr();
date_time_format.format.length= format->length();
if (extract_date_time(&date_time_format, val->ptr(), val->length(),
- ltime, cached_timestamp_type, 0, "datetime",
+ ltime, tstype, 0, "datetime",
fuzzy_date | sql_mode_for_dates(current_thd)))
return (null_value=1);
- if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day)
- {
- /*
- Day part for time type can be nonzero value and so
- we should add hours from day part to hour part to
- keep valid time value.
- */
- ltime->hour+= ltime->day*24;
- ltime->day= 0;
- }
return (null_value= 0);
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 7aacdec85e0..f9709b8f72a 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -25,11 +25,6 @@
class MY_LOCALE;
-enum date_time_format_types
-{
- TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
-};
-
bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval);
@@ -586,66 +581,17 @@ public:
};
-class Item_temporal_func: public Item_func
-{
-public:
- Item_temporal_func(THD *thd): Item_func(thd) {}
- Item_temporal_func(THD *thd, Item *a): Item_func(thd, a) {}
- Item_temporal_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {}
- Item_temporal_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c) {}
- String *val_str(String *str);
- longlong val_int() { return val_int_from_date(); }
- double val_real() { return val_real_from_date(); }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
- my_decimal *val_decimal(my_decimal *decimal_value)
- { return val_decimal_from_date(decimal_value); }
-};
-
-
-/**
- Abstract class for functions returning TIME, DATE, DATETIME or string values,
- whose data type depends on parameters and is set at fix_fields time.
-*/
-class Item_temporal_hybrid_func: public Item_hybrid_func
-{
-protected:
- String ascii_buf; // Conversion buffer
-public:
- Item_temporal_hybrid_func(THD *thd, Item *a, Item *b):
- Item_hybrid_func(thd, a, b) {}
-
- longlong val_int() { return val_int_from_date(); }
- double val_real() { return val_real_from_date(); }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
- my_decimal *val_decimal(my_decimal *decimal_value)
- { return val_decimal_from_date(decimal_value); }
-
- /**
- Fix the returned timestamp to match field_type(),
- which is important for val_str().
- */
- bool fix_temporal_type(MYSQL_TIME *ltime);
- /**
- Return string value in ASCII character set.
- */
- String *val_str_ascii(String *str);
- /**
- Return string value in @@character_set_connection.
- */
- String *val_str(String *str)
- {
- return val_str_from_val_str_ascii(str, &ascii_buf);
- }
-};
-
-
-class Item_datefunc :public Item_temporal_func
+class Item_datefunc :public Item_func
{
public:
- Item_datefunc(THD *thd): Item_temporal_func(thd) { }
- Item_datefunc(THD *thd, Item *a): Item_temporal_func(thd, a) { }
- Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { }
+ Item_datefunc(THD *thd): Item_func(thd) { }
+ Item_datefunc(THD *thd, Item *a): Item_func(thd, a) { }
+ Item_datefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) { }
const Type_handler *type_handler() const { return &type_handler_newdate; }
+ longlong val_int() { return Date(this).to_longlong(); }
+ double val_real() { return Date(this).to_double(); }
+ String *val_str(String *to) { return Date(this).to_string(to); }
+ my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); }
bool fix_length_and_dec()
{
fix_attributes_date();
@@ -655,26 +601,34 @@ public:
};
-class Item_timefunc :public Item_temporal_func
+class Item_timefunc :public Item_func
{
public:
- Item_timefunc(THD *thd): Item_temporal_func(thd) {}
- Item_timefunc(THD *thd, Item *a): Item_temporal_func(thd, a) {}
- Item_timefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) {}
- Item_timefunc(THD *thd, Item *a, Item *b, Item *c):
- Item_temporal_func(thd, a, b ,c) {}
+ Item_timefunc(THD *thd): Item_func(thd) {}
+ Item_timefunc(THD *thd, Item *a): Item_func(thd, a) {}
+ Item_timefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {}
+ Item_timefunc(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b ,c) {}
const Type_handler *type_handler() const { return &type_handler_time2; }
+ longlong val_int() { return Time(this).to_longlong(); }
+ double val_real() { return Time(this).to_double(); }
+ String *val_str(String *to) { return Time(this).to_string(to, decimals); }
+ my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); }
};
-class Item_datetimefunc :public Item_temporal_func
+class Item_datetimefunc :public Item_func
{
public:
- Item_datetimefunc(THD *thd): Item_temporal_func(thd) {}
- Item_datetimefunc(THD *thd, Item *a): Item_temporal_func(thd, a) {}
+ Item_datetimefunc(THD *thd): Item_func(thd) {}
+ Item_datetimefunc(THD *thd, Item *a): Item_func(thd, a) {}
+ Item_datetimefunc(THD *thd, Item *a, Item *b): Item_func(thd, a, b) {}
Item_datetimefunc(THD *thd, Item *a, Item *b, Item *c):
- Item_temporal_func(thd, a, b ,c) {}
+ Item_func(thd, a, b ,c) {}
const Type_handler *type_handler() const { return &type_handler_datetime2; }
+ longlong val_int() { return Datetime(this).to_longlong(); }
+ double val_real() { return Datetime(this).to_double(); }
+ String *val_str(String *to) { return Datetime(this).to_string(to, decimals); }
+ my_decimal *val_decimal(my_decimal *to) { return Datetime(this).to_decimal(to); }
};
@@ -988,18 +942,17 @@ public:
};
-class Item_date_add_interval :public Item_temporal_hybrid_func
+class Item_date_add_interval :public Item_handled_func
{
public:
const interval_type int_type; // keep it public
const bool date_sub_interval; // keep it public
Item_date_add_interval(THD *thd, Item *a, Item *b, interval_type type_arg,
bool neg_arg):
- Item_temporal_hybrid_func(thd, a, b),int_type(type_arg),
+ Item_handled_func(thd, a, b), int_type(type_arg),
date_sub_interval(neg_arg) {}
const char *func_name() const { return "date_add_interval"; }
bool fix_length_and_dec();
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
void print(String *str, enum_query_type query_type);
enum precedence precedence() const { return ADDINTERVAL_PRECEDENCE; }
@@ -1157,22 +1110,16 @@ public:
};
-class Item_temporal_typecast: public Item_temporal_func
-{
-public:
- Item_temporal_typecast(THD *thd, Item *a): Item_temporal_func(thd, a) {}
- virtual const char *cast_type() const = 0;
- void print(String *str, enum_query_type query_type);
-};
-
-class Item_date_typecast :public Item_temporal_typecast
+class Item_date_typecast :public Item_datefunc
{
public:
- Item_date_typecast(THD *thd, Item *a): Item_temporal_typecast(thd, a) {}
+ Item_date_typecast(THD *thd, Item *a): Item_datefunc(thd, a) {}
const char *func_name() const { return "cast_as_date"; }
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
- const char *cast_type() const { return "date"; }
- const Type_handler *type_handler() const { return &type_handler_newdate; }
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this);
@@ -1182,15 +1129,17 @@ public:
};
-class Item_time_typecast :public Item_temporal_typecast
+class Item_time_typecast :public Item_timefunc
{
public:
Item_time_typecast(THD *thd, Item *a, uint dec_arg):
- Item_temporal_typecast(thd, a) { decimals= dec_arg; }
+ Item_timefunc(thd, a) { decimals= dec_arg; }
const char *func_name() const { return "cast_as_time"; }
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
- const char *cast_type() const { return "time"; }
- const Type_handler *type_handler() const { return &type_handler_time2; }
bool fix_length_and_dec()
{
return args[0]->type_handler()->
@@ -1201,14 +1150,16 @@ public:
};
-class Item_datetime_typecast :public Item_temporal_typecast
+class Item_datetime_typecast :public Item_datetimefunc
{
public:
Item_datetime_typecast(THD *thd, Item *a, uint dec_arg):
- Item_temporal_typecast(thd, a) { decimals= dec_arg; }
+ Item_datetimefunc(thd, a) { decimals= dec_arg; }
const char *func_name() const { return "cast_as_datetime"; }
- const char *cast_type() const { return "datetime"; }
- const Type_handler *type_handler() const { return &type_handler_datetime2; }
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
bool fix_length_and_dec()
{
@@ -1234,25 +1185,63 @@ public:
};
-class Item_func_add_time :public Item_temporal_hybrid_func
+class Item_func_timestamp :public Item_datetimefunc
{
- const bool is_date;
- int sign;
-
+ bool check_arguments() const
+ {
+ return args[0]->check_type_can_return_date(func_name()) ||
+ args[1]->check_type_can_return_time(func_name());
+ }
public:
- Item_func_add_time(THD *thd, Item *a, Item *b, bool type_arg, bool neg_arg):
- Item_temporal_hybrid_func(thd, a, b), is_date(type_arg)
- { sign= neg_arg ? -1 : 1; }
- bool fix_length_and_dec();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
- const char *func_name() const
+ Item_func_timestamp(THD *thd, Item *a, Item *b)
+ :Item_datetimefunc(thd, a, b)
+ { }
+ const char *func_name() const { return "timestamp"; }
+ bool fix_length_and_dec()
+ {
+ uint dec= MY_MAX(args[0]->datetime_precision(), args[1]->time_precision());
+ fix_attributes_datetime(dec);
+ maybe_null= true;
+ return false;
+ }
+ bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
- return is_date ? "timestamp" : sign > 0 ? "addtime" : "subtime";
+ Datetime dt(current_thd, args[0], 0);
+ MYSQL_TIME ltime2;
+ return (null_value= (!dt.is_valid_datetime() ||
+ args[1]->get_time(&ltime2) ||
+ Sec6_add(dt.get_mysql_time(), &ltime2, 1).
+ to_datetime(ltime)));
}
Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_timestamp>(thd, this); }
+};
+
+
+/**
+ ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a
+ time/datetime value
+
+ t: time_or_datetime_expression
+ a: time_expression
+
+ Result: Time value or datetime value
+*/
+
+class Item_func_add_time :public Item_handled_func
+{
+ int sign;
+public:
+ Item_func_add_time(THD *thd, Item *a, Item *b, bool neg_arg)
+ :Item_handled_func(thd, a, b), sign(neg_arg ? -1 : 1)
+ { }
+ bool fix_length_and_dec();
+ const char *func_name() const { return sign > 0 ? "addtime" : "subtime"; }
+ Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_add_time>(thd, this); }
};
+
class Item_func_timediff :public Item_timefunc
{
bool check_arguments() const
@@ -1369,19 +1358,18 @@ public:
};
-class Item_func_str_to_date :public Item_temporal_hybrid_func
+class Item_func_str_to_date :public Item_handled_func
{
- timestamp_type cached_timestamp_type;
bool const_item;
String subject_converter;
String format_converter;
CHARSET_INFO *internal_charset;
public:
Item_func_str_to_date(THD *thd, Item *a, Item *b):
- Item_temporal_hybrid_func(thd, a, b), const_item(false),
+ Item_handled_func(thd, a, b), const_item(false),
internal_charset(NULL)
{}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date_common(MYSQL_TIME *ltime, ulonglong fuzzy_date, timestamp_type);
const char *func_name() const { return "str_to_date"; }
bool fix_length_and_dec();
Item *get_copy(THD *thd)
@@ -1401,4 +1389,329 @@ public:
{ return get_item_copy<Item_func_last_day>(thd, this); }
};
+
+/*****************************************************************************/
+
+class Func_handler_date_add_interval
+{
+protected:
+ static uint interval_dec(const Item *item, interval_type int_type)
+ {
+ if (int_type == INTERVAL_MICROSECOND ||
+ (int_type >= INTERVAL_DAY_MICROSECOND &&
+ int_type <= INTERVAL_SECOND_MICROSECOND))
+ return TIME_SECOND_PART_DIGITS;
+ if (int_type == INTERVAL_SECOND && item->decimals > 0)
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+ return 0;
+ }
+ interval_type int_type(const Item_handled_func *item) const
+ {
+ return static_cast<const Item_date_add_interval*>(item)->int_type;
+ }
+ bool sub(const Item_handled_func *item) const
+ {
+ return static_cast<const Item_date_add_interval*>(item)->date_sub_interval;
+ }
+ bool add(Item *item, interval_type type, bool sub, MYSQL_TIME *to) const
+ {
+ INTERVAL interval;
+ if (get_interval_value(item, type, &interval))
+ return true;
+ if (sub)
+ interval.neg = !interval.neg;
+ return date_add_interval(to, type, interval);
+ }
+};
+
+
+class Func_handler_date_add_interval_datetime:
+ public Item_handled_func::Handler_datetime,
+ public Func_handler_date_add_interval
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
+ interval_dec(item->arguments()[1], int_type(item)));
+ item->fix_attributes_datetime(dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ Datetime dt(current_thd, item->arguments()[0], 0);
+ if (!dt.is_valid_datetime() ||
+ dt.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ return (item->null_value= true);
+ dt.copy_to_mysql_time(to);
+ return (item->null_value= add(item->arguments()[1],
+ int_type(item), sub(item), to));
+ }
+};
+
+
+class Func_handler_date_add_interval_datetime_arg0_time:
+ public Func_handler_date_add_interval_datetime
+{
+public:
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const;
+};
+
+
+class Func_handler_date_add_interval_date:
+ public Item_handled_func::Handler_date,
+ public Func_handler_date_add_interval
+{
+public:
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ Date d(current_thd, item->arguments()[0], 0);
+ if (!d.is_valid_date() ||
+ d.check_date_with_warn(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ return (item->null_value= true);
+ d.copy_to_mysql_time(to);
+ return (item->null_value= add(item->arguments()[1],
+ int_type(item), sub(item), to));
+ }
+};
+
+
+class Func_handler_date_add_interval_time:
+ public Item_handled_func::Handler_time,
+ public Func_handler_date_add_interval
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->time_precision(),
+ interval_dec(item->arguments()[1], int_type(item)));
+ item->fix_attributes_time(dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ Time t(item->arguments()[0]);
+ if (!t.is_valid_time())
+ return (item->null_value= true);
+ t.copy_to_mysql_time(to);
+ return (item->null_value= add(item->arguments()[1],
+ int_type(item), sub(item), to));
+ }
+};
+
+
+class Func_handler_date_add_interval_string:
+ public Item_handled_func::Handler_temporal_string,
+ public Func_handler_date_add_interval
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
+ interval_dec(item->arguments()[1], int_type(item)));
+ item->collation.set(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
+ item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ if (item->arguments()[0]->get_date(to, 0) ||
+ (to->time_type != MYSQL_TIMESTAMP_TIME &&
+ check_date_with_warn(to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
+ MYSQL_TIMESTAMP_ERROR)))
+ return (item->null_value= true);
+ return (item->null_value= add(item->arguments()[1],
+ int_type(item), sub(item), to));
+ }
+};
+
+
+class Func_handler_sign
+{
+protected:
+ int m_sign;
+ Func_handler_sign(int sign) :m_sign(sign) { }
+};
+
+
+class Func_handler_add_time_datetime:
+ public Item_handled_func::Handler_datetime,
+ public Func_handler_sign
+{
+public:
+ Func_handler_add_time_datetime(int sign)
+ :Func_handler_sign(sign)
+ { }
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->datetime_precision(),
+ item->arguments()[1]->time_precision());
+ item->fix_attributes_datetime(dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ MYSQL_TIME l_time2;
+ Datetime dt(current_thd, item->arguments()[0], 0);
+ return (item->null_value= (!dt.is_valid_datetime() ||
+ item->arguments()[1]->get_time(&l_time2) ||
+ Sec6_add(dt.get_mysql_time(), &l_time2, m_sign).
+ to_datetime(to)));
+ }
+};
+
+
+class Func_handler_add_time_time:
+ public Item_handled_func::Handler_time,
+ public Func_handler_sign
+{
+public:
+ Func_handler_add_time_time(int sign)
+ :Func_handler_sign(sign)
+ { }
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->time_precision(),
+ item->arguments()[1]->time_precision());
+ item->fix_attributes_time(dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ MYSQL_TIME l_time2;
+ Time t(item->arguments()[0]);
+ return (item->null_value= (!t.is_valid_time() ||
+ item->arguments()[1]->get_time(&l_time2) ||
+ Sec6_add(t.get_mysql_time(), &l_time2, m_sign).
+ to_time(to, item->decimals)));
+ }
+};
+
+
+class Func_handler_add_time_string:
+ public Item_handled_func::Handler_temporal_string,
+ public Func_handler_sign
+{
+public:
+ Func_handler_add_time_string(int sign)
+ :Func_handler_sign(sign)
+ { }
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ uint dec= MY_MAX(item->arguments()[0]->decimals,
+ item->arguments()[1]->decimals);
+ item->collation.set(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
+ item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ // Detect a proper timestamp type based on the argument values
+ MYSQL_TIME l_time1, l_time2;
+ if (item->arguments()[0]->get_time(&l_time1) ||
+ item->arguments()[1]->get_time(&l_time2))
+ return (item->null_value= true);
+ Sec6_add add(&l_time1, &l_time2, m_sign);
+ return (item->null_value= (l_time1.time_type == MYSQL_TIMESTAMP_TIME ?
+ add.to_time(to, item->decimals) :
+ add.to_datetime(to)));
+ }
+};
+
+
+class Func_handler_str_to_date_datetime_sec:
+ public Item_handled_func::Handler_datetime
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ item->fix_attributes_datetime(0);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
+ }
+};
+
+
+class Func_handler_str_to_date_datetime_usec:
+ public Item_handled_func::Handler_datetime
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ item->fix_attributes_datetime(TIME_SECOND_PART_DIGITS);
+ return false;
+ }
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
+ }
+};
+
+
+class Func_handler_str_to_date_date: public Item_handled_func::Handler_date
+{
+public:
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(to, fuzzy, MYSQL_TIMESTAMP_DATE);
+ }
+};
+
+
+class Func_handler_str_to_date_time: public Item_handled_func::Handler_time
+{
+public:
+ bool get_date(Item_handled_func *item, MYSQL_TIME *to, ulonglong fuzzy) const
+ {
+ if (static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(to, fuzzy, MYSQL_TIMESTAMP_TIME))
+ return true;
+ if (to->day)
+ {
+ /*
+ Day part for time type can be nonzero value and so
+ we should add hours from day part to hour part to
+ keep valid time value.
+ */
+ to->hour+= to->day * 24;
+ to->day= 0;
+ }
+ return false;
+ }
+};
+
+
+class Func_handler_str_to_date_time_sec: public Func_handler_str_to_date_time
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ item->fix_attributes_time(0);
+ return false;
+ }
+};
+
+
+class Func_handler_str_to_date_time_usec: public Func_handler_str_to_date_time
+{
+public:
+ bool fix_length_and_dec(Item_handled_func *item) const
+ {
+ item->fix_attributes_time(TIME_SECOND_PART_DIGITS);
+ return false;
+ }
+};
+
+
#endif /* ITEM_TIMEFUNC_INCLUDED */
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index 3ad0527384d..a17f9482ea0 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -120,7 +120,6 @@ Item_window_func::fix_fields(THD *thd, Item **ref)
const_item_cache= false;
with_window_func= true;
- with_sum_func= false;
if (fix_length_and_dec())
return TRUE;
@@ -514,11 +513,11 @@ void Item_sum_hybrid_simple::reset_field()
}
case DECIMAL_RESULT:
{
- my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff);
+ VDec arg_dec(args[0]);
if (maybe_null)
{
- if (args[0]->null_value)
+ if (arg_dec.is_null())
result_field->set_null();
else
result_field->set_notnull();
@@ -527,9 +526,7 @@ void Item_sum_hybrid_simple::reset_field()
We must store zero in the field as we will use the field value in
add()
*/
- if (!arg_dec) // Null
- arg_dec= &decimal_zero;
- result_field->store_decimal(arg_dec);
+ result_field->store_decimal(arg_dec.ptr_or(&decimal_zero));
break;
}
case ROW_RESULT:
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 63734ecf9ac..146c5aa57fe 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -29,10 +29,8 @@
/*
TODO: future development directions:
- 1. add real constants for XPATH_NODESET_CMP and XPATH_NODESET
- into enum Type in item.h.
- 2. add nodeset_to_nodeset_comparator
- 3. add lacking functions:
+ 1. add nodeset_to_nodeset_comparator
+ 2. add lacking functions:
- name()
- lang()
- string()
@@ -44,7 +42,7 @@
- substring-after()
- normalize-space()
- substring-before()
- 4. add lacking axis:
+ 3. add lacking axis:
- following-sibling
- following,
- preceding-sibling
@@ -151,6 +149,9 @@ public:
};
+static Type_handler_long_blob type_handler_xpath_nodeset;
+
+
/*
Common features of the functions returning a node set.
*/
@@ -181,16 +182,29 @@ public:
void prepare(String *nodeset)
{
prepare_nodes();
- String *res= args[0]->val_nodeset(&tmp_value);
+ String *res= args[0]->val_raw(&tmp_value);
fltbeg= (MY_XPATH_FLT*) res->ptr();
fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
nodeset->length(0);
}
- enum Type type() const { return XPATH_NODESET; }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_xpath_nodeset;
+ }
+ const Type_handler *fixed_type_handler() const
+ {
+ return &type_handler_xpath_nodeset;
+ }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
String *val_str(String *str)
{
prepare_nodes();
- String *res= val_nodeset(&tmp2_value);
+ String *res= val_raw(&tmp2_value);
fltbeg= (MY_XPATH_FLT*) res->ptr();
fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
String active;
@@ -247,7 +261,7 @@ public:
Item_nodeset_func_rootelement(THD *thd, String *pxml):
Item_nodeset_func(thd, pxml) {}
const char *func_name() const { return "xpath_rootelement"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_rootelement>(thd, this); }
};
@@ -260,7 +274,7 @@ public:
Item_nodeset_func_union(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) {}
const char *func_name() const { return "xpath_union"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_union>(thd, this); }
};
@@ -294,7 +308,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_selfbyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_selfbyname>(thd, this); }
};
@@ -308,7 +322,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_childbyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_childbyname>(thd, this); }
};
@@ -324,7 +338,7 @@ public:
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml),
need_self(need_self_arg) {}
const char *func_name() const { return "xpath_descendantbyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_descendantbyname>(thd, this); }
};
@@ -340,7 +354,7 @@ public:
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml),
need_self(need_self_arg) {}
const char *func_name() const { return "xpath_ancestorbyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_ancestorbyname>(thd, this); }
};
@@ -354,7 +368,7 @@ public:
String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_parentbyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_parentbyname>(thd, this); }
};
@@ -368,7 +382,7 @@ public:
uint l_arg, String *pxml):
Item_nodeset_func_axisbyname(thd, a, n_arg, l_arg, pxml) {}
const char *func_name() const { return "xpath_attributebyname"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_attributebyname>(thd, this); }
};
@@ -385,7 +399,7 @@ public:
Item_nodeset_func_predicate(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) {}
const char *func_name() const { return "xpath_predicate"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_predicate>(thd, this); }
};
@@ -398,7 +412,7 @@ public:
Item_nodeset_func_elementbyindex(THD *thd, Item *a, Item *b, String *pxml):
Item_nodeset_func(thd, a, b, pxml) { }
const char *func_name() const { return "xpath_elementbyindex"; }
- String *val_nodeset(String *nodeset);
+ String *val_raw(String *nodeset);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_nodeset_func_elementbyindex>(thd, this); }
};
@@ -420,9 +434,9 @@ public:
const char *func_name() const { return "xpath_cast_bool"; }
longlong val_int()
{
- if (args[0]->type() == XPATH_NODESET)
+ if (args[0]->fixed_type_handler() == &type_handler_xpath_nodeset)
{
- String *flt= args[0]->val_nodeset(&tmp_value);
+ String *flt= args[0]->val_raw(&tmp_value);
return flt->length() == sizeof(MY_XPATH_FLT) ? 1 : 0;
}
return args[0]->val_real() ? 1 : 0;
@@ -455,7 +469,7 @@ public:
String *string_cache;
Item_nodeset_context_cache(THD *thd, String *str_arg, String *pxml):
Item_nodeset_func(thd, pxml), string_cache(str_arg) { }
- String *val_nodeset(String *res)
+ String *val_raw(String *res)
{ return string_cache; }
bool fix_length_and_dec() { max_length= MAX_BLOB_WIDTH;; return FALSE; }
Item *get_copy(THD *thd)
@@ -474,7 +488,7 @@ public:
bool fix_length_and_dec() { max_length=10; return FALSE; }
longlong val_int()
{
- String *flt= args[0]->val_nodeset(&tmp_value);
+ String *flt= args[0]->val_raw(&tmp_value);
if (flt->length() == sizeof(MY_XPATH_FLT))
return ((MY_XPATH_FLT*)flt->ptr())->pos + 1;
return 0;
@@ -496,7 +510,7 @@ public:
longlong val_int()
{
uint predicate_supplied_context_size;
- String *res= args[0]->val_nodeset(&tmp_value);
+ String *res= args[0]->val_raw(&tmp_value);
if (res->length() == sizeof(MY_XPATH_FLT) &&
(predicate_supplied_context_size= ((MY_XPATH_FLT*)res->ptr())->size))
return predicate_supplied_context_size;
@@ -519,7 +533,7 @@ public:
double val_real()
{
double sum= 0;
- String *res= args[0]->val_nodeset(&tmp_value);
+ String *res= args[0]->val_raw(&tmp_value);
MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
@@ -587,19 +601,23 @@ public:
Item_nodeset_to_const_comparator(THD *thd, Item *nodeset, Item *cmpfunc,
String *p):
Item_bool_func(thd, nodeset, cmpfunc), pxml(p) {}
- enum Type type() const { return XPATH_NODESET_CMP; };
const char *func_name() const { return "xpath_nodeset_to_const_comparator"; }
bool check_vcol_func_processor(void *arg)
{
return mark_unsupported_function(func_name(), arg, VCOL_IMPOSSIBLE);
}
-
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
longlong val_int()
{
Item_func *comp= (Item_func*)args[1];
Item_string_xml_non_const *fake=
(Item_string_xml_non_const*)(comp->arguments()[0]);
- String *res= args[0]->val_nodeset(&tmp_nodeset);
+ String *res= args[0]->val_raw(&tmp_nodeset);
MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
@@ -630,7 +648,7 @@ public:
};
-String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset)
+String *Item_nodeset_func_rootelement::val_raw(String *nodeset)
{
nodeset->length(0);
((XPathFilter*)nodeset)->append_element(0, 0);
@@ -638,11 +656,11 @@ String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset)
}
-String * Item_nodeset_func_union::val_nodeset(String *nodeset)
+String * Item_nodeset_func_union::val_raw(String *nodeset)
{
uint num_nodes= pxml->length() / sizeof(MY_XML_NODE);
- String set0, *s0= args[0]->val_nodeset(&set0);
- String set1, *s1= args[1]->val_nodeset(&set1);
+ String set0, *s0= args[0]->val_raw(&set0);
+ String set1, *s1= args[1]->val_raw(&set1);
String both_str;
both_str.alloc(num_nodes);
char *both= (char*) both_str.ptr();
@@ -669,7 +687,7 @@ String * Item_nodeset_func_union::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_selfbyname::val_raw(String *nodeset)
{
prepare(nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
@@ -683,7 +701,7 @@ String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_childbyname::val_raw(String *nodeset)
{
prepare(nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
@@ -704,7 +722,7 @@ String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_descendantbyname::val_raw(String *nodeset)
{
prepare(nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
@@ -726,7 +744,7 @@ String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_ancestorbyname::val_raw(String *nodeset)
{
char *active;
String active_str;
@@ -768,7 +786,7 @@ String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_parentbyname::val_raw(String *nodeset)
{
char *active;
String active_str;
@@ -791,7 +809,7 @@ String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
+String *Item_nodeset_func_attributebyname::val_raw(String *nodeset)
{
prepare(nodeset);
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
@@ -812,7 +830,7 @@ String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
}
-String *Item_nodeset_func_predicate::val_nodeset(String *str)
+String *Item_nodeset_func_predicate::val_raw(String *str)
{
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
Item_func *comp_func= (Item_func*)args[1];
@@ -832,7 +850,7 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)
}
-String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
+String *Item_nodeset_func_elementbyindex::val_raw(String *nodeset)
{
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
prepare(nodeset);
@@ -845,7 +863,9 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
flt->pos,
size);
int index= (int) (args[1]->val_int()) - 1;
- if (index >= 0 && (flt->pos == (uint) index || args[1]->is_bool_type()))
+ if (index >= 0 &&
+ (flt->pos == (uint) index ||
+ (args[1]->type_handler()->is_bool_type())))
((XPathFilter*)nodeset)->append_element(flt->num, pos++);
}
return nodeset;
@@ -858,7 +878,7 @@ String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
*/
static Item* nodeset2bool(MY_XPATH *xpath, Item *item)
{
- if (item->type() == Item::XPATH_NODESET)
+ if (item->fixed_type_handler() == &type_handler_xpath_nodeset)
return new (xpath->thd->mem_root)
Item_xpath_cast_bool(xpath->thd, item, xpath->pxml);
return item;
@@ -988,13 +1008,13 @@ static Item *create_comparator(MY_XPATH *xpath,
int oper, MY_XPATH_LEX *context,
Item *a, Item *b)
{
- if (a->type() != Item::XPATH_NODESET &&
- b->type() != Item::XPATH_NODESET)
+ if (a->fixed_type_handler() != &type_handler_xpath_nodeset &&
+ b->fixed_type_handler() != &type_handler_xpath_nodeset)
{
return eq_func(xpath->thd, oper, a, b); // two scalar arguments
}
- else if (a->type() == Item::XPATH_NODESET &&
- b->type() == Item::XPATH_NODESET)
+ else if (a->fixed_type_handler() == &type_handler_xpath_nodeset &&
+ b->fixed_type_handler() == &type_handler_xpath_nodeset)
{
uint len= (uint)(xpath->query.end - context->beg);
set_if_smaller(len, 32);
@@ -1019,7 +1039,7 @@ static Item *create_comparator(MY_XPATH *xpath,
Item_string_xml_non_const(thd, "", 0, xpath->cs));
Item_nodeset_func *nodeset;
Item *scalar, *comp;
- if (a->type() == Item::XPATH_NODESET)
+ if (a->fixed_type_handler() == &type_handler_xpath_nodeset)
{
nodeset= (Item_nodeset_func*) a;
scalar= b;
@@ -1053,7 +1073,7 @@ static Item* nametestfunc(MY_XPATH *xpath,
MEM_ROOT *mem_root= thd->mem_root;
DBUG_ASSERT(arg != 0);
- DBUG_ASSERT(arg->type() == Item::XPATH_NODESET);
+ DBUG_ASSERT(arg->fixed_type_handler() == &type_handler_xpath_nodeset);
DBUG_ASSERT(beg != 0);
DBUG_ASSERT(len > 0);
@@ -1306,7 +1326,7 @@ static Item *create_func_substr(MY_XPATH *xpath, Item **args, uint nargs)
static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs)
{
- if (args[0]->type() != Item::XPATH_NODESET)
+ if (args[0]->fixed_type_handler() != &type_handler_xpath_nodeset)
return 0;
return new (xpath->thd->mem_root) Item_func_xpath_count(xpath->thd, args[0], xpath->pxml);
}
@@ -1314,7 +1334,7 @@ static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs)
static Item *create_func_sum(MY_XPATH *xpath, Item **args, uint nargs)
{
- if (args[0]->type() != Item::XPATH_NODESET)
+ if (args[0]->fixed_type_handler() != &type_handler_xpath_nodeset)
return 0;
return new (xpath->thd->mem_root)
Item_func_xpath_sum(xpath->thd, args[0], xpath->pxml);
@@ -1793,7 +1813,8 @@ my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath)
xpath->item= nodeset2bool(xpath, xpath->item);
- if (xpath->item->is_bool_type())
+ const Type_handler *fh;
+ if ((fh= xpath->item->fixed_type_handler()) && fh->is_bool_type())
{
xpath->context= new (xpath->thd->mem_root)
Item_nodeset_func_predicate(xpath->thd, prev_context,
@@ -2047,11 +2068,11 @@ static int my_xpath_parse_UnionExpr(MY_XPATH *xpath)
while (my_xpath_parse_term(xpath, MY_XPATH_LEX_VLINE))
{
Item *prev= xpath->item;
- if (prev->type() != Item::XPATH_NODESET)
+ if (prev->fixed_type_handler() != &type_handler_xpath_nodeset)
return 0;
if (!my_xpath_parse_PathExpr(xpath)
- || xpath->item->type() != Item::XPATH_NODESET)
+ || xpath->item->fixed_type_handler() != &type_handler_xpath_nodeset)
{
xpath->error= 1;
return 0;
@@ -2089,7 +2110,7 @@ my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH *xpath)
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
return 1;
- if (xpath->item->type() != Item::XPATH_NODESET)
+ if (xpath->item->fixed_type_handler() != &type_handler_xpath_nodeset)
{
xpath->lasttok= xpath->prevtok;
xpath->error= 1;
@@ -3054,7 +3075,7 @@ String *Item_func_xml_update::val_str(String *str)
null_value= 0;
if (!nodeset_func || get_xml(&xml) ||
!(rep= args[2]->val_str(&tmp_value3)) ||
- !(nodeset= nodeset_func->val_nodeset(&tmp_value2)))
+ !(nodeset= nodeset_func->val_raw(&tmp_value2)))
{
null_value= 1;
return 0;
diff --git a/sql/log.cc b/sql/log.cc
index 1ffa6f7588f..86137ad3543 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -866,10 +866,10 @@ bool Log_to_csv_event_handler::
Open_tables_backup open_tables_backup;
CHARSET_INFO *client_cs= thd->variables.character_set_client;
bool save_time_zone_used;
- long query_time= (long) MY_MIN(query_utime/1000000, TIME_MAX_VALUE_SECONDS);
- long lock_time= (long) MY_MIN(lock_utime/1000000, TIME_MAX_VALUE_SECONDS);
- long query_time_micro= (long) (query_utime % 1000000);
- long lock_time_micro= (long) (lock_utime % 1000000);
+ ulong query_time= (ulong) MY_MIN(query_utime/1000000, TIME_MAX_VALUE_SECONDS);
+ ulong lock_time= (ulong) MY_MIN(lock_utime/1000000, TIME_MAX_VALUE_SECONDS);
+ ulong query_time_micro= (ulong) (query_utime % 1000000);
+ ulong lock_time_micro= (ulong) (lock_utime % 1000000);
DBUG_ENTER("Log_to_csv_event_handler::log_slow");
@@ -1162,6 +1162,10 @@ bool LOGGER::error_log_print(enum loglevel level, const char *format,
{
bool error= FALSE;
Log_event_handler **current_handler;
+ THD *thd= current_thd;
+
+ if (likely(thd))
+ thd->error_printed_to_log= 1;
/* currently we don't need locking here as there is no error_log table */
for (current_handler= error_log_handler_list ; *current_handler ;)
@@ -2183,16 +2187,16 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional)
{
if (is_transactional)
{
- my_message(ER_TRANS_CACHE_FULL, ER_THD(thd, ER_TRANS_CACHE_FULL), MYF(MY_WME));
+ my_message(ER_TRANS_CACHE_FULL, ER_THD(thd, ER_TRANS_CACHE_FULL), MYF(0));
}
else
{
- my_message(ER_STMT_CACHE_FULL, ER_THD(thd, ER_STMT_CACHE_FULL), MYF(MY_WME));
+ my_message(ER_STMT_CACHE_FULL, ER_THD(thd, ER_STMT_CACHE_FULL), MYF(0));
}
}
else
{
- my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
+ my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
}
DBUG_VOID_RETURN;
@@ -2649,7 +2653,7 @@ bool MYSQL_LOG::open(
#endif
if ((file= mysql_file_open(log_file_key, log_file_name, open_flags,
- MYF(MY_WME | ME_WAITTANG))) < 0)
+ MYF(MY_WME))) < 0)
goto err;
if (is_fifo)
@@ -2791,7 +2795,7 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name,
{
THD *thd= current_thd;
if (unlikely(thd))
- my_error(ER_NO_UNIQUE_LOGFILE, MYF(ME_FATALERROR), log_name);
+ my_error(ER_NO_UNIQUE_LOGFILE, MYF(ME_FATAL), log_name);
sql_print_error(ER_DEFAULT(ER_NO_UNIQUE_LOGFILE), log_name);
return 1;
}
@@ -4627,7 +4631,7 @@ int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
if (!my_b_inited(&purge_index_file))
{
if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
- MYF(MY_WME | ME_WAITTANG))) < 0 ||
+ MYF(MY_WME))) < 0 ||
init_io_cache(&purge_index_file, file, IO_SIZE,
(destroy ? WRITE_CACHE : READ_CACHE),
0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
@@ -5196,7 +5200,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
close_on_error= TRUE;
my_printf_error(ER_ERROR_ON_WRITE,
ER_THD_OR_DEFAULT(current_thd, ER_CANT_OPEN_FILE),
- MYF(ME_FATALERROR), name, errno);
+ MYF(ME_FATAL), name, errno);
goto end;
}
bytes_written += r.data_written;
@@ -5265,7 +5269,7 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
/* handle reopening errors */
if (unlikely(error))
{
- my_error(ER_CANT_OPEN_FILE, MYF(ME_FATALERROR), file_to_open, error);
+ my_error(ER_CANT_OPEN_FILE, MYF(ME_FATAL), file_to_open, error);
close_on_error= TRUE;
}
@@ -7748,10 +7752,10 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
switch (entry->error)
{
case ER_ERROR_ON_WRITE:
- my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, entry->commit_errno);
+ my_error(ER_ERROR_ON_WRITE, MYF(ME_ERROR_LOG), name, entry->commit_errno);
break;
case ER_ERROR_ON_READ:
- my_error(ER_ERROR_ON_READ, MYF(ME_NOREFRESH),
+ my_error(ER_ERROR_ON_READ, MYF(ME_ERROR_LOG),
entry->error_cache->file_name, entry->commit_errno);
break;
default:
@@ -7762,7 +7766,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
*/
my_printf_error(entry->error,
"Error writing transaction to binary log: %d",
- MYF(ME_NOREFRESH), entry->error);
+ MYF(ME_ERROR_LOG), entry->error);
}
/*
@@ -7985,7 +7989,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
when the transaction has been safely committed in the engine.
*/
leader->cache_mngr->delayed_error= true;
- my_error(ER_ERROR_ON_WRITE, MYF(ME_NOREFRESH), name, errno);
+ my_error(ER_ERROR_ON_WRITE, MYF(ME_ERROR_LOG), name, errno);
check_purge= false;
}
/* In case of binlog rotate, update the correct current binlog offset. */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c550adea26b..13690a8be60 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2732,9 +2732,7 @@ log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
goto return_null;
uint bin_size= my_decimal_get_binary_size(precision, decimals);
- my_decimal dec;
- binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) ptr, &dec,
- precision, decimals);
+ my_decimal dec((const uchar *) ptr, precision, decimals);
int length= DECIMAL_MAX_STR_LENGTH;
char buff[DECIMAL_MAX_STR_LENGTH + 1];
decimal2string(&dec, buff, &length, 0, 0, 0);
@@ -4390,7 +4388,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t que
have to use the transactional cache to ensure we don't
calculate any checksum for the CREATE part.
*/
- trx_cache= (lex->select_lex.item_list.elements &&
+ trx_cache= (lex->first_select_lex()->item_list.elements &&
thd->is_current_stmt_binlog_format_row()) ||
(thd->variables.option_bits & OPTION_GTID_BEGIN);
use_cache= (lex->tmp_table() &&
@@ -7382,8 +7380,9 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
ex.skip_lines = skip_lines;
List<Item> field_list;
- thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
- set_fields(tables.db.str, field_list, &thd->lex->select_lex.context);
+ thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
+ set_fields(tables.db.str,
+ field_list, &thd->lex->first_select_lex()->context);
thd->variables.pseudo_thread_id= thread_id;
if (net)
{
@@ -9037,11 +9036,8 @@ void User_var_log_event::pack_info(Protocol* protocol)
String buf(buf_mem, sizeof(buf_mem), system_charset_info);
char buf2[DECIMAL_MAX_STR_LENGTH+1];
String str(buf2, sizeof(buf2), &my_charset_bin);
- my_decimal dec;
buf.length(0);
- binary2my_decimal(E_DEC_FATAL_ERROR, (uchar*) (val+2), &dec, val[0],
- val[1]);
- my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
+ my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
buf.append(buf2))
return;
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index 338f78d8f08..de7018c53cb 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -20,6 +20,7 @@
#ifndef MYSQL_CLIENT
#include "sql_class.h" // THD
+#include "field.h"
#endif
#define DIG_BASE 1000000000
@@ -95,9 +96,8 @@ int decimal_operation_results(int result, const char *value, const char *type)
@retval E_DEC_OOM
*/
-int my_decimal2string(uint mask, const my_decimal *d,
- uint fixed_prec, uint fixed_dec,
- char filler, String *str)
+int my_decimal::to_string_native(String *str, uint fixed_prec, uint fixed_dec,
+ char filler, uint mask) const
{
/*
Calculate the size of the string: For DECIMAL(a,b), fixed_prec==a
@@ -113,11 +113,11 @@ int my_decimal2string(uint mask, const my_decimal *d,
*/
int length= (fixed_prec
? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
- : my_decimal_string_length(d));
+ : my_decimal_string_length(this));
int result;
if (str->alloc(length))
return check_result(mask, E_DEC_OOM);
- result= decimal2string((decimal_t*) d, (char*) str->ptr(),
+ result= decimal2string(this, (char*) str->ptr(),
&length, (int)fixed_prec, fixed_dec,
filler);
str->length(length);
@@ -156,8 +156,8 @@ str_set_decimal(uint mask, const my_decimal *val,
{
if (!(cs->state & MY_CS_NONASCII))
{
- /* For ASCII-compatible character sets we can use my_decimal2string */
- my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, str);
+ // For ASCII-compatible character sets we can use to_string_native()
+ val->to_string_native(str, fixed_prec, fixed_dec, filler, mask);
str->set_charset(cs);
return FALSE;
}
@@ -165,14 +165,13 @@ str_set_decimal(uint mask, const my_decimal *val,
{
/*
For ASCII-incompatible character sets (like UCS2) we
- call my_decimal2string() on a temporary buffer first,
+ call my_string_native() on a temporary buffer first,
and then convert the result to the target character
with help of str->copy().
*/
uint errors;
- char buf[DECIMAL_MAX_STR_LENGTH];
- String tmp(buf, sizeof(buf), &my_charset_latin1);
- my_decimal2string(mask, val, fixed_prec, fixed_dec, filler, &tmp);
+ StringBuffer<DECIMAL_MAX_STR_LENGTH> tmp;
+ val->to_string_native(&tmp, fixed_prec, fixed_dec, filler, mask);
return str->copy(tmp.ptr(), tmp.length(), &my_charset_latin1, cs, &errors);
}
}
@@ -182,7 +181,7 @@ str_set_decimal(uint mask, const my_decimal *val,
Convert from decimal to binary representation
SYNOPSIS
- my_decimal2binary()
+ to_binary()
mask error processing mask
d number for conversion
bin pointer to buffer where to write result
@@ -199,12 +198,11 @@ str_set_decimal(uint mask, const my_decimal *val,
E_DEC_OVERFLOW
*/
-int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
- int scale)
+int my_decimal::to_binary(uchar *bin, int prec, int scale, uint mask) const
{
int err1= E_DEC_OK, err2;
my_decimal rounded;
- my_decimal2decimal(d, &rounded);
+ my_decimal2decimal(this, &rounded);
rounded.frac= decimal_actual_fraction(&rounded);
if (scale < rounded.frac)
{
@@ -368,6 +366,26 @@ int my_decimal2int(uint mask, const decimal_t *d, bool unsigned_flag,
}
+longlong my_decimal::to_longlong(bool unsigned_flag) const
+{
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, this, unsigned_flag, &result);
+ return result;
+}
+
+
+my_decimal::my_decimal(Field *field)
+{
+ init();
+ DBUG_ASSERT(!field->is_null());
+#ifndef DBUG_OFF
+ my_decimal *dec=
+#endif
+ field->val_decimal(this);
+ DBUG_ASSERT(dec == this);
+}
+
+
#ifndef DBUG_OFF
/* routines for debugging print */
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 22800c24338..d035641cfa6 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -39,6 +39,7 @@ C_MODE_START
C_MODE_END
class String;
+class Field;
typedef struct st_mysql_time MYSQL_TIME;
/**
@@ -63,6 +64,25 @@ inline int my_decimal_int_part(uint precision, uint decimals)
}
+#ifndef MYSQL_CLIENT
+int decimal_operation_results(int result, const char *value, const char *type);
+#else
+inline int decimal_operation_results(int result, const char *value,
+ const char *type)
+{
+ return result;
+}
+#endif /*MYSQL_CLIENT*/
+
+
+inline int check_result(uint mask, int result)
+{
+ if (result & mask)
+ decimal_operation_results(result, "", "DECIMAL");
+ return result;
+}
+
+
/**
my_decimal class limits 'decimal_t' type to what we need in MySQL.
@@ -125,6 +145,12 @@ public:
{
init();
}
+ my_decimal(const uchar *bin, int prec, int scale)
+ {
+ init();
+ check_result(E_DEC_FATAL_ERROR, bin2decimal(bin, this, prec, scale));
+ }
+ my_decimal(Field *field);
~my_decimal()
{
sanity_check();
@@ -141,7 +167,59 @@ public:
bool sign() const { return decimal_t::sign; }
void sign(bool s) { decimal_t::sign= s; }
uint precision() const { return intg + frac; }
+ void set_zero()
+ {
+ /*
+ We need the up-cast here, since my_decimal has sign() member functions,
+ which conflicts with decimal_t::sign
+ (and decimal_make_zero is a macro, rather than a funcion).
+ */
+ decimal_make_zero(static_cast<decimal_t*>(this));
+ }
+ int cmp(const my_decimal *other) const
+ {
+ return decimal_cmp(this, other);
+ }
+#ifndef MYSQL_CLIENT
+ bool to_bool() const
+ {
+ return !decimal_is_zero(this);
+ }
+ double to_double() const
+ {
+ double res;
+ decimal2double(this, &res);
+ return res;
+ }
+ longlong to_longlong(bool unsigned_flag) const;
+ // Convert to string returning decimal2string() error code
+ int to_string_native(String *to, uint prec, uint dec, char filler,
+ uint mask= E_DEC_FATAL_ERROR) const;
+ // Convert to string returning the String pointer
+ String *to_string(String *to, uint prec, uint dec, char filler) const
+ {
+ return to_string_native(to, prec, dec, filler) ? NULL : to;
+ }
+ String *to_string(String *to) const
+ {
+ return to_string(to, 0, 0, 0);
+ }
+ String *to_string_round(String *to, uint scale, my_decimal *round_buff) const
+ {
+ (void) round_to(round_buff, scale, HALF_UP); // QQ: check result?
+ return round_buff->to_string(to);
+ }
+ int round_to(my_decimal *to, uint scale, decimal_round_mode mode,
+ int mask= E_DEC_FATAL_ERROR) const
+ {
+ return check_result(mask, decimal_round(this, to, (int) scale, mode));
+ }
+ bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const char *field_name);
+ int to_binary(uchar *bin, int prec, int scale,
+ uint mask= E_DEC_FATAL_ERROR) const;
+#endif
/** Swap two my_decimal values */
void swap(my_decimal &rhs)
{
@@ -164,16 +242,6 @@ bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec,
extern my_decimal decimal_zero;
-#ifndef MYSQL_CLIENT
-int decimal_operation_results(int result, const char *value, const char *type);
-#else
-inline int decimal_operation_results(int result, const char *value,
- const char *type)
-{
- return result;
-}
-#endif /*MYSQL_CLIENT*/
-
inline
void max_my_decimal(my_decimal *to, int precision, int frac)
{
@@ -187,13 +255,6 @@ inline void max_internal_decimal(my_decimal *to)
max_my_decimal(to, DECIMAL_MAX_PRECISION, 0);
}
-inline int check_result(uint mask, int result)
-{
- if (result & mask)
- decimal_operation_results(result, "", "DECIMAL");
- return result;
-}
-
inline int check_result_and_overflow(uint mask, int result, my_decimal *val)
{
if (check_result(mask, result) & E_DEC_OVERFLOW)
@@ -271,10 +332,6 @@ void my_decimal2decimal(const my_decimal *from, my_decimal *to)
}
-int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec,
- int scale);
-
-
inline
int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
int scale)
@@ -286,12 +343,7 @@ int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec,
inline
int my_decimal_set_zero(my_decimal *d)
{
- /*
- We need the up-cast here, since my_decimal has sign() member functions,
- which conflicts with decimal_t::sign
- (and decimal_make_zero is a macro, rather than a funcion).
- */
- decimal_make_zero(static_cast<decimal_t*>(d));
+ d->set_zero();
return 0;
}
@@ -303,40 +355,12 @@ bool my_decimal_is_zero(const my_decimal *decimal_value)
}
-inline
-int my_decimal_round(uint mask, const my_decimal *from, int scale,
- bool truncate, my_decimal *to)
-{
- return check_result(mask, decimal_round(from, to, scale,
- (truncate ? TRUNCATE : HALF_UP)));
-}
-
-
-inline
-int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
-{
- return check_result(mask, decimal_round(from, to, 0, FLOOR));
-}
-
-
-inline
-int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
-{
- return check_result(mask, decimal_round(from, to, 0, CEILING));
-}
-
-
inline bool str_set_decimal(const my_decimal *val, String *str,
CHARSET_INFO *cs)
{
return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs);
}
-#ifndef MYSQL_CLIENT
-class String;
-int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
- uint fixed_dec, char filler, String *str);
-#endif
bool my_decimal2seconds(const my_decimal *d, ulonglong *sec, ulong *microsec);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f2b00831d6f..acb7532f922 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -319,22 +319,15 @@ MY_TIMER_INFO sys_timer_info;
/* static variables */
#ifdef HAVE_PSI_INTERFACE
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY)
static PSI_thread_key key_thread_handle_con_namedpipes;
static PSI_cond_key key_COND_handler_count;
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
-static PSI_thread_key key_thread_handle_con_sharedmem;
-#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
static PSI_thread_key key_thread_handle_con_sockets;
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+#endif /* _WIN32 |&& !EMBEDDED_LIBRARY */
-#ifdef __WIN__
+#ifdef _WIN32
static PSI_thread_key key_thread_handle_shutdown;
-#endif /* __WIN__ */
+#endif
#ifdef HAVE_OPENSSL10
static PSI_rwlock_key key_rwlock_openssl;
@@ -1098,9 +1091,9 @@ PSI_cond_key key_COND_ack_receiver;
static PSI_cond_info all_server_conds[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+#if defined(_WIN32) && !defined(EMBEDDED_LIBRARY)
{ &key_COND_handler_count, "COND_handler_count", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
+#endif /* _WIN32 && !EMBEDDED_LIBRARY */
#ifdef HAVE_MMAP
{ &key_PAGE_cond, "PAGE::cond", 0},
{ &key_COND_active, "TC_LOG_MMAP::COND_active", 0},
@@ -1161,21 +1154,11 @@ PSI_thread_key key_thread_ack_receiver;
static PSI_thread_info all_server_threads[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
+#if (defined (_WIN32) && !defined (EMBEDDED_LIBRARY))
{ &key_thread_handle_con_namedpipes, "con_named_pipes", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if defined(HAVE_SMEM) && !defined(EMBEDDED_LIBRARY)
- { &key_thread_handle_con_sharedmem, "con_shared_mem", PSI_FLAG_GLOBAL},
-#endif /* HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
{ &key_thread_handle_con_sockets, "con_sockets", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
-
-#ifdef __WIN__
{ &key_thread_handle_shutdown, "shutdown", PSI_FLAG_GLOBAL},
-#endif /* __WIN__ */
+#endif
{ &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL},
{ &key_thread_delayed_insert, "delayed_insert", 0},
@@ -1519,11 +1502,7 @@ int deny_severity = LOG_WARNING;
ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
-#ifdef HAVE_SMEM
-const char *shared_memory_base_name= default_shared_memory_base_name;
-my_bool opt_enable_shared_memory;
-HANDLE smem_event_connect_request= 0;
-#endif
+
my_bool opt_use_ssl = 0;
char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL,
@@ -1585,9 +1564,6 @@ static bool read_init_file(char *file_name);
#ifdef _WIN32
pthread_handler_t handle_connections_namedpipes(void *arg);
#endif
-#ifdef HAVE_SMEM
-pthread_handler_t handle_connections_shared_memory(void *arg);
-#endif
pthread_handler_t handle_slave(void *arg);
static void clean_up(bool print_message);
static int test_if_case_insensitive(const char *dir_name);
@@ -2011,21 +1987,6 @@ static void __cdecl kill_server(int sig_ptr)
else
sql_print_error(ER_DEFAULT(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
-#ifdef HAVE_SMEM
- /*
- Send event to smem_event_connect_request for aborting
- */
- if (opt_enable_shared_memory)
- {
- if (!SetEvent(smem_event_connect_request))
- {
- DBUG_PRINT("error",
- ("Got error: %ld from SetEvent of smem_event_connect_request",
- GetLastError()));
- }
- }
-#endif
-
/* Stop wsrep threads in case they are running. */
if (wsrep_running_threads > 0)
{
@@ -2786,9 +2747,10 @@ static void network_init(void)
*/
if (mysqld_unix_port[0] && !opt_bootstrap)
{
+ size_t port_len;
DBUG_PRINT("general",("UNIX Socket is %s",mysqld_unix_port));
- if (strlen(mysqld_unix_port) > (sizeof(UNIXaddr.sun_path) - 1))
+ if ((port_len= strlen(mysqld_unix_port)) > sizeof(UNIXaddr.sun_path) - 1)
{
sql_print_error("The socket file path is too long (> %u): %s",
(uint) sizeof(UNIXaddr.sun_path) - 1, mysqld_unix_port);
@@ -2806,14 +2768,26 @@ static void network_init(void)
bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, mysqld_unix_port);
- (void) unlink(mysqld_unix_port);
+#if defined(__linux__)
+ /* Abstract socket */
+ if (mysqld_unix_port[0] == '@')
+ {
+ UNIXaddr.sun_path[0]= '\0';
+ port_len+= offsetof(struct sockaddr_un, sun_path);
+ }
+ else
+#endif
+ {
+ (void) unlink(mysqld_unix_port);
+ port_len= sizeof(UNIXaddr);
+ }
arg= 1;
(void) mysql_socket_setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,
(char*)&arg, sizeof(arg));
umask(0);
if (mysql_socket_bind(unix_sock,
reinterpret_cast<struct sockaddr *>(&UNIXaddr),
- sizeof(UNIXaddr)) < 0)
+ port_len) < 0)
{
sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */
sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysqld_unix_port);
@@ -3647,7 +3621,7 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
void my_message_sql(uint error, const char *str, myf MyFlags)
{
- THD *thd= current_thd;
+ THD *thd= MyFlags & ME_ERROR_LOG_ONLY ? NULL : current_thd;
Sql_condition::enum_warning_level level;
sql_print_message_func func;
DBUG_ENTER("my_message_sql");
@@ -3656,13 +3630,15 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
DBUG_ASSERT(str != NULL);
DBUG_ASSERT(error != 0);
+ DBUG_ASSERT((MyFlags & ~(ME_BELL | ME_ERROR_LOG | ME_ERROR_LOG_ONLY |
+ ME_NOTE | ME_WARNING | ME_FATAL)) == 0);
- if (MyFlags & ME_JUST_INFO)
+ if (MyFlags & ME_NOTE)
{
level= Sql_condition::WARN_LEVEL_NOTE;
func= sql_print_information;
}
- else if (MyFlags & ME_JUST_WARNING)
+ else if (MyFlags & ME_WARNING)
{
level= Sql_condition::WARN_LEVEL_WARN;
func= sql_print_warning;
@@ -3675,7 +3651,7 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
if (likely(thd))
{
- if (unlikely(MyFlags & ME_FATALERROR))
+ if (unlikely(MyFlags & ME_FATAL))
thd->is_fatal_error= 1;
(void) thd->raise_condition(error, NULL, level, str);
}
@@ -3685,7 +3661,7 @@ void my_message_sql(uint error, const char *str, myf MyFlags)
/* When simulating OOM, skip writing to error log to avoid mtr errors */
DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_VOID_RETURN;);
- if (unlikely(!thd) || thd->log_all_errors || (MyFlags & ME_NOREFRESH))
+ if (unlikely(!thd) || thd->log_all_errors || (MyFlags & ME_ERROR_LOG))
(*func)("%s: %s", my_progname_short, str); /* purecov: inspected */
DBUG_VOID_RETURN;
}
@@ -5613,7 +5589,7 @@ static int init_server_components()
#ifndef EMBEDDED_LIBRARY
-
+#ifdef _WIN32
static void create_shutdown_thread()
{
#ifdef __WIN__
@@ -5631,19 +5607,14 @@ static void create_shutdown_thread()
#endif /* __WIN__ */
}
-#endif /* EMBEDDED_LIBRARY */
-
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
static void handle_connections_methods()
{
pthread_t hThread;
int error;
DBUG_ENTER("handle_connections_methods");
- if (hPipe == INVALID_HANDLE_VALUE &&
- (!have_tcpip || opt_disable_networking) &&
- !opt_enable_shared_memory)
+ if (hPipe == INVALID_HANDLE_VALUE && opt_disable_networking)
{
- sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS");
+ sql_print_error("TCP/IP, or --named-pipe should be configured on Windows");
unireg_abort(1); // Will not return
}
@@ -5674,20 +5645,6 @@ static void handle_connections_methods()
handler_count--;
}
}
-#ifdef HAVE_SMEM
- if (opt_enable_shared_memory)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_sharedmem,
- &hThread, &connection_attrib,
- handle_connections_shared_memory, 0)))
- {
- sql_print_warning("Can't create thread to handle shared memory",
- " (errno= %d)", error);
- handler_count--;
- }
- }
-#endif
while (handler_count > 0)
mysql_cond_wait(&COND_handler_count, &LOCK_start_thread);
@@ -5703,10 +5660,11 @@ void decrement_handler_count()
mysql_mutex_unlock(&LOCK_start_thread);
my_thread_end();
}
-#else
+#else /* WIN32*/
+#define create_shutdown_thread()
#define decrement_handler_count()
-#endif /* defined(_WIN32) || defined(HAVE_SMEM) */
-
+#endif
+#endif /* EMBEDDED_LIBRARY */
#ifndef EMBEDDED_LIBRARY
@@ -6178,11 +6136,11 @@ int mysqld_main(int argc, char **argv)
/* Memory used when everything is setup */
start_memory_used= global_status_var.global_memory_used;
-#if defined(_WIN32) || defined(HAVE_SMEM)
+#ifdef _WIN32
handle_connections_methods();
#else
handle_connections_sockets();
-#endif /* _WIN32 || HAVE_SMEM */
+#endif /* _WIN32 */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -7014,250 +6972,6 @@ pthread_handler_t handle_connections_namedpipes(void *arg)
}
#endif /* _WIN32 */
-
-#ifdef HAVE_SMEM
-
-/**
- Thread of shared memory's service.
-
- @param arg Arguments of thread
-*/
-pthread_handler_t handle_connections_shared_memory(void *arg)
-{
- /* file-mapping object, use for create shared memory */
- HANDLE handle_connect_file_map= 0;
- char *handle_connect_map= 0; // pointer on shared memory
- HANDLE event_connect_answer= 0;
- ulong smem_buffer_length= shared_memory_buffer_length + 4;
- ulong connect_number= 1;
- char *tmp= NULL;
- char *suffix_pos;
- char connect_number_char[22], *p;
- const char *errmsg= 0;
- SECURITY_ATTRIBUTES *sa_event= 0, *sa_mapping= 0;
- my_thread_init();
- DBUG_ENTER("handle_connections_shared_memorys");
- DBUG_PRINT("general",("Waiting for allocated shared memory."));
-
- /*
- get enough space base-name + '_' + longest suffix we might ever send
- */
- if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L,
- MYF(MY_FAE))))
- goto error;
-
- if (my_security_attr_create(&sa_event, &errmsg,
- GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
- goto error;
-
- if (my_security_attr_create(&sa_mapping, &errmsg,
- GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
- goto error;
-
- /*
- The name of event and file-mapping events create agree next rule:
- shared_memory_base_name+unique_part
- Where:
- shared_memory_base_name is unique value for each server
- unique_part is unique value for each object (events and file-mapping)
- */
- suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS);
- strmov(suffix_pos, "CONNECT_REQUEST");
- if ((smem_event_connect_request= CreateEvent(sa_event,
- FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create request event";
- goto error;
- }
- strmov(suffix_pos, "CONNECT_ANSWER");
- if ((event_connect_answer= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg="Could not create answer event";
- goto error;
- }
- strmov(suffix_pos, "CONNECT_DATA");
- if ((handle_connect_file_map=
- CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
- PAGE_READWRITE, 0, sizeof(connect_number), tmp)) == 0)
- {
- errmsg= "Could not create file mapping";
- goto error;
- }
- if ((handle_connect_map= (char *)MapViewOfFile(handle_connect_file_map,
- FILE_MAP_WRITE,0,0,
- sizeof(DWORD))) == 0)
- {
- errmsg= "Could not create shared memory service";
- goto error;
- }
-
- while (!abort_loop)
- {
- /* Wait a request from client */
- WaitForSingleObject(smem_event_connect_request,INFINITE);
-
- /*
- it can be after shutdown command
- */
- if (abort_loop)
- goto error;
-
- HANDLE handle_client_file_map= 0;
- char *handle_client_map= 0;
- HANDLE event_client_wrote= 0;
- HANDLE event_client_read= 0; // for transfer data server <-> client
- HANDLE event_server_wrote= 0;
- HANDLE event_server_read= 0;
- HANDLE event_conn_closed= 0;
- CONNECT *connect= 0;
-
- p= int10_to_str(connect_number, connect_number_char, 10);
- /*
- The name of event and file-mapping events create agree next rule:
- shared_memory_base_name+unique_part+number_of_connection
- Where:
- shared_memory_base_name is uniquel value for each server
- unique_part is unique value for each object (events and file-mapping)
- number_of_connection is connection-number between server and client
- */
- suffix_pos= strxmov(tmp,shared_memory_base_name,"_",connect_number_char,
- "_",NullS);
- strmov(suffix_pos, "DATA");
- if ((handle_client_file_map=
- CreateFileMapping(INVALID_HANDLE_VALUE, sa_mapping,
- PAGE_READWRITE, 0, smem_buffer_length, tmp)) == 0)
- {
- errmsg= "Could not create file mapping";
- goto errorconn;
- }
- if ((handle_client_map= (char*)MapViewOfFile(handle_client_file_map,
- FILE_MAP_WRITE,0,0,
- smem_buffer_length)) == 0)
- {
- errmsg= "Could not create memory map";
- goto errorconn;
- }
- strmov(suffix_pos, "CLIENT_WROTE");
- if ((event_client_wrote= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create client write event";
- goto errorconn;
- }
- strmov(suffix_pos, "CLIENT_READ");
- if ((event_client_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create client read event";
- goto errorconn;
- }
- strmov(suffix_pos, "SERVER_READ");
- if ((event_server_read= CreateEvent(sa_event, FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create server read event";
- goto errorconn;
- }
- strmov(suffix_pos, "SERVER_WROTE");
- if ((event_server_wrote= CreateEvent(sa_event,
- FALSE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create server write event";
- goto errorconn;
- }
- strmov(suffix_pos, "CONNECTION_CLOSED");
- if ((event_conn_closed= CreateEvent(sa_event,
- TRUE, FALSE, tmp)) == 0)
- {
- errmsg= "Could not create closed connection event";
- goto errorconn;
- }
- if (abort_loop)
- goto errorconn;
-
- if (!(connect= new CONNECT))
- {
- errmsg= "Could not create CONNECT object";
- goto errorconn;
- }
-
- /* Send number of connection to client */
- int4store(handle_connect_map, connect_number);
- if (!SetEvent(event_connect_answer))
- {
- errmsg= "Could not send answer event";
- goto errorconn;
- }
- /* Set event that client should receive data */
- if (!SetEvent(event_client_read))
- {
- errmsg= "Could not set client to read mode";
- goto errorconn;
- }
- if (!(connect->vio= vio_new_win32shared_memory(handle_client_file_map,
- handle_client_map,
- event_client_wrote,
- event_client_read,
- event_server_wrote,
- event_server_read,
- event_conn_closed)))
- {
- errmsg= "Could not create VIO object";
- goto errorconn;
- }
- connect->host= my_localhost; /* Host is unknown */
- create_new_thread(connect);
- connect_number++;
- continue;
-
-errorconn:
- /* Could not form connection; Free used handlers/memort and retry */
- if (errmsg)
- {
- char buff[180];
- strxmov(buff, "Can't create shared memory connection: ", errmsg, ".",
- NullS);
- sql_perror(buff);
- }
- if (handle_client_file_map)
- CloseHandle(handle_client_file_map);
- if (handle_client_map)
- UnmapViewOfFile(handle_client_map);
- if (event_server_wrote)
- CloseHandle(event_server_wrote);
- if (event_server_read)
- CloseHandle(event_server_read);
- if (event_client_wrote)
- CloseHandle(event_client_wrote);
- if (event_client_read)
- CloseHandle(event_client_read);
- if (event_conn_closed)
- CloseHandle(event_conn_closed);
-
- delete connect;
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- }
-
- /* End shared memory handling */
-error:
- if (tmp)
- my_free(tmp);
-
- if (errmsg)
- {
- char buff[180];
- strxmov(buff, "Can't create shared memory service: ", errmsg, ".", NullS);
- sql_perror(buff);
- }
- my_security_attr_free(sa_event);
- my_security_attr_free(sa_mapping);
- if (handle_connect_map) UnmapViewOfFile(handle_connect_map);
- if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
- if (event_connect_answer) CloseHandle(event_connect_answer);
- if (smem_event_connect_request) CloseHandle(smem_event_connect_request);
- DBUG_LEAVE;
- decrement_handler_count();
- return 0;
-}
-#endif /* HAVE_SMEM */
#endif /* EMBEDDED_LIBRARY */
@@ -9061,9 +8775,6 @@ static int mysql_init_variables(void)
ssl_acceptor_fd= 0;
#endif /* ! EMBEDDED_LIBRARY */
#endif /* HAVE_OPENSSL */
-#ifdef HAVE_SMEM
- shared_memory_base_name= default_shared_memory_base_name;
-#endif
#if defined(__WIN__)
/* Allow Win32 users to move MySQL anywhere */
@@ -9806,10 +9517,10 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
errors.
*/
if (global_system_variables.log_warnings >= 10)
- my_global_flags= MY_WME | ME_JUST_INFO;
+ my_global_flags= MY_WME | ME_NOTE;
/* Log all errors not handled by thd->handle_error() to my_message_sql() */
if (global_system_variables.log_warnings >= 11)
- my_global_flags|= ME_NOREFRESH;
+ my_global_flags|= ME_ERROR_LOG;
if (my_assert_on_error)
debug_assert_if_crashed_table= 1;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0b29fcd2f11..7faae008dab 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1479,7 +1479,6 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler,
{
handler *save_file= file, *org_file;
THD *thd= head->in_use;
- MY_BITMAP * const save_vcol_set= head->vcol_set;
MY_BITMAP * const save_read_set= head->read_set;
MY_BITMAP * const save_write_set= head->write_set;
DBUG_ENTER("QUICK_RANGE_SELECT::init_ror_merged_scan");
@@ -1537,14 +1536,14 @@ end:
org_file= head->file;
head->file= file;
- head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap, &column_bitmap);
+ head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap);
head->prepare_for_keyread(index, &column_bitmap);
head->prepare_for_position();
head->file= org_file;
/* Restore head->read_set (and write_set) to what they had before the call */
- head->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ head->column_bitmaps_set(save_read_set, save_write_set);
if (reset())
{
@@ -1559,7 +1558,7 @@ end:
DBUG_RETURN(0);
failure:
- head->column_bitmaps_set(save_read_set, save_write_set, save_vcol_set);
+ head->column_bitmaps_set(save_read_set, save_write_set);
delete file;
file= save_file;
DBUG_RETURN(1);
@@ -1893,6 +1892,118 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 part_,
left=right= &null_element;
}
+
+/*
+ A number of helper classes:
+ SEL_ARG_LE, SEL_ARG_LT, SEL_ARG_GT, SEL_ARG_GE,
+ to share the code between:
+ Field::stored_field_make_mm_leaf()
+ Field::stored_field_make_mm_leaf_exact()
+*/
+class SEL_ARG_LE: public SEL_ARG
+{
+public:
+ SEL_ARG_LE(const uchar *key, Field *field)
+ :SEL_ARG(field, key, key)
+ {
+ if (!field->real_maybe_null())
+ min_flag= NO_MIN_RANGE; // From start
+ else
+ {
+ min_value= is_null_string;
+ min_flag= NEAR_MIN; // > NULL
+ }
+ }
+};
+
+
+class SEL_ARG_LT: public SEL_ARG_LE
+{
+public:
+ /*
+ Use this constructor if value->save_in_field() went precisely,
+ without any data rounding or truncation.
+ */
+ SEL_ARG_LT(const uchar *key, Field *field)
+ :SEL_ARG_LE(key, field)
+ { max_flag= NEAR_MAX; }
+ /*
+ Use this constructor if value->save_in_field() returned success,
+ but we don't know if rounding or truncation happened
+ (as some Field::store() do not report minor data changes).
+ */
+ SEL_ARG_LT(THD *thd, const uchar *key, Field *field, Item *value)
+ :SEL_ARG_LE(key, field)
+ {
+ if (stored_field_cmp_to_item(thd, field, value) == 0)
+ max_flag= NEAR_MAX;
+ }
+};
+
+
+class SEL_ARG_GT: public SEL_ARG
+{
+public:
+ /*
+ Use this constructor if value->save_in_field() went precisely,
+ without any data rounding or truncation.
+ */
+ SEL_ARG_GT(const uchar *key, const KEY_PART *key_part, Field *field)
+ :SEL_ARG(field, key, key)
+ {
+ // Don't use open ranges for partial key_segments
+ if (!(key_part->flag & HA_PART_KEY_SEG))
+ min_flag= NEAR_MIN;
+ max_flag= NO_MAX_RANGE;
+ }
+ /*
+ Use this constructor if value->save_in_field() returned success,
+ but we don't know if rounding or truncation happened
+ (as some Field::store() do not report minor data changes).
+ */
+ SEL_ARG_GT(THD *thd, const uchar *key,
+ const KEY_PART *key_part, Field *field, Item *value)
+ :SEL_ARG(field, key, key)
+ {
+ // Don't use open ranges for partial key_segments
+ if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
+ (stored_field_cmp_to_item(thd, field, value) <= 0))
+ min_flag= NEAR_MIN;
+ max_flag= NO_MAX_RANGE;
+ }
+};
+
+
+class SEL_ARG_GE: public SEL_ARG
+{
+public:
+ /*
+ Use this constructor if value->save_in_field() went precisely,
+ without any data rounding or truncation.
+ */
+ SEL_ARG_GE(const uchar *key, Field *field)
+ :SEL_ARG(field, key, key)
+ {
+ max_flag= NO_MAX_RANGE;
+ }
+ /*
+ Use this constructor if value->save_in_field() returned success,
+ but we don't know if rounding or truncation happened
+ (as some Field::store() do not report minor data changes).
+ */
+ SEL_ARG_GE(THD *thd, const uchar *key,
+ const KEY_PART *key_part, Field *field, Item *value)
+ :SEL_ARG(field, key, key)
+ {
+ // Don't use open ranges for partial key_segments
+ if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
+ (stored_field_cmp_to_item(thd, field, value) < 0))
+ min_flag= NEAR_MIN;
+ max_flag= NO_MAX_RANGE;
+ }
+};
+
+
SEL_ARG *SEL_ARG::clone(RANGE_OPT_PARAM *param, SEL_ARG *new_parent,
SEL_ARG **next_arg)
{
@@ -4544,7 +4655,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
if (max_cost != DBL_MAX && (busy_blocks+index_reads_cost) >= n_blocks)
return 1;
*/
- JOIN *join= param->thd->lex->select_lex.join;
+ JOIN *join= param->thd->lex->first_select_lex()->join;
if (!join || join->table_count == 1)
{
/* No join, assume reading is done in one 'sweep' */
@@ -8015,52 +8126,112 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PARAM *param,
SEL_ARG *
Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
Field *field, KEY_PART *key_part,
- Item_func::Functype type, Item *value)
+ Item_func::Functype functype, Item *value)
{
- uint maybe_null=(uint) field->real_maybe_null();
- SEL_ARG *tree= 0;
- MEM_ROOT *alloc= param->mem_root;
- uchar *str;
- int err;
DBUG_ENTER("Item_bool_func::get_mm_leaf");
-
DBUG_ASSERT(value); // IS NULL and IS NOT NULL are handled separately
-
if (key_part->image_type != Field::itRAW)
DBUG_RETURN(0); // e.g. SPATIAL index
+ DBUG_RETURN(field->get_mm_leaf(param, key_part, this,
+ functype_to_scalar_comparison_op(functype),
+ value));
+}
- if (param->using_real_indexes &&
- !field->optimize_range(param->real_keynr[key_part->key],
- key_part->part) &&
- type != EQ_FUNC &&
- type != EQUAL_FUNC)
- goto end; // Can't optimize this
- if (!field->can_optimize_range(this, value,
- type == EQUAL_FUNC || type == EQ_FUNC))
- goto end;
+bool Field::can_optimize_scalar_range(const RANGE_OPT_PARAM *param,
+ const KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op,
+ const Item *value) const
+{
+ bool is_eq_func= op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL;
+ if ((param->using_real_indexes &&
+ !optimize_range(param->real_keynr[key_part->key],
+ key_part->part) && !is_eq_func) ||
+ !can_optimize_range(cond, value, is_eq_func))
+ return false;
+ return true;
+}
+
+
+uchar *Field::make_key_image(MEM_ROOT *mem_root, const KEY_PART *key_part)
+{
+ DBUG_ENTER("Field::make_key_image");
+ uint maybe_null= (uint) real_maybe_null();
+ uchar *str;
+ if (!(str= (uchar*) alloc_root(mem_root, key_part->store_length + 1)))
+ DBUG_RETURN(0);
+ if (maybe_null)
+ *str= (uchar) is_real_null(); // Set to 1 if null
+ get_key_image(str + maybe_null, key_part->length, key_part->image_type);
+ DBUG_RETURN(str);
+}
+
+
+SEL_ARG *Field::stored_field_make_mm_leaf_truncated(RANGE_OPT_PARAM *param,
+ scalar_comparison_op op,
+ Item *value)
+{
+ DBUG_ENTER("Field::stored_field_make_mm_leaf_truncated");
+ if ((op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) &&
+ value->result_type() == item_cmp_type(result_type(),
+ value->result_type()))
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ /*
+ TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
+ for the cases like int_field > 999999999999999999999999 as well.
+ */
+ DBUG_RETURN(0);
+}
+
- err= value->save_in_field_no_warnings(field, 1);
+SEL_ARG *Field_num::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)
+{
+ DBUG_ENTER("Field_num::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0 && cmp_type() != value->result_type())
+ DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+}
+
+
+SEL_ARG *Field_temporal::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)
+{
+ DBUG_ENTER("Field_temporal::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
if (err > 0)
- {
- if (field->type_handler() == &type_handler_enum ||
- field->type_handler() == &type_handler_set)
- {
- if (type == EQ_FUNC || type == EQUAL_FUNC)
- tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
- goto end;
- }
+ DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+}
- if (err == 2 && field->cmp_type() == STRING_RESULT)
- {
- if (type == EQ_FUNC || type == EQUAL_FUNC)
- tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
- else
- tree= NULL; /* Cannot infer anything */
- goto end;
- }
- if (err == 3 && field->type() == FIELD_TYPE_DATE)
+SEL_ARG *Field_date_common::get_mm_leaf(RANGE_OPT_PARAM *prm,
+ KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op,
+ Item *value)
+{
+ DBUG_ENTER("Field_date_common::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0)
+ {
+ if (err == 3)
{
/*
We were saving DATETIME into a DATE column, the conversion went ok
@@ -8080,76 +8251,86 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
be done together with other types at the end of this function
(grep for stored_field_cmp_to_item)
*/
- if (type == EQ_FUNC || type == EQUAL_FUNC)
- {
- tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
- goto end;
- }
- // Continue with processing non-equality ranges
- }
- else if (field->cmp_type() != value->result_type())
- {
- if ((type == EQ_FUNC || type == EQUAL_FUNC) &&
- value->result_type() == item_cmp_type(field->result_type(),
- value->result_type()))
- {
- tree= new (alloc) SEL_ARG_IMPOSSIBLE(field);
- goto end;
- }
- else
- {
- /*
- TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE
- for the cases like int_field > 999999999999999999999999 as well.
- */
- tree= 0;
- goto end;
- }
- }
-
- /*
- guaranteed at this point: err > 0; field and const of same type
- If an integer got bounded (e.g. to within 0..255 / -128..127)
- for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
- */
- else if (err == 1 && field->result_type() == INT_RESULT)
- {
- if (type == LT_FUNC && (value->val_int() > 0))
- type= LE_FUNC;
- else if (type == GT_FUNC &&
- (field->type() != FIELD_TYPE_BIT) &&
- !((Field_num*)field)->unsigned_flag &&
- !((Item_int*)value)->unsigned_flag &&
- (value->val_int() < 0))
- type= GE_FUNC;
+ if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
+ DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
}
+ DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
}
- else if (err < 0)
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+}
+
+
+SEL_ARG *Field_str::get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value)
+{
+ DBUG_ENTER("Field_str::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0)
{
- /* This happens when we try to insert a NULL field in a not null column */
- tree= &null_element; // cmp with NULL is never TRUE
- goto end;
+ if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
+ DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ DBUG_RETURN(NULL); /* Cannot infer anything */
}
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+}
- /*
- Any sargable predicate except "<=>" involving NULL as a constant is always
- FALSE
- */
- if (type != EQUAL_FUNC && field->is_real_null())
+
+SEL_ARG *Field::get_mm_leaf_int(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value,
+ bool unsigned_field)
+{
+ DBUG_ENTER("Field::get_mm_leaf_int");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0)
{
- tree= &null_element;
- goto end;
+ if (value->result_type() != INT_RESULT)
+ DBUG_RETURN(stored_field_make_mm_leaf_truncated(prm, op, value));
+ else
+ DBUG_RETURN(stored_field_make_mm_leaf_bounded_int(prm, key_part,
+ op, value,
+ unsigned_field));
}
-
- str= (uchar*) alloc_root(alloc, key_part->store_length+1);
- if (!str)
- goto end;
- if (maybe_null)
- *str= (uchar) field->is_real_null(); // Set to 1 if null
- field->get_key_image(str+maybe_null, key_part->length,
- key_part->image_type);
- if (!(tree= new (alloc) SEL_ARG(field, str, str)))
- goto end; // out of memory
+ if (value->result_type() != INT_RESULT)
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+ DBUG_RETURN(stored_field_make_mm_leaf_exact(prm, key_part, op, value));
+}
+
+
+/*
+ This method is called when:
+ - value->save_in_field_no_warnings() returned err > 0
+ - and both field and "value" are of integer data types
+ If an integer got bounded (e.g. to within 0..255 / -128..127)
+ for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN)
+*/
+
+SEL_ARG *Field::stored_field_make_mm_leaf_bounded_int(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op,
+ Item *value,
+ bool unsigned_field)
+{
+ DBUG_ENTER("Field::stored_field_make_mm_leaf_bounded_int");
+ if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL) // e.g. tinyint = 200
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ longlong item_val= value->val_int();
+
+ if (op == SCALAR_CMP_LT && item_val > 0)
+ op= SCALAR_CMP_LE; // e.g. rewrite (tinyint < 200) to (tinyint <= 127)
+ else if (op == SCALAR_CMP_GT && !unsigned_field &&
+ !value->unsigned_flag && item_val < 0)
+ op= SCALAR_CMP_GE; // e.g. rewrite (tinyint > -200) to (tinyint >= -128)
/*
Check if we are comparing an UNSIGNED integer with a negative constant.
@@ -8162,66 +8343,74 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
negative integers (which otherwise fails because at query execution time
negative integers are cast to unsigned if compared with unsigned).
*/
- if (field->result_type() == INT_RESULT &&
- value->result_type() == INT_RESULT &&
- ((field->type() == FIELD_TYPE_BIT ||
- ((Field_num *) field)->unsigned_flag) &&
- !((Item_int*) value)->unsigned_flag))
+ if (unsigned_field && !value->unsigned_flag && item_val < 0)
{
- longlong item_val= value->val_int();
- if (item_val < 0)
- {
- if (type == LT_FUNC || type == LE_FUNC)
- {
- tree->type= SEL_ARG::IMPOSSIBLE;
- goto end;
- }
- if (type == GT_FUNC || type == GE_FUNC)
- {
- tree= 0;
- goto end;
- }
- }
+ if (op == SCALAR_CMP_LT || op == SCALAR_CMP_LE) // e.g. uint < -1
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ if (op == SCALAR_CMP_GT || op == SCALAR_CMP_GE) // e.g. uint > -1
+ DBUG_RETURN(0);
}
+ DBUG_RETURN(stored_field_make_mm_leaf_exact(param, key_part, op, value));
+}
- switch (type) {
- case LT_FUNC:
- if (stored_field_cmp_to_item(param->thd, field, value) == 0)
- tree->max_flag=NEAR_MAX;
- /* fall through */
- case LE_FUNC:
- if (!maybe_null)
- tree->min_flag=NO_MIN_RANGE; /* From start */
- else
- { // > NULL
- tree->min_value=is_null_string;
- tree->min_flag=NEAR_MIN;
- }
- break;
- case GT_FUNC:
- /* Don't use open ranges for partial key_segments */
- if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
- (stored_field_cmp_to_item(param->thd, field, value) <= 0))
- tree->min_flag=NEAR_MIN;
- tree->max_flag= NO_MAX_RANGE;
- break;
- case GE_FUNC:
- /* Don't use open ranges for partial key_segments */
- if ((!(key_part->flag & HA_PART_KEY_SEG)) &&
- (stored_field_cmp_to_item(param->thd, field, value) < 0))
- tree->min_flag= NEAR_MIN;
- tree->max_flag=NO_MAX_RANGE;
- break;
- case EQ_FUNC:
- case EQUAL_FUNC:
- break;
- default:
- DBUG_ASSERT(0);
+
+SEL_ARG *Field::stored_field_make_mm_leaf(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op,
+ Item *value)
+{
+ DBUG_ENTER("Field::stored_field_make_mm_leaf");
+ THD *thd= param->thd;
+ MEM_ROOT *mem_root= param->mem_root;
+ uchar *str;
+ if (!(str= make_key_image(param->mem_root, key_part)))
+ DBUG_RETURN(0);
+
+ switch (op) {
+ case SCALAR_CMP_LE:
+ DBUG_RETURN(new (mem_root) SEL_ARG_LE(str, this));
+ case SCALAR_CMP_LT:
+ DBUG_RETURN(new (mem_root) SEL_ARG_LT(thd, str, this, value));
+ case SCALAR_CMP_GT:
+ DBUG_RETURN(new (mem_root) SEL_ARG_GT(thd, str, key_part, this, value));
+ case SCALAR_CMP_GE:
+ DBUG_RETURN(new (mem_root) SEL_ARG_GE(thd, str, key_part, this, value));
+ case SCALAR_CMP_EQ:
+ case SCALAR_CMP_EQUAL:
+ DBUG_RETURN(new (mem_root) SEL_ARG(this, str, str));
break;
}
+ DBUG_ASSERT(0);
+ DBUG_RETURN(NULL);
+}
-end:
- DBUG_RETURN(tree);
+
+SEL_ARG *Field::stored_field_make_mm_leaf_exact(RANGE_OPT_PARAM *param,
+ KEY_PART *key_part,
+ scalar_comparison_op op,
+ Item *value)
+{
+ DBUG_ENTER("Field::stored_field_make_mm_leaf_exact");
+ uchar *str;
+ if (!(str= make_key_image(param->mem_root, key_part)))
+ DBUG_RETURN(0);
+
+ switch (op) {
+ case SCALAR_CMP_LE:
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_LE(str, this));
+ case SCALAR_CMP_LT:
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_LT(str, this));
+ case SCALAR_CMP_GT:
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_GT(str, key_part, this));
+ case SCALAR_CMP_GE:
+ DBUG_RETURN(new (param->mem_root) SEL_ARG_GE(str, this));
+ case SCALAR_CMP_EQ:
+ case SCALAR_CMP_EQUAL:
+ DBUG_RETURN(new (param->mem_root) SEL_ARG(this, str, str));
+ break;
+ }
+ DBUG_ASSERT(0);
+ DBUG_RETURN(NULL);
}
@@ -11351,7 +11540,6 @@ int QUICK_RANGE_SELECT::reset()
HANDLER_BUFFER empty_buf;
MY_BITMAP * const save_read_set= head->read_set;
MY_BITMAP * const save_write_set= head->write_set;
- MY_BITMAP * const save_vcol_set= head->vcol_set;
DBUG_ENTER("QUICK_RANGE_SELECT::reset");
last_range= NULL;
cur_range= (QUICK_RANGE**) ranges.buffer;
@@ -11365,8 +11553,7 @@ int QUICK_RANGE_SELECT::reset()
}
if (in_ror_merged_scan)
- head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap,
- &column_bitmap);
+ head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap);
if (file->inited == handler::NONE)
{
@@ -11412,8 +11599,7 @@ int QUICK_RANGE_SELECT::reset()
err:
/* Restore bitmaps set on entry */
if (in_ror_merged_scan)
- head->column_bitmaps_set_no_signal(save_read_set, save_write_set,
- save_vcol_set);
+ head->column_bitmaps_set_no_signal(save_read_set, save_write_set);
DBUG_RETURN(error);
}
@@ -11444,16 +11630,13 @@ int QUICK_RANGE_SELECT::get_next()
MY_BITMAP * const save_read_set= head->read_set;
MY_BITMAP * const save_write_set= head->write_set;
- MY_BITMAP * const save_vcol_set= head->vcol_set;
/*
We don't need to signal the bitmap change as the bitmap is always the
same for this head->file
*/
- head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap,
- &column_bitmap);
+ head->column_bitmaps_set_no_signal(&column_bitmap, &column_bitmap);
result= file->multi_range_read_next(&dummy);
- head->column_bitmaps_set_no_signal(save_read_set, save_write_set,
- save_vcol_set);
+ head->column_bitmaps_set_no_signal(save_read_set, save_write_set);
DBUG_RETURN(result);
}
@@ -13028,7 +13211,8 @@ check_group_min_max_predicates(Item *cond, Item_field *min_max_arg_item,
if (args[0] && args[1]) // this is a binary function or BETWEEN
{
- DBUG_ASSERT(pred->is_bool_type());
+ DBUG_ASSERT(pred->fixed_type_handler());
+ DBUG_ASSERT(pred->fixed_type_handler()->is_bool_type());
Item_bool_func *bool_func= (Item_bool_func*) pred;
Field *field= min_max_arg_item->field;
if (!args[2]) // this is a binary function
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 13c0ce0c157..d1877c6c245 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -519,6 +519,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
+ child_select->outer_select() &&
child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
@@ -826,7 +827,7 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs)
{
DBUG_ENTER("subquery_types_allow_materialization");
- DBUG_ASSERT(in_subs->left_expr->fixed);
+ DBUG_ASSERT(in_subs->left_expr->is_fixed());
List_iterator<Item> it(in_subs->unit->first_select()->item_list);
uint elements= in_subs->unit->first_select()->item_list.elements;
@@ -902,7 +903,7 @@ bool make_in_exists_conversion(THD *thd, JOIN *join, Item_in_subselect *item)
/*
We're going to finalize IN->EXISTS conversion.
Normally, IN->EXISTS conversion takes place inside the
- Item_subselect::fix_fields() call, where item_subselect->fixed==FALSE (as
+ Item_subselect::fix_fields() call, where item_subselect->is_fixed()==FALSE (as
fix_fields() haven't finished yet) and item_subselect->changed==FALSE (as
the conversion haven't been finalized)
@@ -929,7 +930,7 @@ bool make_in_exists_conversion(THD *thd, JOIN *join, Item_in_subselect *item)
item->fixed= 1;
Item *substitute= item->substitution;
- bool do_fix_fields= !item->substitution->fixed;
+ bool do_fix_fields= !item->substitution->is_fixed();
/*
The Item_subselect has already been wrapped with Item_in_optimizer, so we
should search for item->optimizer, not 'item'.
@@ -1265,7 +1266,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
in_subq->fixed= 1;
Item *substitute= in_subq->substitution;
- bool do_fix_fields= !in_subq->substitution->fixed;
+ bool do_fix_fields= !in_subq->substitution->is_fixed();
Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
&join->conds : &(in_subq->emb_on_expr_nest->on_expr);
Item *replace_me= in_subq->original_item();
@@ -1800,7 +1801,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
subq_lex->ref_pointer_array[i]);
if (!item_eq)
DBUG_RETURN(TRUE);
- DBUG_ASSERT(subq_pred->left_expr->element_index(i)->fixed);
+ DBUG_ASSERT(subq_pred->left_expr->element_index(i)->is_fixed());
if (subq_pred->left_expr_orig->element_index(i) !=
subq_pred->left_expr->element_index(i))
thd->change_item_tree(item_eq->arguments(),
@@ -5509,31 +5510,454 @@ int select_value_catcher::send_data(List<Item> &items)
}
-/*
- Setup JTBM join tabs for execution
+/**
+ @brief
+ Conjugate conditions after optimize_cond() call
+
+ @param thd the thread handle
+ @param cond the condition where to attach new conditions
+ @param cond_eq IN/OUT the multiple equalities of cond
+ @param new_conds IN/OUT the list of conditions needed to add
+ @param cond_value the returned value of the condition
+
+ @details
+ The method creates new condition through conjunction of cond and
+ the conditions from new_conds list.
+ The method is called after optimize_cond() for cond. The result
+ of the conjunction should be the same as if it was done before the
+ the optimize_cond() call.
+
+ @retval NULL if an error occurs
+ @retval otherwise the created condition
+*/
+
+Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
+ COND_EQUAL **cond_eq,
+ List<Item> &new_conds,
+ Item::cond_result *cond_value)
+{
+ COND_EQUAL new_cond_equal;
+ Item *item;
+ Item_equal *equality;
+ bool is_simplified_cond= false;
+ List_iterator<Item> li(new_conds);
+ List_iterator_fast<Item_equal> it(new_cond_equal.current_level);
+
+ /*
+ Creates multiple equalities new_cond_equal from new_conds list
+ equalities. If multiple equality can't be created or the condition
+ from new_conds list isn't an equality the method leaves it in new_conds
+ list.
+
+ The equality can't be converted into the multiple equality if it
+ is a knowingly false or true equality.
+ For example, (3 = 1) equality.
+ */
+ while ((item=li++))
+ {
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::EQ_FUNC &&
+ check_simple_equality(thd,
+ Item::Context(Item::ANY_SUBST,
+ ((Item_func_equal *)item)->compare_type_handler(),
+ ((Item_func_equal *)item)->compare_collation()),
+ ((Item_func *)item)->arguments()[0]->real_item(),
+ ((Item_func *)item)->arguments()[1]->real_item(),
+ &new_cond_equal))
+ li.remove();
+ }
+
+ it.rewind();
+ if (cond && cond->type() == Item::COND_ITEM &&
+ ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+ {
+ /*
+ cond is an AND-condition.
+ The method conjugates the AND-condition cond, created multiple
+ equalities new_cond_equal and remain conditions from new_conds.
+
+ First, the method disjoins multiple equalities of cond and
+ merges new_cond_equal multiple equalities with these equalities.
+ It checks if after the merge the multiple equalities are knowingly
+ true or false equalities.
+ It attaches to cond the conditions from new_conds list and the result
+ of the merge of multiple equalities. The multiple equalities are
+ attached only to the upper level of AND-condition cond. So they
+ should be pushed down to the inner levels of cond AND-condition
+ if needed. It is done by propagate_new_equalities().
+ */
+ COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal;
+ List<Item_equal> *cond_equalities= &cond_equal->current_level;
+ List<Item> *and_args= ((Item_cond_and *)cond)->argument_list();
+ and_args->disjoin((List<Item> *) cond_equalities);
+ and_args->append(&new_conds);
+
+ while ((equality= it++))
+ {
+ equality->upper_levels= 0;
+ equality->merge_into_list(thd, cond_equalities, false, false);
+ }
+ List_iterator_fast<Item_equal> ei(*cond_equalities);
+ while ((equality= ei++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ equality->fixed= 0;
+ if (equality->fix_fields(thd, NULL))
+ return NULL;
+ }
+
+ and_args->append((List<Item> *) cond_equalities);
+ *cond_eq= &((Item_cond_and *) cond)->m_cond_equal;
+
+ propagate_new_equalities(thd, cond, cond_equalities,
+ cond_equal->upper_levels,
+ &is_simplified_cond);
+ cond= cond->propagate_equal_fields(thd,
+ Item::Context_boolean(),
+ cond_equal);
+ }
+ else
+ {
+ /*
+ cond isn't AND-condition or is NULL.
+ There can be several cases:
+
+ 1. cond is a multiple equality.
+ In this case cond is merged with the multiple equalities of
+ new_cond_equal.
+ The new condition is created with the conjunction of new_conds
+ list conditions and the result of merge of multiple equalities.
+ 2. cond is NULL
+ The new condition is created from the conditions of new_conds
+ list and multiple equalities from new_cond_equal.
+ 3. Otherwise
+ In this case the new condition is created from cond, remain conditions
+ from new_conds list and created multiple equalities from
+ new_cond_equal.
+ */
+ List<Item> new_conds_list;
+ /* Flag is set to true if cond is a multiple equality */
+ bool is_mult_eq= (cond && cond->type() == Item::FUNC_ITEM &&
+ ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC);
+
+ if (cond && !is_mult_eq &&
+ new_conds_list.push_back(cond, thd->mem_root))
+ return NULL;
+
+ if (new_conds.elements > 0)
+ {
+ li.rewind();
+ while ((item=li++))
+ {
+ if (item->fix_fields_if_needed(thd, NULL))
+ return NULL;
+ if (item->const_item() && !item->val_int())
+ is_simplified_cond= true;
+ }
+
+ if (new_conds.elements > 1)
+ new_conds_list.append(&new_conds);
+ else
+ {
+ li.rewind();
+ item= li++;
+ if (new_conds_list.push_back(item, thd->mem_root))
+ return NULL;
+ }
+ }
+
+ if (new_cond_equal.current_level.elements > 0)
+ {
+ if (is_mult_eq)
+ {
+ Item_equal *eq_cond= (Item_equal *)cond;
+ eq_cond->upper_levels= 0;
+ eq_cond->merge_into_list(thd, &new_cond_equal.current_level,
+ false, false);
+
+ while ((equality= it++))
+ {
+ if (equality->const_item() && !equality->val_int())
+ is_simplified_cond= true;
+ }
+
+ if (new_cond_equal.current_level.elements +
+ new_conds_list.elements == 1)
+ {
+ it.rewind();
+ equality= it++;
+ equality->fixed= 0;
+ if (equality->fix_fields(thd, NULL))
+ return NULL;
+ }
+ (*cond_eq)->copy(new_cond_equal);
+ }
+ new_conds_list.append((List<Item> *)&new_cond_equal.current_level);
+ }
+
+ if (new_conds_list.elements > 1)
+ {
+ Item_cond_and *and_cond=
+ new (thd->mem_root) Item_cond_and(thd, new_conds_list);
+
+ and_cond->m_cond_equal.copy(new_cond_equal);
+ cond= (Item *)and_cond;
+ *cond_eq= &((Item_cond_and *)cond)->m_cond_equal;
+ }
+ else
+ {
+ List_iterator_fast<Item> iter(new_conds_list);
+ cond= iter++;
+ }
+
+ if (cond->fix_fields_if_needed(thd, NULL))
+ return NULL;
+
+ if (new_cond_equal.current_level.elements > 0)
+ cond= cond->propagate_equal_fields(thd,
+ Item::Context_boolean(),
+ &new_cond_equal);
+ }
+
+ /*
+ If it was found that some of the created condition parts are knowingly
+ true or false equalities the method calls removes_eq_cond() to remove them
+ from cond and set the cond_value to the appropriate value.
+ */
+ if (is_simplified_cond)
+ cond= cond->remove_eq_conds(thd, cond_value, true);
+ return cond;
+}
+
+
+/**
+ @brief Materialize a degenerate jtbm semi join
+
+ @param thd thread handler
+ @param tbl table list for the target jtbm semi join table
+ @param subq_pred IN subquery predicate with the degenerate jtbm semi join
+ @param eq_list IN/OUT the list where to add produced equalities
+
+ @details
+ The method materializes the degenerate jtbm semi join for the
+ subquery from the IN subquery predicate subq_pred taking table
+ as the target for materialization.
+ Any degenerate table is guaranteed to produce 0 or 1 record.
+ Examples of both cases:
+
+ select * from ot where col in (select ... from it where 2>3)
+ select * from ot where col in (select MY_MIN(it.key) from it)
+
+ in this case, there is no necessity to create a temp.table for
+ materialization.
+ We now just need to
+ 1. Check whether 1 or 0 records are produced, setup this as a
+ constant join tab.
+ 2. Create a dummy temporary table, because all of the join
+ optimization code relies on TABLE object being present.
+
+ In the case when materialization produces one row the function
+ additionally creates equalities between the expressions from the
+ left part of the IN subquery predicate and the corresponding
+ columns of the produced row. These equalities are added to the
+ list eq_list. They are supposed to be conjuncted with the condition
+ of the WHERE clause.
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
*/
-bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
- Item **join_where)
+bool execute_degenerate_jtbm_semi_join(THD *thd,
+ TABLE_LIST *tbl,
+ Item_in_subselect *subq_pred,
+ List<Item> &eq_list)
+{
+ DBUG_ENTER("execute_degenerate_jtbm_semi_join");
+ select_value_catcher *new_sink;
+
+ DBUG_ASSERT(subq_pred->engine->engine_type() ==
+ subselect_engine::SINGLE_SELECT_ENGINE);
+ subselect_single_select_engine *engine=
+ (subselect_single_select_engine*)subq_pred->engine;
+ if (!(new_sink= new (thd->mem_root) select_value_catcher(thd, subq_pred)))
+ DBUG_RETURN(TRUE);
+ if (new_sink->setup(&engine->select_lex->join->fields_list) ||
+ engine->select_lex->join->change_result(new_sink, NULL) ||
+ engine->exec())
+ {
+ DBUG_RETURN(TRUE);
+ }
+ subq_pred->is_jtbm_const_tab= TRUE;
+
+ if (new_sink->assigned)
+ {
+ /*
+ Subselect produced one row, which is saved in new_sink->row.
+ Save "left_expr[i] == row[i]" equalities into the eq_list.
+ */
+ subq_pred->jtbm_const_row_found= TRUE;
+
+ Item *eq_cond;
+ for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
+ {
+ eq_cond=
+ new (thd->mem_root) Item_func_eq(thd,
+ subq_pred->left_expr->element_index(i),
+ new_sink->row[i]);
+ if (!eq_cond || eq_cond->fix_fields(thd, NULL) ||
+ eq_list.push_back(eq_cond, thd->mem_root))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ {
+ /* Subselect produced no rows. Just set the flag */
+ subq_pred->jtbm_const_row_found= FALSE;
+ }
+
+ TABLE *dummy_table;
+ if (!(dummy_table= create_dummy_tmp_table(thd)))
+ DBUG_RETURN(TRUE);
+ tbl->table= dummy_table;
+ tbl->table->pos_in_table_list= tbl;
+ /*
+ Note: the table created above may be freed by:
+ 1. JOIN_TAB::cleanup(), when the parent join is a regular join.
+ 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a
+ degenerate join (e.g. one with "Impossible where").
+ */
+ setup_table_map(tbl->table, tbl, tbl->jtbm_table_no);
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ @brief
+ Execute degenerate jtbm semi joins before optimize_cond() for parent
+
+ @param join the parent join for jtbm semi joins
+ @param join_list the list of tables where jtbm semi joins are processed
+ @param eq_list IN/OUT the list where to add equalities produced after
+ materialization of single-row degenerate jtbm semi joins
+
+ @details
+ The method traverses join_list trying to find any degenerate jtbm semi
+ joins for subqueries of IN predicates. For each degenerate jtbm
+ semi join execute_degenerate_jtbm_semi_join() is called. As a result
+ of this call new equalities that substitute for single-row materialized
+ jtbm semi join are added to eq_list.
+
+ In the case when a table is nested in another table 'nested_join' the
+ method is recursively called for the join_list of the 'nested_join' trying
+ to find in the list any degenerate jtbm semi joins. Currently a jtbm semi
+ join may occur in a mergeable semi join nest.
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
+*/
+
+bool setup_degenerate_jtbm_semi_joins(JOIN *join,
+ List<TABLE_LIST> *join_list,
+ List<Item> &eq_list)
+{
+ TABLE_LIST *table;
+ NESTED_JOIN *nested_join;
+ List_iterator<TABLE_LIST> li(*join_list);
+ THD *thd= join->thd;
+ DBUG_ENTER("setup_degenerate_jtbm_semi_joins");
+
+ while ((table= li++))
+ {
+ Item_in_subselect *subq_pred;
+
+ if ((subq_pred= table->jtbm_subselect))
+ {
+ JOIN *subq_join= subq_pred->unit->first_select()->join;
+
+ if (!subq_join->tables_list || !subq_join->table_count)
+ {
+ if (execute_degenerate_jtbm_semi_join(thd,
+ table,
+ subq_pred,
+ eq_list))
+ DBUG_RETURN(TRUE);
+ join->is_orig_degenerated= true;
+ }
+ }
+ if ((nested_join= table->nested_join))
+ {
+ if (setup_degenerate_jtbm_semi_joins(join,
+ &nested_join->join_list,
+ eq_list))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ @brief
+ Optimize jtbm semi joins for materialization
+
+ @param join the parent join for jtbm semi joins
+ @param join_list the list of TABLE_LIST objects where jtbm semi join
+ can occur
+ @param eq_list IN/OUT the list where to add produced equalities
+
+ @details
+ This method is called by the optimizer after the call of
+ optimize_cond() for parent select.
+ The method traverses join_list trying to find any jtbm semi joins for
+ subqueries from IN predicates and optimizes them.
+ After the optimization some of jtbm semi joins may become degenerate.
+ For example the subquery 'SELECT MAX(b) FROM t2' from the query
+
+ SELECT * FROM t1 WHERE 4 IN (SELECT MAX(b) FROM t2);
+
+ will become degenerate if there is an index on t2.b.
+ If a subquery becomes degenerate it is handled by the function
+ execute_degenerate_jtbm_semi_join().
+
+ Otherwise the method creates a temporary table in which the subquery
+ of the jtbm semi join will be materialied.
+
+ The function saves the equalities between all pairs of the expressions
+ from the left part of the IN subquery predicate and the corresponding
+ columns of the subquery from the predicate in eq_list appending them
+ to the list. The equalities of eq_list will be later conjucted with the
+ condition of the WHERE clause.
+
+ In the case when a table is nested in another table 'nested_join' the
+ method is recursively called for the join_list of the 'nested_join' trying
+ to find in the list any degenerate jtbm semi joins. Currently a jtbm semi
+ join may occur in a mergeable semi join nest.
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
+*/
+
+bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
+ List<Item> &eq_list)
{
TABLE_LIST *table;
NESTED_JOIN *nested_join;
List_iterator<TABLE_LIST> li(*join_list);
THD *thd= join->thd;
DBUG_ENTER("setup_jtbm_semi_joins");
-
+
while ((table= li++))
{
- Item_in_subselect *item;
+ Item_in_subselect *subq_pred;
- if ((item= table->jtbm_subselect))
+ if ((subq_pred= table->jtbm_subselect))
{
- Item_in_subselect *subq_pred= item;
double rows;
double read_time;
/*
- Perform optimization of the subquery, so that we know estmated
+ Perform optimization of the subquery, so that we know estimated
- cost of materialization process
- how many records will be in the materialized temp.table
*/
@@ -5546,102 +5970,37 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
if (!subq_join->tables_list || !subq_join->table_count)
{
- /*
- A special case; subquery's join is degenerate, and it either produces
- 0 or 1 record. Examples of both cases:
-
- select * from ot where col in (select ... from it where 2>3)
- select * from ot where col in (select MY_MIN(it.key) from it)
-
- in this case, the subquery predicate has not been setup for
- materialization. In particular, there is no materialized temp.table.
- We'll now need to
- 1. Check whether 1 or 0 records are produced, setup this as a
- constant join tab.
- 2. Create a dummy temporary table, because all of the join
- optimization code relies on TABLE object being present (here we
- follow a bad tradition started by derived tables)
- */
- DBUG_ASSERT(subq_pred->engine->engine_type() ==
- subselect_engine::SINGLE_SELECT_ENGINE);
- subselect_single_select_engine *engine=
- (subselect_single_select_engine*)subq_pred->engine;
- select_value_catcher *new_sink;
- if (!(new_sink=
- new (thd->mem_root) select_value_catcher(thd, subq_pred)))
- DBUG_RETURN(TRUE);
- if (new_sink->setup(&engine->select_lex->join->fields_list) ||
- engine->select_lex->join->change_result(new_sink, NULL) ||
- engine->exec())
- {
+ if (!join->is_orig_degenerated &&
+ execute_degenerate_jtbm_semi_join(thd, table, subq_pred,
+ eq_list))
DBUG_RETURN(TRUE);
- }
- subq_pred->is_jtbm_const_tab= TRUE;
-
- if (new_sink->assigned)
- {
- subq_pred->jtbm_const_row_found= TRUE;
- /*
- Subselect produced one row, which is saved in new_sink->row.
- Inject "left_expr[i] == row[i] equalities into parent's WHERE.
- */
- Item *eq_cond;
- for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
- {
- eq_cond= new (thd->mem_root)
- Item_func_eq(thd, subq_pred->left_expr->element_index(i),
- new_sink->row[i]);
- if (!eq_cond)
- DBUG_RETURN(1);
-
- if (!((*join_where)= and_items(thd, *join_where, eq_cond)) ||
- (*join_where)->fix_fields(thd, join_where))
- DBUG_RETURN(1);
- }
- }
- else
- {
- /* Subselect produced no rows. Just set the flag, */
- subq_pred->jtbm_const_row_found= FALSE;
- }
-
- /* Set up a dummy TABLE*, optimizer code needs JOIN_TABs to have TABLE */
- TABLE *dummy_table;
- if (!(dummy_table= create_dummy_tmp_table(thd)))
- DBUG_RETURN(1);
- table->table= dummy_table;
- table->table->pos_in_table_list= table;
- /*
- Note: the table created above may be freed by:
- 1. JOIN_TAB::cleanup(), when the parent join is a regular join.
- 2. cleanup_empty_jtbm_semi_joins(), when the parent join is a
- degenerate join (e.g. one with "Impossible where").
- */
- setup_table_map(table->table, table, table->jtbm_table_no);
}
else
{
DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION));
subq_pred->is_jtbm_const_tab= FALSE;
subselect_hash_sj_engine *hash_sj_engine=
- ((subselect_hash_sj_engine*)item->engine);
+ ((subselect_hash_sj_engine*)subq_pred->engine);
table->table= hash_sj_engine->tmp_table;
table->table->pos_in_table_list= table;
setup_table_map(table->table, table, table->jtbm_table_no);
- Item *sj_conds= hash_sj_engine->semi_join_conds;
-
- (*join_where)= and_items(thd, *join_where, sj_conds);
- (*join_where)->fix_fields_if_needed(thd, join_where);
+ List_iterator<Item> li(*hash_sj_engine->semi_join_conds->argument_list());
+ Item *item;
+ while ((item=li++))
+ {
+ item->update_used_tables();
+ if (eq_list.push_back(item, thd->mem_root))
+ DBUG_RETURN(TRUE);
+ }
}
table->table->maybe_null= MY_TEST(join->mixed_implicit_grouping);
}
-
if ((nested_join= table->nested_join))
{
- if (setup_jtbm_semi_joins(join, &nested_join->join_list, join_where))
+ if (setup_jtbm_semi_joins(join, &nested_join->join_list, eq_list))
DBUG_RETURN(TRUE);
}
}
@@ -5749,8 +6108,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
/* A strategy must be chosen earlier. */
DBUG_ASSERT(in_subs->has_strategy());
DBUG_ASSERT(in_to_exists_where || in_to_exists_having);
- DBUG_ASSERT(!in_to_exists_where || in_to_exists_where->fixed);
- DBUG_ASSERT(!in_to_exists_having || in_to_exists_having->fixed);
+ DBUG_ASSERT(!in_to_exists_where || in_to_exists_where->is_fixed());
+ DBUG_ASSERT(!in_to_exists_having || in_to_exists_having->is_fixed());
/* The original QEP of the subquery. */
Join_plan_state save_qep(table_count);
@@ -6037,3 +6396,418 @@ bool JOIN::choose_tableless_subquery_plan()
exec_const_cond= zero_result_cause ? 0 : conds;
return FALSE;
}
+
+
+/*
+ Check if the item exists in the fields list of the left part of
+ the IN subquery predicate subq_pred and returns its corresponding
+ item from the select of the right part of subq_pred.
+*/
+Item *Item::get_corresponding_field_in_insubq(Item_in_subselect *subq_pred)
+{
+ DBUG_ASSERT(type() == Item::FIELD_ITEM ||
+ (type() == Item::REF_ITEM &&
+ ((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF));
+
+ List_iterator<Field_pair> it(subq_pred->corresponding_fields);
+ Field_pair *ret;
+ Item_field *field_item= (Item_field *) (real_item());
+ while ((ret= it++))
+ {
+ if (field_item->field == ret->field)
+ return ret->corresponding_item;
+ }
+ return NULL;
+}
+
+
+bool Item_field::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+{
+ if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred))
+ return true;
+ if (item_equal)
+ {
+ Item_equal_fields_iterator it(*item_equal);
+ Item *equal_item;
+ while ((equal_item= it++))
+ {
+ if (equal_item->const_item())
+ continue;
+ if (equal_item->get_corresponding_field_in_insubq(subq_pred))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Item_direct_view_ref::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+{
+ if (item_equal)
+ {
+ DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
+ if (((Item *)this)->get_corresponding_field_in_insubq(subq_pred))
+ return true;
+ }
+ return (*ref)->excl_dep_on_in_subq_left_part(subq_pred);
+}
+
+
+bool Item_equal::excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
+{
+ Item *left_item = get_const();
+ Item_equal_fields_iterator it(*this);
+ Item *item;
+ if (!left_item)
+ {
+ while ((item=it++))
+ {
+ if (item->excl_dep_on_in_subq_left_part(subq_pred))
+ {
+ left_item= item;
+ break;
+ }
+ }
+ }
+ if (!left_item)
+ return false;
+ while ((item=it++))
+ {
+ if (item->excl_dep_on_in_subq_left_part(subq_pred))
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ @brief
+ Get corresponding item from the select of the right part of IN subquery
+
+ @param thd the thread handle
+ @param item the item from the left part of subq_pred for which
+ corresponding item should be found
+ @param subq_pred the IN subquery predicate
+
+ @details
+ This method looks through the fields of the select of the right part of
+ the IN subquery predicate subq_pred trying to find the corresponding
+ item 'new_item' for item. If item has equal items it looks through
+ the fields of the select of the right part of subq_pred for each equal
+ item trying to find the corresponding item.
+ The method assumes that the given item is either a field item or
+ a reference to a field item.
+
+ @retval <item*> reference to the corresponding item
+ @retval NULL if item was not found
+*/
+
+static
+Item *get_corresponding_item(THD *thd, Item *item,
+ Item_in_subselect *subq_pred)
+{
+ DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
+ (item->type() == Item::REF_ITEM &&
+ ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF));
+
+ Item *corresonding_item;
+ Item_equal *item_equal= item->get_item_equal();
+
+ if (item_equal)
+ {
+ Item_equal_fields_iterator it(*item_equal);
+ Item *equal_item;
+ while ((equal_item= it++))
+ {
+ corresonding_item=
+ equal_item->get_corresponding_field_in_insubq(subq_pred);
+ if (corresonding_item)
+ return corresonding_item;
+ }
+ return NULL;
+ }
+ else
+ return item->get_corresponding_field_in_insubq(subq_pred);
+}
+
+
+Item *Item_field::in_subq_field_transformer_for_where(THD *thd, uchar *arg)
+{
+ Item_in_subselect *subq_pred= (Item_in_subselect *)arg;
+ Item *producing_item= get_corresponding_item(thd, this, subq_pred);
+ if (producing_item)
+ return producing_item->build_clone(thd);
+ return this;
+}
+
+
+Item *Item_direct_view_ref::in_subq_field_transformer_for_where(THD *thd,
+ uchar *arg)
+{
+ if (item_equal)
+ {
+ Item_in_subselect *subq_pred= (Item_in_subselect *)arg;
+ Item *producing_item= get_corresponding_item(thd, this, subq_pred);
+ DBUG_ASSERT (producing_item != NULL);
+ return producing_item->build_clone(thd);
+ }
+ return this;
+}
+
+
+/**
+ @brief
+ Transforms item so it can be pushed into the IN subquery HAVING clause
+
+ @param thd the thread handle
+ @param in_item the item for which pushable item should be created
+ @param subq_pred the IN subquery predicate
+
+ @details
+ This method finds for in_item that is a field from the left part of the
+ IN subquery predicate subq_pred its corresponding item from the right part
+ of subq_pred.
+ If corresponding item is found, a shell for this item is created.
+ This shell can be pushed into the HAVING part of subq_pred select.
+
+ @retval <item*> reference to the created corresponding item shell for in_item
+ @retval NULL if mistake occurs
+*/
+
+static Item*
+get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item,
+ Item_in_subselect *subq_pred)
+{
+ Item *new_item= get_corresponding_item(thd, in_item, subq_pred);
+
+ if (new_item)
+ {
+ Item_ref *ref=
+ new (thd->mem_root) Item_ref(thd,
+ &subq_pred->unit->first_select()->context,
+ NullS, NullS,
+ &new_item->name);
+ if (!ref)
+ DBUG_ASSERT(0);
+ return ref;
+ }
+ return new_item;
+}
+
+
+Item *Item_field::in_subq_field_transformer_for_having(THD *thd, uchar *arg)
+{
+ return get_corresponding_item_for_in_subq_having(thd, this,
+ (Item_in_subselect *)arg);
+}
+
+
+Item *Item_direct_view_ref::in_subq_field_transformer_for_having(THD *thd,
+ uchar *arg)
+{
+ if (!item_equal)
+ return this;
+ else
+ {
+ Item *new_item= get_corresponding_item_for_in_subq_having(thd, this,
+ (Item_in_subselect *)arg);
+ if (!new_item)
+ return this;
+ return new_item;
+ }
+}
+
+
+/**
+ @brief
+ Find fields that are used in the GROUP BY of the select
+
+ @param thd the thread handle
+ @param sel the select of the IN subquery predicate
+ @param fields fields of the left part of the IN subquery predicate
+ @param grouping_list GROUP BY clause
+
+ @details
+ This method traverses fields which are used in the GROUP BY of
+ sel and saves them with their corresponding items from fields.
+*/
+
+bool grouping_fields_in_the_in_subq_left_part(THD *thd,
+ st_select_lex *sel,
+ List<Field_pair> *fields,
+ ORDER *grouping_list)
+{
+ DBUG_ENTER("grouping_fields_in_the_in_subq_left_part");
+ sel->grouping_tmp_fields.empty();
+ List_iterator<Field_pair> it(*fields);
+ Field_pair *item;
+ while ((item= it++))
+ {
+ for (ORDER *ord= grouping_list; ord; ord= ord->next)
+ {
+ if ((*ord->item)->eq(item->corresponding_item, 0))
+ {
+ if (sel->grouping_tmp_fields.push_back(item, thd->mem_root))
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/**
+ @brief
+ Extract condition that can be pushed into select of this IN subquery
+
+ @param thd the thread handle
+ @param cond current condition
+
+ @details
+ This function builds the most restrictive condition depending only on
+ the list of fields of the left part of this IN subquery predicate
+ (directly or indirectly through equality) that can be extracted from the
+ given condition cond and pushes it into this IN subquery.
+
+ Example of the transformation:
+
+ SELECT * FROM t1
+ WHERE a>3 AND b>10 AND
+ (a,b) IN (SELECT x,MAX(y) FROM t2 GROUP BY x);
+
+ =>
+
+ SELECT * FROM t1
+ WHERE a>3 AND b>10 AND
+ (a,b) IN (SELECT x,max(y)
+ FROM t2
+ WHERE x>3
+ GROUP BY x
+ HAVING MAX(y)>10);
+
+
+ In details:
+ 1. Check what pushable formula can be extracted from cond
+ 2. Build a clone PC of the formula that can be extracted
+ (the clone is built only if the extracted formula is a AND subformula
+ of cond or conjunction of such subformulas)
+ 3. If there is no HAVING clause prepare PC to be conjuncted with
+ WHERE clause of this subquery. Otherwise do 4-7.
+ 4. Check what formula PC_where can be extracted from PC to be pushed
+ into the WHERE clause of the subquery
+ 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC
+ getting PC_having
+ 6. Prepare PC_where to be conjuncted with the WHERE clause of
+ the IN subquery
+ 7. Prepare PC_having to be conjuncted with the HAVING clause of
+ the IN subquery
+
+ @note
+ This method is similar to pushdown_cond_for_derived()
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
+*/
+
+bool Item_in_subselect::pushdown_cond_for_in_subquery(THD *thd, Item *cond)
+{
+ DBUG_ENTER("Item_in_subselect::pushdown_cond_for_in_subquery");
+ Item *remaining_cond= NULL;
+
+ if (!cond)
+ DBUG_RETURN(FALSE);
+
+ st_select_lex *sel = unit->first_select();
+
+ if (is_jtbm_const_tab)
+ DBUG_RETURN(FALSE);
+
+ if (!sel->cond_pushdown_is_allowed())
+ DBUG_RETURN(FALSE);
+
+ /*
+ Create a list of Field_pair items for this IN subquery.
+ It consists of the pairs of fields from the left part of this IN subquery
+ predicate 'left_part' and the respective fields from the select of the
+ right part of the IN subquery 'sel' (the field from left_part with the
+ corresponding field from the sel projection list).
+ Attach this list to the IN subquery.
+ */
+ corresponding_fields.empty();
+ List_iterator_fast<Item> it(sel->join->fields_list);
+ Item *item;
+ for (uint i= 0; i < left_expr->cols(); i++)
+ {
+ item= it++;
+ Item *elem= left_expr->element_index(i);
+
+ if (elem->real_item()->type() != Item::FIELD_ITEM)
+ continue;
+
+ if (corresponding_fields.push_back(
+ new Field_pair(((Item_field *)(elem->real_item()))->field,
+ item)))
+ DBUG_RETURN(TRUE);
+ }
+
+ /* 1. Check what pushable formula can be extracted from cond */
+ Item *extracted_cond;
+ cond->check_pushable_cond(&Item::pushable_cond_checker_for_subquery,
+ (uchar *)this);
+ /* 2. Build a clone PC of the formula that can be extracted */
+ extracted_cond=
+ cond->build_pushable_cond(thd,
+ &Item::pushable_equality_checker_for_subquery,
+ (uchar *)this);
+ /* Nothing to push */
+ if (!extracted_cond)
+ {
+ DBUG_RETURN(FALSE);
+ }
+
+ /* Collect fields that are used in the GROUP BY of sel */
+ st_select_lex *save_curr_select= thd->lex->current_select;
+ if (sel->have_window_funcs())
+ {
+ if (sel->group_list.first || sel->join->implicit_grouping)
+ goto exit;
+ ORDER *common_partition_fields=
+ sel->find_common_window_func_partition_fields(thd);
+ if (!common_partition_fields)
+ goto exit;
+
+ if (grouping_fields_in_the_in_subq_left_part(thd, sel, &corresponding_fields,
+ common_partition_fields))
+ DBUG_RETURN(TRUE);
+ }
+ else if (grouping_fields_in_the_in_subq_left_part(thd, sel,
+ &corresponding_fields,
+ sel->group_list.first))
+ DBUG_RETURN(TRUE);
+
+ /* Do 4-6 */
+ sel->pushdown_cond_into_where_clause(thd, extracted_cond,
+ &remaining_cond,
+ &Item::in_subq_field_transformer_for_where,
+ (uchar *) this);
+ if (!remaining_cond)
+ goto exit;
+ /*
+ 7. Prepare PC_having to be conjuncted with the HAVING clause of
+ the IN subquery
+ */
+ remaining_cond=
+ remaining_cond->transform(thd,
+ &Item::in_subq_field_transformer_for_having,
+ (uchar *)this);
+ if (!remaining_cond)
+ goto exit;
+
+ remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor,
+ 0, 0);
+ sel->cond_pushed_into_having= remaining_cond;
+
+exit:
+ thd->lex->current_select= save_curr_select;
+ DBUG_RETURN(FALSE);
+}
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index 9cb19e0cc6c..031118288b9 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -26,8 +26,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join);
bool convert_join_subqueries_to_semijoins(JOIN *join);
int pull_out_semijoin_tables(JOIN *join);
bool optimize_semijoin_nests(JOIN *join, table_map all_table_map);
-bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
- Item **join_where);
+Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond,
+ COND_EQUAL **cond_eq,
+ List<Item> &new_conds,
+ Item::cond_result *cond_value);
+bool setup_degenerate_jtbm_semi_joins(JOIN *join,
+ List<TABLE_LIST> *join_list,
+ List<Item> &eq_list);
+bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
+ List<Item> &eq_list);
void cleanup_empty_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list);
// used by Loose_scan_opt
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 82946709166..ecede5903a2 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -318,7 +318,7 @@ int opt_sum_query(THD *thd,
error= tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
if (unlikely(error))
{
- tl->table->file->print_error(error, MYF(ME_FATALERROR));
+ tl->table->file->print_error(error, MYF(ME_FATAL));
DBUG_RETURN(error);
}
count*= tl->table->file->stats.records;
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index ef9b07cca47..74d1e775c43 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -617,12 +617,12 @@ void eliminate_tables(JOIN *join)
we should also take into account tables mentioned in "val".
*/
if (join->thd->lex->sql_command == SQLCOM_INSERT_SELECT &&
- join->select_lex == &thd->lex->select_lex)
+ join->select_lex == thd->lex->first_select_lex())
{
List_iterator<Item> val_it(thd->lex->value_list);
while ((item= val_it++))
{
- DBUG_ASSERT(item->fixed);
+ DBUG_ASSERT(item->is_fixed());
used_tables |= item->used_tables();
}
}
@@ -640,7 +640,7 @@ void eliminate_tables(JOIN *join)
used_tables |= (*(cur_list->item))->used_tables();
}
- if (join->select_lex == &thd->lex->select_lex)
+ if (join->select_lex == thd->lex->first_select_lex())
{
/* Multi-table UPDATE: don't eliminate tables referred from SET statement */
diff --git a/sql/procedure.h b/sql/procedure.h
index 1ece31223ad..8826b397fb2 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -44,6 +44,16 @@ public:
this->name.length= strlen(name_par);
}
enum Type type() const { return Item::PROC_ITEM; }
+ Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ const Tmp_field_param *param)
+ {
+ /*
+ We can get to here when using a CURSOR for a query with PROCEDURE:
+ DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
+ OPEN c;
+ */
+ return create_tmp_field_ex_simple(table, src, param);
+ }
virtual void set(double nr)=0;
virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
virtual void set(longlong nr)=0;
diff --git a/sql/protocol.cc b/sql/protocol.cc
index c4c243ea166..7eee9283989 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1195,9 +1195,8 @@ bool Protocol_text::store_decimal(const my_decimal *d)
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++;
#endif
- char buff[DECIMAL_MAX_STR_LENGTH];
- String str(buff, sizeof(buff), &my_charset_bin);
- (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
+ (void) d->to_string(&str);
return net_store_data((uchar*) str.ptr(), str.length());
}
@@ -1446,9 +1445,8 @@ bool Protocol_binary::store_decimal(const my_decimal *d)
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++;
#endif
- char buff[DECIMAL_MAX_STR_LENGTH];
- String str(buff, sizeof(buff), &my_charset_bin);
- (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
+ (void) d->to_string(&str);
return store(str.ptr(), str.length(), str.charset());
}
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 6f659aa12ad..897d4394525 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -1091,7 +1091,7 @@ bool Master_info_index::init_all_master_info()
if ((index_file_nr= my_open(index_file_name,
O_RDWR | O_CREAT | O_BINARY ,
- MYF(MY_WME | ME_NOREFRESH))) < 0 ||
+ MYF(MY_WME | ME_ERROR_LOG))) < 0 ||
my_sync(index_file_nr, MYF(MY_WME)) ||
init_io_cache(&index_file, index_file_nr,
IO_SIZE, READ_CACHE,
@@ -1307,7 +1307,7 @@ Master_info *get_master_info(const LEX_CSTRING *connection_name,
if (warning != Sql_condition::WARN_LEVEL_NOTE)
my_error(WARN_NO_MASTER_INFO,
MYF(warning == Sql_condition::WARN_LEVEL_WARN ?
- ME_JUST_WARNING : 0),
+ ME_WARNING : 0),
(int) connection_name->length, connection_name->str);
mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(0);
@@ -1377,7 +1377,7 @@ Master_info_index::get_master_info(const LEX_CSTRING *connection_name,
if (!mi && warning != Sql_condition::WARN_LEVEL_NOTE)
{
my_error(WARN_NO_MASTER_INFO,
- MYF(warning == Sql_condition::WARN_LEVEL_WARN ? ME_JUST_WARNING :
+ MYF(warning == Sql_condition::WARN_LEVEL_WARN ? ME_WARNING :
0),
(int) connection_name->length,
connection_name->str);
diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc
index db579a63ce0..94c1f08e4e3 100644
--- a/sql/rpl_record.cc
+++ b/sql/rpl_record.cc
@@ -497,7 +497,9 @@ int prepare_record(TABLE *const table, const uint skip, const bool check)
DBUG_RETURN(0);
}
/**
- Fills @c table->record[0] with computed values of extra persistent column which are present on slave but not on master.
+ Fills @c table->record[0] with computed values of extra persistent column
+ which are present on slave but not on master.
+
@param table Table whose record[0] buffer is prepared.
@param master_cols No of columns on master
@returns 0 on success
@@ -514,10 +516,8 @@ int fill_extra_persistent_columns(TABLE *table, int master_cols)
vfield= *vfield_ptr;
if (vfield->field_index >= master_cols && vfield->stored_in_db())
{
- /*Set bitmap for writing*/
- bitmap_set_bit(table->vcol_set, vfield->field_index);
+ bitmap_set_bit(table->write_set, vfield->field_index);
error= vfield->vcol_info->expr->save_in_field(vfield,0);
- bitmap_clear_bit(table->vcol_set, vfield->field_index);
}
}
return error;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 8ab892068b3..de9bda3d067 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -742,7 +742,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free)
err:
if (free)
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, thd->lex->first_select_lex());
DBUG_RETURN(error);
}
diff --git a/sql/sp.cc b/sql/sp.cc
index af86737ebb9..723f30ec85d 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1468,7 +1468,7 @@ log:
log_query.ptr(), log_query.length(),
FALSE, FALSE, FALSE, 0))
{
- my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), "binary log", -1);
+ my_error(ER_ERROR_ON_WRITE, MYF(0), "binary log", -1);
goto done;
}
thd->variables.sql_mode= 0;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index c1c938dd9e7..c86edc47bf9 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -71,33 +71,6 @@ static void reset_start_time_for_sp(THD *thd)
}
-Item::Type
-sp_map_item_type(const Type_handler *handler)
-{
- if (handler == &type_handler_row)
- return Item::ROW_ITEM;
- enum_field_types type= real_type_to_type(handler->real_field_type());
-
- switch (type) {
- case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- return Item::INT_ITEM;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- return Item::DECIMAL_ITEM;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- return Item::REAL_ITEM;
- default:
- return Item::STRING_ITEM;
- }
-}
-
-
bool Item_splocal::append_for_log(THD *thd, String *str)
{
if (fix_fields_if_needed(thd, NULL))
@@ -318,7 +291,7 @@ sp_get_flags_for_command(LEX *lex)
- EXPLAIN DELETE ...
- ANALYZE DELETE ...
*/
- if (lex->select_lex.item_list.is_empty() &&
+ if (lex->first_select_lex()->item_list.is_empty() &&
!lex->describe && !lex->analyze_stmt)
flags= 0;
else
@@ -1922,7 +1895,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
for (arg_no= 0; arg_no < argcount; arg_no++)
{
/* Arguments must be fixed in Item_func_sp::fix_fields */
- DBUG_ASSERT(argp[arg_no]->fixed);
+ DBUG_ASSERT(argp[arg_no]->is_fixed());
if ((err_status= (*func_ctx)->set_parameter(thd, arg_no, &(argp[arg_no]))))
goto err_with_cleanup;
@@ -2292,6 +2265,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!err_status)
{
err_status= execute(thd, TRUE);
+ DBUG_PRINT("info", ("execute returned %d", (int) err_status));
}
if (save_log_general)
@@ -4576,7 +4550,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp)
thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item))
{
/* If this also failed, we have to abort. */
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
}
}
else
diff --git a/sql/sp_head.h b/sql/sp_head.h
index cf934603cf0..8db6ecac9e7 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -39,9 +39,6 @@
@{
*/
-Item::Type
-sp_map_item_type(const Type_handler *handler);
-
uint
sp_get_flags_for_command(LEX *lex);
@@ -592,7 +589,8 @@ public:
if (!oldlex)
DBUG_RETURN(false); // Nothing to restore
LEX *sublex= thd->lex;
- if (thd->restore_from_local_lex_to_old_lex(oldlex))// This restores thd->lex
+ // This restores thd->lex and thd->stmt_lex
+ if (thd->restore_from_local_lex_to_old_lex(oldlex))
DBUG_RETURN(true);
if (!sublex->sp_lex_in_use)
{
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 24777abe1c3..a31631e33ef 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -228,9 +228,10 @@ bool Qualified_column_ident::resolve_type_ref(THD *thd, Column_definition *def)
// Make %TYPE variables see temporary tables that shadow permanent tables
thd->temporary_tables= open_tables_state_backup.temporary_tables;
- if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0,
- TL_READ_NO_INSERT,
- MDL_SHARED_READ)) &&
+ if ((table_list=
+ lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_READ)) &&
!check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) &&
!open_tables_only_view_structure(thd, table_list,
thd->mdl_context.has_locks()))
@@ -286,9 +287,10 @@ bool Table_ident::resolve_table_rowtype_ref(THD *thd,
// Make %ROWTYPE variables see temporary tables that shadow permanent tables
thd->temporary_tables= open_tables_state_backup.temporary_tables;
- if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0,
- TL_READ_NO_INSERT,
- MDL_SHARED_READ)) &&
+ if ((table_list=
+ lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0,
+ TL_READ_NO_INSERT,
+ MDL_SHARED_READ)) &&
!check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) &&
!open_tables_only_view_structure(thd, table_list,
thd->mdl_context.has_locks()))
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 21bb086f013..9f92af61eec 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -306,7 +306,7 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table,
bool is_view_operator_func)
{
LEX *lex= thd->lex;
- SELECT_LEX *select= &lex->select_lex;
+ SELECT_LEX *select= lex->first_select_lex();
TABLE_LIST *save_next_global, *save_next_local;
bool open_error;
save_next_global= table->next_global;
@@ -1301,7 +1301,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
bool Sql_cmd_analyze_table::execute(THD *thd)
{
LEX *m_lex= thd->lex;
- TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
bool res= TRUE;
thr_lock_type lock_type = TL_READ_NO_INSERT;
DBUG_ENTER("Sql_cmd_analyze_table::execute");
@@ -1321,7 +1321,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- m_lex->select_lex.table_list.first= first_table;
+ m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
error:
@@ -1332,7 +1332,7 @@ error:
bool Sql_cmd_check_table::execute(THD *thd)
{
LEX *m_lex= thd->lex;
- TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
thr_lock_type lock_type = TL_READ_NO_INSERT;
bool res= TRUE;
DBUG_ENTER("Sql_cmd_check_table::execute");
@@ -1345,7 +1345,7 @@ bool Sql_cmd_check_table::execute(THD *thd)
lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
&handler::ha_check, &view_check);
- m_lex->select_lex.table_list.first= first_table;
+ m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
error:
@@ -1356,7 +1356,7 @@ error:
bool Sql_cmd_optimize_table::execute(THD *thd)
{
LEX *m_lex= thd->lex;
- TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
bool res= TRUE;
DBUG_ENTER("Sql_cmd_optimize_table::execute");
@@ -1378,7 +1378,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- m_lex->select_lex.table_list.first= first_table;
+ m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
error:
@@ -1389,7 +1389,7 @@ error:
bool Sql_cmd_repair_table::execute(THD *thd)
{
LEX *m_lex= thd->lex;
- TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+ TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
bool res= TRUE;
DBUG_ENTER("Sql_cmd_repair_table::execute");
@@ -1413,7 +1413,7 @@ bool Sql_cmd_repair_table::execute(THD *thd)
*/
res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
}
- m_lex->select_lex.table_list.first= first_table;
+ m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
error:
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index a96b0a5a32b..700b4699430 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -356,7 +356,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
{
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
/*
@@ -506,7 +506,7 @@ error:
bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
{
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
/* first table of first SELECT_LEX */
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 6626a054052..a7cfaca0d0e 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -68,6 +68,25 @@ int compare_decimal2(int* len, const char *s, const char *t)
}
+static bool
+prepare_param(THD *thd, Item **item, const char *proc_name, uint pos)
+{
+ if ((*item)->fix_fields_if_needed(thd, item))
+ {
+ DBUG_PRINT("info", ("fix_fields() for the parameter %u failed", pos));
+ return true;
+ }
+ if ((*item)->type_handler()->result_type() != INT_RESULT ||
+ !(*item)->basic_const_item() ||
+ (*item)->val_real() < 0)
+ {
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
+ return true;
+ }
+ return false;
+}
+
+
Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list)
@@ -88,17 +107,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
else if (param->next)
{
// first parameter
- if ((*param->item)->fix_fields_if_needed(thd, param->item))
- {
- DBUG_PRINT("info", ("fix_fields() for the first parameter failed"));
- goto err;
- }
- if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val_real() < 0)
- {
- my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
+ if (prepare_param(thd, param->item, proc_name, 0))
goto err;
- }
pc->max_tree_elements = (uint) (*param->item)->val_int();
param = param->next;
if (param->next) // no third parameter possible
@@ -107,25 +117,12 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
goto err;
}
// second parameter
- if ((*param->item)->fix_fields_if_needed(thd, param->item))
- {
- DBUG_PRINT("info", ("fix_fields() for the second parameter failed"));
- goto err;
- }
- if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val_real() < 0)
- {
- my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
+ if (prepare_param(thd, param->item, proc_name, 1))
goto err;
- }
pc->max_treemem = (uint) (*param->item)->val_int();
}
- else if ((*param->item)->type() != Item::INT_ITEM ||
- (*param->item)->val_real() < 0)
- {
- my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
+ else if (prepare_param(thd, param->item, proc_name, 0))
goto err;
- }
// if only one parameter was given, it will be the value of max_tree_elements
else
{
@@ -481,30 +478,28 @@ void field_real::add()
void field_decimal::add()
{
/*TODO - remove rounding stuff after decimal_div returns proper frac */
- my_decimal dec_buf, *dec= item->val_decimal(&dec_buf);
- my_decimal rounded;
+ VDec vdec(item);
uint length;
TREE_ELEMENT *element;
- if (item->null_value)
+ if (vdec.is_null())
{
nulls++;
return;
}
- my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded);
- dec= &rounded;
+ my_decimal dec;
+ vdec.round_to(&dec, item->decimals, HALF_UP);
- length= my_decimal_string_length(dec);
+ length= my_decimal_string_length(&dec);
- if (decimal_is_zero(dec))
+ if (decimal_is_zero(&dec))
empty++;
if (room_in_tree)
{
uchar buf[DECIMAL_MAX_FIELD_SIZE];
- my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
- item->max_length, item->decimals);
+ dec.to_binary(buf, item->max_length, item->decimals);
if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
@@ -524,18 +519,18 @@ void field_decimal::add()
if (!found)
{
found = 1;
- min_arg = max_arg = sum[0] = *dec;
- my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
+ min_arg = max_arg = sum[0] = dec;
+ my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, &dec, &dec);
cur_sum= 0;
min_length = max_length = length;
}
- else if (!decimal_is_zero(dec))
+ else if (!decimal_is_zero(&dec))
{
int next_cur_sum= cur_sum ^ 1;
my_decimal sqr_buf;
- my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
- my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, &dec);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, &dec, &dec);
my_decimal_add(E_DEC_FATAL_ERROR,
sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
cur_sum= next_cur_sum;
@@ -543,13 +538,13 @@ void field_decimal::add()
min_length = length;
if (length > max_length)
max_length = length;
- if (my_decimal_cmp(dec, &min_arg) < 0)
+ if (dec.cmp(&min_arg) < 0)
{
- min_arg= *dec;
+ min_arg= dec;
}
- if (my_decimal_cmp(dec, &max_arg) > 0)
+ if (dec.cmp(&max_arg) > 0)
{
- max_arg= *dec;
+ max_arg= dec;
}
}
}
@@ -1003,7 +998,7 @@ void field_decimal::get_opt_type(String *answer,
uint length;
my_decimal_set_zero(&zero);
- my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
+ my_bool is_unsigned= (zero.cmp(&min_arg) >= 0);
length= sprintf(buff, "DECIMAL(%d, %d)",
(int) (max_length - (item->decimals ? 1 : 0)),
@@ -1016,14 +1011,14 @@ void field_decimal::get_opt_type(String *answer,
String *field_decimal::get_min_arg(String *str)
{
- my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
+ min_arg.to_string_native(str, 0, 0, '0');
return str;
}
String *field_decimal::get_max_arg(String *str)
{
- my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
+ max_arg.to_string_native(str, 0, 0, '0');
return str;
}
@@ -1041,10 +1036,10 @@ String *field_decimal::avg(String *s, ha_rows rows)
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment);
/* TODO remove this after decimal_div returns proper frac */
- my_decimal_round(E_DEC_FATAL_ERROR, &avg_val,
+ avg_val.round_to(&rounded_avg,
MY_MIN(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE),
- FALSE,&rounded_avg);
- my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s);
+ HALF_UP);
+ rounded_avg.to_string_native(s, 0, 0, '0');
return s;
}
@@ -1057,7 +1052,6 @@ String *field_decimal::std(String *s, ha_rows rows)
return s;
}
my_decimal num, tmp, sum2, sum2d;
- double std_sqr;
int prec_increment= current_thd->variables.div_precincrement;
int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
@@ -1065,7 +1059,7 @@ String *field_decimal::std(String *s, ha_rows rows)
my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp);
my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
- my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr);
+ double std_sqr= tmp.to_double();
s->set_real(((double) std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)),
MY_MIN(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset);
@@ -1117,12 +1111,9 @@ int collect_decimal(uchar *element, element_count count,
info->str->append(',');
else
info->found = 1;
- my_decimal dec;
- binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
- info->item->max_length, info->item->decimals);
-
+ my_decimal dec(element, info->item->max_length, info->item->decimals);
info->str->append('\'');
- my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
+ dec.to_string_native(&s, 0, 0, '0');
info->str->append(s);
info->str->append('\'');
return 0;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 15cfba80340..7327484469a 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -597,6 +597,7 @@ bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
+ DBUG_ENTER("mark_used_tables_as_free_for_reuse");
for (; table ; table= table->next)
{
DBUG_ASSERT(table->pos_in_locked_tables == NULL ||
@@ -607,6 +608,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
table->file->ha_reset();
}
}
+ DBUG_VOID_RETURN;
}
@@ -5424,43 +5426,27 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
DBUG_ENTER("update_field_dependencies");
if (should_mark_column(thd->column_usage))
{
- MY_BITMAP *bitmap;
-
/*
We always want to register the used keys, as the column bitmap may have
been set for all fields (for example for view).
*/
-
table->covering_keys.intersect(field->part_of_key);
- if (field->vcol_info)
- table->mark_virtual_col(field);
-
if (thd->column_usage == MARK_COLUMNS_READ)
- bitmap= table->read_set;
+ {
+ if (table->mark_column_with_deps(field))
+ DBUG_VOID_RETURN; // Field was already marked
+ }
else
- bitmap= table->write_set;
-
- /*
- The test-and-set mechanism in the bitmap is not reliable during
- multi-UPDATE statements under MARK_COLUMNS_READ mode
- (thd->column_usage == MARK_COLUMNS_READ), as this bitmap contains
- only those columns that are used in the SET clause. I.e they are being
- set here. See multi_update::prepare()
- */
- if (bitmap_fast_test_and_set(bitmap, field->field_index))
{
- if (thd->column_usage == MARK_COLUMNS_WRITE)
+ if (bitmap_fast_test_and_set(table->write_set, field->field_index))
{
DBUG_PRINT("warning", ("Found duplicated field"));
thd->dup_field= field;
+ DBUG_VOID_RETURN;
}
- else
- {
- DBUG_PRINT("note", ("Field found before"));
- }
- DBUG_VOID_RETURN;
}
+
table->used_fields++;
}
if (table->get_fields_in_item_tree)
@@ -7378,7 +7364,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
Item_window_func::split_sum_func.
*/
if (sum_func_list &&
- ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
+ ((item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) ||
item->with_window_func))
{
item->split_sum_func(thd, ref_pointer_array, *sum_func_list,
@@ -7486,7 +7472,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
TABLE_LIST *first_select_table= (select_insert ?
tables->next_local:
0);
- SELECT_LEX *select_lex= select_insert ? &thd->lex->select_lex :
+ SELECT_LEX *select_lex= select_insert ? thd->lex->first_select_lex() :
thd->lex->current_select;
if (select_lex->first_cond_optimization)
{
@@ -7514,7 +7500,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
{
/* new counting for SELECT of INSERT ... SELECT command */
first_select_table= 0;
- thd->lex->select_lex.insert_tables= tablenr;
+ thd->lex->first_select_lex()->insert_tables= tablenr;
tablenr= 0;
}
if(table_list->jtbm_subselect)
@@ -7881,18 +7867,9 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if ((field= field_iterator.field()))
{
- /* Mark fields as used to allow storage engine to optimze access */
- bitmap_set_bit(field->table->read_set, field->field_index);
- /*
- Mark virtual fields for write and others that the virtual fields
- depend on for read.
- */
- if (field->vcol_info)
- field->table->mark_virtual_col(field);
+ field->table->mark_column_with_deps(field);
if (table)
- {
table->covering_keys.intersect(field->part_of_key);
- }
if (tables->is_natural_join)
{
TABLE *field_table;
@@ -8070,7 +8047,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
from subquery of VIEW, because tables of subquery belongs to VIEW
(see condition before prepare_check_option() call)
*/
- bool it_is_update= (select_lex == &thd->lex->select_lex) &&
+ bool it_is_update= (select_lex == thd->lex->first_select_lex()) &&
thd->lex->which_check_option_applicable();
bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
TABLE_LIST *derived= select_lex->master_unit()->derived;
@@ -8086,7 +8063,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
for (table= tables; table; table= table->next_local)
{
- if (select_lex == &thd->lex->select_lex &&
+ if (select_lex == thd->lex->first_select_lex() &&
select_lex->first_cond_optimization &&
table->merged_for_insert &&
table->prepare_where(thd, conds, FALSE))
@@ -8693,7 +8670,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
Item_func_match *ifm;
while ((ifm=li++))
- if (unlikely(!ifm->fixed))
+ if (unlikely(!ifm->is_fixed()))
/*
it mean that clause where was FT function was removed, so we have
to remove the function from the list.
@@ -8795,6 +8772,13 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
void
close_system_tables(THD *thd, Open_tables_backup *backup)
{
+ /*
+ Inform the transaction handler that we are closing the
+ system tables and we don't need the read view anymore.
+ */
+ for (TABLE *table= thd->open_tables ; table ; table= table->next)
+ table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
+
close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
}
@@ -8928,7 +8912,7 @@ void unfix_fields(List<Item> &fields)
List_iterator<Item> li(fields);
Item *item;
while ((item= li++))
- item->fixed= 0;
+ item->unfix_fields();
}
diff --git a/sql/sql_base.h b/sql/sql_base.h
index be93566be09..59c849086e6 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -367,10 +367,12 @@ inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array,
bool allow_sum_func)
{
bool res;
- thd->lex->select_lex.no_wrap_view_item= TRUE;
+ SELECT_LEX *first= thd->lex->first_select_lex();
+ DBUG_ASSERT(thd->lex->current_select == first);
+ first->no_wrap_view_item= TRUE;
res= setup_fields(thd, ref_pointer_array, item, column_usage,
sum_func_list, NULL, allow_sum_func);
- thd->lex->select_lex.no_wrap_view_item= FALSE;
+ first->no_wrap_view_item= FALSE;
return res;
}
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 00270fb6f32..1fa3cca7c27 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -173,7 +173,7 @@ void mysql_client_binlog_statement(THD* thd)
*/
if (!(rli && buf))
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 1); /* needed 1 bytes */
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 1); /* needed 1 bytes */
goto end;
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index aa4c77d0939..44211fca506 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -480,8 +480,7 @@ static void make_base_query(String *new_query,
/* We do not support UCS2, UTF16, UTF32 as a client character set */
DBUG_ASSERT(current_thd->variables.character_set_client->mbminlen == 1);
- new_query->length(0); // Don't copy anything from old buffer
- if (new_query->realloc(query_length + additional_length))
+ if (new_query->alloc(query_length + additional_length))
{
/*
We could not allocate the query. Use original query for
@@ -4147,13 +4146,13 @@ Query_cache::is_cacheable(THD *thd, LEX *lex,
if (thd->lex->safe_to_cache_query &&
(thd->variables.query_cache_type == 1 ||
- (thd->variables.query_cache_type == 2 && (lex->select_lex.options &
- OPTION_TO_QUERY_CACHE))) &&
+ (thd->variables.query_cache_type == 2 &&
+ (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE))) &&
qc_is_able_to_intercept_result(thd))
{
DBUG_PRINT("qcache", ("options: %lx %lx type: %u",
(long) OPTION_TO_QUERY_CACHE,
- (long) lex->select_lex.options,
+ (long) lex->first_select_lex()->options,
(int) thd->variables.query_cache_type));
if (!(table_count= process_and_count_tables(thd, tables_used,
@@ -4174,7 +4173,7 @@ Query_cache::is_cacheable(THD *thd, LEX *lex,
("not interesting query: %d or not cacheable, options %lx %lx type: %u net->vio present: %u",
(int) lex->sql_command,
(long) OPTION_TO_QUERY_CACHE,
- (long) lex->select_lex.options,
+ (long) lex->first_select_lex()->options,
(int) thd->variables.query_cache_type,
(uint) MY_TEST(qc_is_able_to_intercept_result(thd))));
DBUG_RETURN(0);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fc96aa96278..0bbfdba88c7 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1406,7 +1406,7 @@ bool THD::set_db(const LEX_CSTRING *new_db)
const char *tmp= NULL;
if (new_db->str)
{
- if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATALERROR))))
+ if (!(tmp= my_strndup(new_db->str, new_db->length, MYF(MY_WME | ME_FATAL))))
result= 1;
}
@@ -2565,7 +2565,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, size_t key_length)
key_length + 1);
if (!new_table)
{
- my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_FATALERROR),
+ my_error(EE_OUTOFMEMORY, MYF(ME_FATAL),
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
set_killed(KILL_CONNECTION);
return 0;
@@ -3220,9 +3220,9 @@ int select_export::send_data(List<Item> &items)
((uint64) res->length() / res->charset()->mbminlen + 1) *
write_cs->mbmaxlen + 1;
set_if_smaller(estimated_bytes, UINT_MAX32);
- if (cvt_str.realloc((uint32) estimated_bytes))
+ if (cvt_str.alloc((uint32) estimated_bytes))
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), (uint32) estimated_bytes);
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), (uint32) estimated_bytes);
goto err;
}
@@ -3480,7 +3480,7 @@ int select_singlerow_subselect::send_data(List<Item> &items)
if (it->assigned())
{
my_message(ER_SUBQUERY_NO_1_ROW, ER_THD(thd, ER_SUBQUERY_NO_1_ROW),
- MYF(current_thd->lex->ignore ? ME_JUST_WARNING : 0));
+ MYF(current_thd->lex->ignore ? ME_WARNING : 0));
DBUG_RETURN(1);
}
if (unit->offset_limit_cnt)
@@ -3587,18 +3587,15 @@ bool select_max_min_finder_subselect::cmp_int()
bool select_max_min_finder_subselect::cmp_decimal()
{
Item *maxmin= ((Item_singlerow_subselect *)item)->element_index(0);
- my_decimal cval, *cvalue= cache->val_decimal(&cval);
- my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
+ VDec cvalue(cache), mvalue(maxmin);
/* Ignore NULLs for ANY and keep them for ALL subqueries */
- if (cache->null_value)
- return (is_all && !maxmin->null_value) || (!is_all && maxmin->null_value);
- if (maxmin->null_value)
+ if (cvalue.is_null())
+ return (is_all && !mvalue.is_null()) || (!is_all && mvalue.is_null());
+ if (mvalue.is_null())
return !is_all;
- if (fmax)
- return (my_decimal_cmp(cvalue, mvalue) > 0) ;
- return (my_decimal_cmp(cvalue,mvalue) < 0);
+ return fmax ? cvalue.cmp(mvalue) > 0 : cvalue.cmp(mvalue) < 0;
}
bool select_max_min_finder_subselect::cmp_str()
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 00a5c41f708..30622fde577 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -718,6 +718,7 @@ typedef struct system_variables
ulong session_track_transaction_info;
my_bool session_track_schema;
my_bool session_track_state_change;
+ my_bool tcp_nodelay;
ulong threadpool_priority;
@@ -3123,6 +3124,9 @@ public:
it returned an error on master, and this is OK on the slave.
*/
bool is_slave_error;
+ /* True if we have printed something to the error log for this statement */
+ bool error_printed_to_log;
+
/*
True when a transaction is queued up for binlog group commit.
Used so that if another transaction needs to wait for a row lock held by
@@ -4372,6 +4376,69 @@ private:
return raised;
}
+private:
+ void push_warning_truncated_priv(Sql_condition::enum_warning_level level,
+ uint sql_errno,
+ const char *type_str, const char *val)
+ {
+ DBUG_ASSERT(sql_errno == ER_TRUNCATED_WRONG_VALUE ||
+ sql_errno == ER_WRONG_VALUE);
+ char buff[MYSQL_ERRMSG_SIZE];
+ CHARSET_INFO *cs= &my_charset_latin1;
+ cs->cset->snprintf(cs, buff, sizeof(buff),
+ ER_THD(this, sql_errno), type_str, val);
+ /*
+ Note: the format string can vary between ER_TRUNCATED_WRONG_VALUE
+ and ER_WRONG_VALUE, but the code passed to push_warning() is
+ always ER_TRUNCATED_WRONG_VALUE. This is intentional.
+ */
+ push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff);
+ }
+public:
+ void push_warning_truncated_wrong_value(Sql_condition::enum_warning_level level,
+ const char *type_str, const char *val)
+ {
+ return push_warning_truncated_priv(level, ER_TRUNCATED_WRONG_VALUE,
+ type_str, val);
+ }
+ void push_warning_wrong_value(Sql_condition::enum_warning_level level,
+ const char *type_str, const char *val)
+ {
+ return push_warning_truncated_priv(level, ER_WRONG_VALUE, type_str, val);
+ }
+ void push_warning_truncated_wrong_value(const char *type_str, const char *val)
+ {
+ return push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ type_str, val);
+ }
+ void push_warning_truncated_value_for_field(Sql_condition::enum_warning_level
+ level, const char *type_str,
+ const char *val, const char *name)
+ {
+ DBUG_ASSERT(name);
+ char buff[MYSQL_ERRMSG_SIZE];
+ CHARSET_INFO *cs= &my_charset_latin1;
+ cs->cset->snprintf(cs, buff, sizeof(buff),
+ ER_THD(this, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ type_str, val, name,
+ (ulong) get_stmt_da()->current_row_for_warning());
+ push_warning(this, level, ER_TRUNCATED_WRONG_VALUE, buff);
+
+ }
+ void push_warning_wrong_or_truncated_value(Sql_condition::enum_warning_level level,
+ bool totally_useless_value,
+ const char *type_str,
+ const char *val,
+ const char *field_name)
+ {
+ if (field_name)
+ push_warning_truncated_value_for_field(level, type_str, val, field_name);
+ else if (totally_useless_value)
+ push_warning_wrong_value(level, type_str, val);
+ else
+ push_warning_truncated_wrong_value(level, type_str, val);
+ }
+
public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
@@ -6318,7 +6385,8 @@ public:
inline bool add_item_to_list(THD *thd, Item *item)
{
- return thd->lex->current_select->add_item_to_list(thd, item);
+ bool res= thd->lex->current_select->add_item_to_list(thd, item);
+ return res;
}
inline bool add_value_to_list(THD *thd, Item *value)
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 97bbf8f73bd..a518f991892 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -55,6 +55,14 @@ bool With_clause::add_with_element(With_element *elem)
}
+void st_select_lex_unit::set_with_clause(With_clause *with_cl)
+{
+ with_clause= with_cl;
+ if (with_clause)
+ with_clause->set_owner(this);
+}
+
+
/**
@brief
Check dependencies between tables defined in a list of with clauses
@@ -682,7 +690,7 @@ void With_element::move_anchors_ahead()
{
st_select_lex *next_sl;
st_select_lex *new_pos= spec->first_select();
- new_pos->linkage= UNION_TYPE;
+ new_pos->set_linkage(UNION_TYPE);
for (st_select_lex *sl= new_pos; sl; sl= next_sl)
{
next_sl= sl->next_select();
@@ -691,9 +699,9 @@ void With_element::move_anchors_ahead()
sl->move_node(new_pos);
if (new_pos == spec->first_select())
{
- enum sub_select_type type= new_pos->linkage;
- new_pos->linkage= sl->linkage;
- sl->linkage= type;
+ enum sub_select_type type= new_pos->get_linkage();
+ new_pos->set_linkage(sl->get_linkage());
+ sl->set_linkage(type);
new_pos->with_all_modifier= sl->with_all_modifier;
sl->with_all_modifier= false;
}
@@ -764,7 +772,7 @@ bool With_element::set_unparsed_spec(THD *thd, char *spec_start, char *spec_end)
if (!unparsed_spec.str)
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR),
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL),
static_cast<int>(unparsed_spec.length));
return true;
}
@@ -834,9 +842,8 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
goto err;
lex_start(thd);
lex->stmt_lex= old_lex;
- with_select= &lex->select_lex;
- with_select->select_number= ++thd->lex->stmt_lex->current_select_number;
parse_status= parse_sql(thd, &parser_state, 0);
+ with_select= lex->first_select_lex();
if (parse_status)
goto err;
@@ -987,7 +994,7 @@ bool With_element::prepare_unreferenced(THD *thd)
rename_columns_of_derived_unit(thd, spec) ||
check_duplicate_names(thd, first_sl->item_list, 1)))
rc= true;
-
+
thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED;
return rc;
}
@@ -1098,7 +1105,8 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem)
if(!(derived= with_elem->clone_parsed_spec(thd, this)))
return true;
}
- derived->first_select()->linkage= DERIVED_TABLE_TYPE;
+ derived->first_select()->set_linkage(DERIVED_TABLE_TYPE);
+ select_lex->add_statistics(derived);
with_elem->inc_references();
return false;
}
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index 16b473f0665..4a194b2a38f 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -279,8 +279,7 @@ private:
*/
With_clause *next_with_clause;
/* Set to true if dependencies between with elements have been checked */
- bool dependencies_are_checked;
-
+ bool dependencies_are_checked;
/*
The bitmap of all recursive with elements whose specifications
are not complied with restrictions imposed by the SQL standards
@@ -304,9 +303,8 @@ public:
bool with_recursive;
With_clause(bool recursive_fl, With_clause *emb_with_clause)
- : owner(NULL),
- embedding_with_clause(emb_with_clause), next_with_clause(NULL),
- dependencies_are_checked(false), unrestricted(0),
+ : owner(NULL), embedding_with_clause(emb_with_clause),
+ next_with_clause(NULL), dependencies_are_checked(false), unrestricted(0),
with_prepared_anchor(0), cleaned(0), stabilized(0),
with_recursive(recursive_fl)
{ }
@@ -320,8 +318,12 @@ public:
last_next= &this->next_with_clause;
}
+ st_select_lex_unit *get_owner() { return owner; }
+
void set_owner(st_select_lex_unit *unit) { owner= unit; }
+ void attach_to(st_select_lex *select_lex);
+
With_clause *pop() { return embedding_with_clause; }
bool check_dependencies();
@@ -354,7 +356,6 @@ bool With_element::is_unrestricted()
}
inline
-
bool With_element::is_with_prepared_anchor()
{
return owner->with_prepared_anchor & get_elem_map();
@@ -436,11 +437,14 @@ void With_element::prepare_for_next_iteration()
inline
-void st_select_lex_unit::set_with_clause(With_clause *with_cl)
-{
- with_clause= with_cl;
- if (with_clause)
- with_clause->set_owner(this);
+void With_clause::attach_to(st_select_lex *select_lex)
+{
+ for (With_element *with_elem= with_list.first;
+ with_elem;
+ with_elem= with_elem->next)
+ {
+ select_lex->register_unit(with_elem->spec, NULL);
+ }
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index a040ba9eb93..326f2a64bbe 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -290,7 +290,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
bool has_triggers;
ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
order_list->first : NULL);
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
killed_state killed_status= NOT_KILLED;
THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
bool binlog_is_row;
@@ -352,7 +352,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
DBUG_RETURN(TRUE);
}
table->map=1;
- query_plan.select_lex= &thd->lex->select_lex;
+ query_plan.select_lex= thd->lex->first_select_lex();
query_plan.table= table;
query_plan.updating_a_view= MY_TEST(table_list->view);
@@ -384,7 +384,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
setup_order(thd, select_lex->ref_pointer_array, &tables,
fields, all_fields, order))
{
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, thd->lex->first_select_lex());
DBUG_RETURN(TRUE);
}
}
@@ -770,7 +770,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else
{
table->file->print_error(error,
- MYF(thd->lex->ignore ? ME_JUST_WARNING : 0));
+ MYF(thd->lex->ignore ? ME_WARNING : 0));
if (thd->is_error())
{
error= 1;
@@ -931,14 +931,16 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list,
bool *delete_while_scanning)
{
Item *fake_conds= 0;
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
DBUG_ENTER("mysql_prepare_delete");
List<Item> all_fields;
*delete_while_scanning= true;
thd->lex->allow_sum_func= 0;
- if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
+ if (setup_tables_and_check_access(thd,
+ &thd->lex->first_select_lex()->context,
+ &thd->lex->first_select_lex()->
+ top_join_list,
table_list,
select_lex->leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE))
@@ -1021,21 +1023,23 @@ int mysql_multi_delete_prepare(THD *thd)
lex->query_tables also point on local list of DELETE SELECT_LEX
*/
- if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
+ if (setup_tables_and_check_access(thd,
+ &thd->lex->first_select_lex()->context,
+ &thd->lex->first_select_lex()->
+ top_join_list,
lex->query_tables,
- lex->select_lex.leaf_tables, FALSE,
- DELETE_ACL, SELECT_ACL, FALSE))
+ lex->first_select_lex()->leaf_tables,
+ FALSE, DELETE_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(TRUE);
- if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
+ if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
/*
Multi-delete can't be constructed over-union => we always have
single SELECT on top and have to check underlying SELECTs of it
*/
- lex->select_lex.exclude_from_table_unique_test= TRUE;
+ lex->first_select_lex()->exclude_from_table_unique_test= TRUE;
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (target_tbl= (TABLE_LIST*) aux_tables;
target_tbl;
@@ -1077,8 +1081,8 @@ int mysql_multi_delete_prepare(THD *thd)
Reset the exclude flag to false so it doesn't interfare
with further calls to unique_table
*/
- lex->select_lex.exclude_from_table_unique_test= FALSE;
-
+ lex->first_select_lex()->exclude_from_table_unique_test= FALSE;
+
if (lex->save_prep_leaf_tables())
DBUG_RETURN(TRUE);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 6a2e956fbf3..d65969d2160 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -99,7 +99,8 @@ mysql_handle_derived(LEX *lex, uint phases)
processed normally.
*/
if (phases == DT_MERGE_FOR_INSERT &&
- cursor && cursor->top_table()->select_lex != &lex->select_lex)
+ cursor && (cursor->top_table()->select_lex !=
+ lex->first_select_lex()))
continue;
for (;
cursor && !res;
@@ -1239,25 +1240,61 @@ bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived)
/**
@brief
- Extract the condition depended on derived table/view and pushed it there
+ Extract condition that can be pushed into a derived table/view
- @param thd The thread handle
- @param cond The condition from which to extract the pushed condition
- @param derived The reference to the derived table/view
+ @param thd the thread handle
+ @param cond current condition
+ @param derived the reference to the derived table/view
@details
- This functiom builds the most restrictive condition depending only on
- the derived table/view that can be extracted from the condition cond.
- The built condition is pushed into the having clauses of the
- selects contained in the query specifying the derived table/view.
- The function also checks for each select whether any condition depending
- only on grouping fields can be extracted from the pushed condition.
- If so, it pushes the condition over grouping fields into the where
- clause of the select.
-
- @retval
- true if an error is reported
- false otherwise
+ This function builds the most restrictive condition depending only on
+ the derived table/view (directly or indirectly through equality) that
+ can be extracted from the given condition cond and pushes it into the
+ derived table/view.
+
+ Example of the transformation:
+
+ SELECT *
+ FROM t1,
+ (
+ SELECT x,MAX(y) AS max_y
+ FROM t2
+ GROUP BY x
+ ) AS d_tab
+ WHERE d_tab.x>1 AND d_tab.max_y<30;
+
+ =>
+
+ SELECT *
+ FROM t1,
+ (
+ SELECT x,z,MAX(y) AS max_y
+ FROM t2
+ WHERE x>1
+ HAVING max_y<30
+ GROUP BY x
+ ) AS d_tab
+ WHERE d_tab.x>1 AND d_tab.max_y<30;
+
+ In details:
+ 1. Check what pushable formula can be extracted from cond
+ 2. Build a clone PC of the formula that can be extracted
+ (the clone is built only if the extracted formula is a AND subformula
+ of cond or conjunction of such subformulas)
+ Do for every select specifying derived table/view:
+ 3. If there is no HAVING clause prepare PC to be conjuncted with
+ WHERE clause of the select. Otherwise do 4-7.
+ 4. Check what formula PC_where can be extracted from PC to be pushed
+ into the WHERE clause of the select
+ 5. Build PC_where and if PC_where is a conjunct(s) of PC remove it from PC
+ getting PC_having
+ 6. Prepare PC_where to be conjuncted with the WHERE clause of the select
+ 7. Prepare PC_having to be conjuncted with the HAVING clause of the select
+ @note
+ This method is similar to pushdown_cond_for_in_subquery()
+
+ @retval TRUE if an error occurs
+ @retval FALSE otherwise
*/
bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
@@ -1297,63 +1334,25 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!some_select_allows_cond_pushdown)
DBUG_RETURN(false);
- /*
- Build the most restrictive condition extractable from 'cond'
- that can be pushed into the derived table 'derived'.
- All subexpressions of this condition are cloned from the
- subexpressions of 'cond'.
- This condition has to be fixed yet.
- */
+ /* 1. Check what pushable formula can be extracted from cond */
Item *extracted_cond;
- derived->check_pushable_cond_for_table(cond);
- extracted_cond= derived->build_pushable_cond_for_table(thd, cond);
+ cond->check_pushable_cond(&Item::pushable_cond_checker_for_derived,
+ (uchar *)(&derived->table->map));
+ /* 2. Build a clone PC of the formula that can be extracted */
+ extracted_cond=
+ cond->build_pushable_cond(thd,
+ &Item::pushable_equality_checker_for_derived,
+ ((uchar *)&derived->table->map));
if (!extracted_cond)
{
/* Nothing can be pushed into the derived table */
DBUG_RETURN(false);
}
- /* Push extracted_cond into every select of the unit specifying 'derived' */
+
st_select_lex *save_curr_select= thd->lex->current_select;
for (; sl; sl= sl->next_select())
{
Item *extracted_cond_copy;
- if (!sl->cond_pushdown_is_allowed())
- continue;
- thd->lex->current_select= sl;
- if (sl->have_window_funcs())
- {
- if (sl->join->group_list || sl->join->implicit_grouping)
- continue;
- ORDER *common_partition_fields=
- sl->find_common_window_func_partition_fields(thd);
- if (!common_partition_fields)
- continue;
- extracted_cond_copy= !sl->next_select() ?
- extracted_cond :
- extracted_cond->build_clone(thd);
- if (!extracted_cond_copy)
- continue;
-
- Item *cond_over_partition_fields;;
- sl->collect_grouping_fields(thd, common_partition_fields);
- sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
- derived);
- cond_over_partition_fields=
- sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
- if (cond_over_partition_fields)
- cond_over_partition_fields= cond_over_partition_fields->transform(thd,
- &Item::derived_grouping_field_transformer_for_where,
- (uchar*) sl);
- if (cond_over_partition_fields)
- {
- cond_over_partition_fields->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- sl->cond_pushed_into_where= cond_over_partition_fields;
- }
-
- continue;
- }
-
/*
For each select of the unit except the last one
create a clone of extracted_cond
@@ -1364,73 +1363,44 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
if (!extracted_cond_copy)
continue;
- if (!sl->join->group_list && !sl->with_sum_func)
- {
- /* extracted_cond_copy is pushed into where of sl */
- extracted_cond_copy= extracted_cond_copy->transform(thd,
- &Item::derived_field_transformer_for_where,
- (uchar*) sl);
- if (extracted_cond_copy)
- {
- extracted_cond_copy->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- sl->cond_pushed_into_where= extracted_cond_copy;
- }
-
- continue;
- }
-
- /*
- Figure out what can be extracted from the pushed condition
- that could be pushed into the where clause of sl
- */
- Item *cond_over_grouping_fields;
- sl->collect_grouping_fields(thd, sl->join->group_list);
- sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
- derived);
- cond_over_grouping_fields=
- sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
-
- /*
- Transform the references to the 'derived' columns from the condition
- pushed into the where clause of sl to make them usable in the new context
- */
- if (cond_over_grouping_fields)
- cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
- &Item::derived_grouping_field_transformer_for_where,
- (uchar*) sl);
-
- if (cond_over_grouping_fields)
+ /* Collect fields that are used in the GROUP BY of sl */
+ if (sl->have_window_funcs())
{
- /*
- In extracted_cond_copy remove top conjuncts that
- has been pushed into the where clause of sl
- */
- extracted_cond_copy= remove_pushed_top_conjuncts(thd, extracted_cond_copy);
-
- cond_over_grouping_fields->walk(
- &Item::cleanup_excluding_const_fields_processor, 0, 0);
- sl->cond_pushed_into_where= cond_over_grouping_fields;
-
- if (!extracted_cond_copy)
+ if (sl->group_list.first || sl->join->implicit_grouping)
+ continue;
+ ORDER *common_partition_fields=
+ sl->find_common_window_func_partition_fields(thd);
+ if (!common_partition_fields)
continue;
+ sl->collect_grouping_fields(thd, common_partition_fields);
}
+ else
+ sl->collect_grouping_fields(thd, sl->group_list.first);
+
+ Item *remaining_cond= NULL;
+ /* Do 4-6 */
+ sl->pushdown_cond_into_where_clause(thd, extracted_cond_copy,
+ &remaining_cond,
+ &Item::derived_field_transformer_for_where,
+ (uchar *) sl);
+ if (!remaining_cond)
+ continue;
/*
- Transform the references to the 'derived' columns from the condition
- pushed into the having clause of sl to make them usable in the new context
+ 7. Prepare PC_having to be conjuncted with the HAVING clause of
+ the select
*/
- extracted_cond_copy= extracted_cond_copy->transform(thd,
- &Item::derived_field_transformer_for_having,
- (uchar*) sl);
- if (!extracted_cond_copy)
+ remaining_cond=
+ remaining_cond->transform(thd,
+ &Item::derived_field_transformer_for_having,
+ (uchar *) sl);
+ if (!remaining_cond)
continue;
- extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor,
- 0, 0);
- sl->cond_pushed_into_having= extracted_cond_copy;
+ remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor,
+ 0, 0);
+ sl->cond_pushed_into_having= remaining_cond;
}
thd->lex->current_select= save_curr_select;
DBUG_RETURN(false);
}
-
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 2a4e43ab78a..1652b313909 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -33,7 +33,7 @@ bool mysql_do(THD *thd, List<Item> &values)
DBUG_RETURN(TRUE);
while ((value = li++))
(void) value->is_null();
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, thd->lex->first_select_lex());
if (unlikely(thd->is_error()))
{
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index d6f5b99eef6..8d639f9271d 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -781,7 +781,7 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
List<Item> field_list;
MEM_ROOT *mem_root= thd->mem_root;
const Sql_condition *err;
- SELECT_LEX *sel= &thd->lex->select_lex;
+ SELECT_LEX *sel= thd->lex->first_select_lex();
SELECT_LEX_UNIT *unit= &thd->lex->unit;
ulonglong idx= 0;
Protocol *protocol=thd->protocol;
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 69ea04a170c..72df8367dc7 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -433,8 +433,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
/* Always read all columns */
table->read_set= &table->s->all_set;
- if (table->vcol_set)
- table->vcol_set= &table->s->all_set;
/* Restore the state. */
thd->set_open_tables(backup_open_tables);
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index aa9f3fedd6d..95bc6ade366 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -87,7 +87,7 @@ enum enum_used_fields
static bool init_fields(THD *thd, TABLE_LIST *tables,
struct st_find_field *find_fields, uint count)
{
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
DBUG_ENTER("init_fields");
context->resolve_in_table_list_only(tables);
for (; count-- ; find_fields++)
@@ -719,10 +719,11 @@ static bool mysqld_help_internal(THD *thd, const char *mask)
Init tables and fields to be usable from items
tables do not contain VIEWs => we can pass 0 as conds
*/
- thd->lex->select_lex.context.table_list=
- thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
- if (setup_tables(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
+ thd->lex->first_select_lex()->context.table_list=
+ thd->lex->first_select_lex()->context.first_name_resolution_table=
+ &tables[0];
+ if (setup_tables(thd, &thd->lex->first_select_lex()->context,
+ &thd->lex->first_select_lex()->top_join_list,
tables, leaves, FALSE, FALSE))
goto error;
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 52a465f7613..51acf10a98a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -241,7 +241,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
}
else
{ // Part field list
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
Name_resolution_context *context= &select_lex->context;
Name_resolution_context_state ctx_state;
int res;
@@ -273,7 +273,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
- thd->lex->select_lex.no_wrap_view_item= FALSE;
+ thd->lex->first_select_lex()->no_wrap_view_item= FALSE;
if (res)
DBUG_RETURN(-1);
@@ -657,7 +657,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
bool skip= MY_TEST(table_list->view);
/* Save subquery children */
- for (SELECT_LEX_UNIT *unit= thd->lex->select_lex.first_inner_unit();
+ for (SELECT_LEX_UNIT *unit= thd->lex->first_select_lex()->first_inner_unit();
unit;
unit= unit->next_unit())
{
@@ -777,7 +777,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* mysql_prepare_insert sets table_list->table if it was not set */
table= table_list->table;
- context= &thd->lex->select_lex.context;
+ context= &thd->lex->first_select_lex()->context;
/*
These three asserts test the hypothesis that the resetting of the name
resolution context below is not necessary at all since the list of local
@@ -1070,7 +1070,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
} while (bulk_parameters_iterations(thd));
values_loop_end:
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, thd->lex->first_select_lex());
joins_freed= TRUE;
/*
@@ -1259,7 +1259,7 @@ abort:
table->file->ha_release_auto_increment();
if (!joins_freed)
- free_underlaid_joins(thd, &thd->lex->select_lex);
+ free_underlaid_joins(thd, thd->lex->first_select_lex());
thd->abort_on_warning= 0;
DBUG_RETURN(retval);
}
@@ -1289,7 +1289,7 @@ abort:
static bool check_view_insertability(THD * thd, TABLE_LIST *view)
{
- uint num= view->view->select_lex.item_list.elements;
+ uint num= view->view->first_select_lex()->item_list.elements;
TABLE *table= view->table;
Field_translator *trans_start= view->field_translation,
*trans_end= trans_start + num;
@@ -1389,10 +1389,12 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
than INSERT.
*/
- if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
+ if (setup_tables_and_check_access(thd,
+ &thd->lex->first_select_lex()->context,
+ &thd->lex->first_select_lex()->
+ top_join_list,
table_list,
- thd->lex->select_lex.leaf_tables,
+ thd->lex->first_select_lex()->leaf_tables,
select_insert, INSERT_ACL, SELECT_ACL,
TRUE))
DBUG_RETURN(TRUE);
@@ -1400,7 +1402,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
if (insert_into_view && !fields.elements)
{
thd->lex->empty_field_list_on_rset= 1;
- if (!thd->lex->select_lex.leaf_tables.head()->table ||
+ if (!thd->lex->first_select_lex()->leaf_tables.head()->table ||
table_list->is_multitable())
{
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
@@ -1474,7 +1476,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
enum_duplicates duplic, COND **where,
bool select_insert)
{
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
Name_resolution_context *context= &select_lex->context;
Name_resolution_context_state ctx_state;
bool insert_into_view= (table_list->view != 0);
@@ -1719,7 +1721,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
*/
if (info->ignore)
{
- table->file->print_error(error, MYF(ME_JUST_WARNING));
+ table->file->print_error(error, MYF(ME_WARNING));
goto ok_or_after_trg_err; /* Ignoring a not fatal error, return 0 */
}
goto err;
@@ -1844,7 +1846,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
{
if (!(thd->variables.old_behavior &
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
- table->file->print_error(error, MYF(ME_JUST_WARNING));
+ table->file->print_error(error, MYF(ME_WARNING));
goto ok_or_after_trg_err;
}
goto err;
@@ -2025,7 +2027,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err;
if (!(thd->variables.old_behavior &
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
- table->file->print_error(error, MYF(ME_JUST_WARNING));
+ table->file->print_error(error, MYF(ME_WARNING));
table->file->restore_auto_increment(prev_insert_id);
goto ok_or_after_trg_err;
}
@@ -2359,7 +2361,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
di->thd.set_db(&table_list->db);
di->thd.set_query(my_strndup(table_list->table_name.str,
table_list->table_name.length,
- MYF(MY_WME | ME_FATALERROR)),
+ MYF(MY_WME | ME_FATAL)),
table_list->table_name.length, system_charset_info);
if (di->thd.db.str == NULL || di->thd.query() == NULL)
{
@@ -2391,7 +2393,7 @@ bool delayed_get_table(THD *thd, MDL_request *grl_protection_request,
mysql_mutex_unlock(&di->mutex);
di->unlock();
delete di;
- my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error);
+ my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATAL), error);
goto end_create;
}
@@ -2604,10 +2606,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
share->default_fields)
{
bool error_reported= FALSE;
- if (unlikely(!(copy->def_vcol_set=
- (MY_BITMAP*) alloc_root(client_thd->mem_root,
- sizeof(MY_BITMAP)))))
- goto error;
if (unlikely(parse_vcol_defs(client_thd, client_thd->mem_root, copy,
&error_reported)))
goto error;
@@ -2626,15 +2624,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
copy->def_write_set.bitmap= ((my_bitmap_map*)
(bitmap + share->column_bitmap_size));
bitmaps_used= 2;
- if (share->virtual_fields)
- {
- my_bitmap_init(copy->def_vcol_set,
- (my_bitmap_map*) (bitmap +
- bitmaps_used*share->column_bitmap_size),
- share->fields, FALSE);
- bitmaps_used++;
- copy->vcol_set= copy->def_vcol_set;
- }
if (share->default_fields || share->default_expressions)
{
my_bitmap_init(&copy->has_value_set,
@@ -3260,7 +3249,7 @@ bool Delayed_insert::handle_inserts(void)
or if another thread is removing the current table definition
from the table cache.
*/
- my_error(ER_DELAYED_CANT_CHANGE_LOCK, MYF(ME_FATALERROR | ME_NOREFRESH),
+ my_error(ER_DELAYED_CANT_CHANGE_LOCK, MYF(ME_FATAL | ME_ERROR_LOG),
table->s->table_name.str);
goto err;
}
@@ -3433,7 +3422,7 @@ bool Delayed_insert::handle_inserts(void)
{
/* This is not known to happen. */
my_error(ER_DELAYED_CANT_CHANGE_LOCK,
- MYF(ME_FATALERROR | ME_NOREFRESH),
+ MYF(ME_FATAL | ME_ERROR_LOG),
table->s->table_name.str);
goto err;
}
@@ -3529,7 +3518,7 @@ bool Delayed_insert::handle_inserts(void)
bool mysql_insert_select_prepare(THD *thd)
{
LEX *lex= thd->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
DBUG_ENTER("mysql_insert_select_prepare");
@@ -3618,7 +3607,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
select, LEX::current_select should point to the first select while
we are fixing fields from insert list.
*/
- lex->current_select= &lex->select_lex;
+ lex->current_select= lex->first_select_lex();
res= (setup_fields(thd, Ref_ptr_array(),
values, MARK_COLUMNS_READ, 0, NULL, 0) ||
@@ -3635,7 +3624,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (info.handle_duplicates == DUP_UPDATE && !res)
{
- Name_resolution_context *context= &lex->select_lex.context;
+ Name_resolution_context *context= &lex->first_select_lex()->context;
Name_resolution_context_state ctx_state;
/* Save the state of the current name resolution context. */
@@ -3645,7 +3634,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- lex->select_lex.no_wrap_view_item= TRUE;
+ lex->first_select_lex()->no_wrap_view_item= TRUE;
res= res ||
check_update_fields(thd, context->table_list,
*info.update_fields, *info.update_values,
@@ -3656,15 +3645,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
*/
true,
&map);
- lex->select_lex.no_wrap_view_item= FALSE;
+ lex->first_select_lex()->no_wrap_view_item= FALSE;
/*
When we are not using GROUP BY and there are no ungrouped aggregate functions
we can refer to other tables in the ON DUPLICATE KEY part.
We use next_name_resolution_table descructively, so check it first (views?)
*/
DBUG_ASSERT (!table_list->next_name_resolution_table);
- if (lex->select_lex.group_list.elements == 0 &&
- !lex->select_lex.with_sum_func)
+ if (lex->first_select_lex()->group_list.elements == 0 &&
+ !lex->first_select_lex()->with_sum_func)
/*
We must make a single context out of the two separate name resolution contexts :
the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
@@ -4080,9 +4069,9 @@ void select_insert::abort_result_set() {
Field *Item::create_field_for_create_select(TABLE *table)
{
- Field *def_field, *tmp_field;
- return ::create_tmp_field(table->in_use, table, this, type(),
- (Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0);
+ static Tmp_field_param param(false, false, false, false);
+ Tmp_field_src src;
+ return create_tmp_field_ex(table, &src, &param);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 1b1031d440b..bff6dfb0e05 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -174,7 +174,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
{
TABLE_LIST *table_list;
Table_ident *table_ident;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
Name_resolution_context *context= &select_lex->context;
/*
We will call the parser to create a part_info struct based on the
@@ -635,6 +635,30 @@ void Lex_input_stream::reduce_digest_token(uint token_left, uint token_right)
}
}
+/**
+ lex starting operations for builtin select collected together
+*/
+
+void SELECT_LEX::lex_start(LEX *plex)
+{
+ SELECT_LEX_UNIT *unit= &plex->unit;
+ /* 'parent_lex' is used in init_query() so it must be before it. */
+ parent_lex= plex;
+ init_query();
+ master= unit;
+ prev= &unit->slave;
+ link_next= slave= next= 0;
+ link_prev= (st_select_lex_node**)&(plex->all_selects_list);
+ DBUG_ASSERT(!group_list_ptrs);
+ select_number= 1;
+ in_sum_expr=0;
+ ftfunc_list_alloc.empty();
+ ftfunc_list= &ftfunc_list_alloc;
+ group_list.empty();
+ order_list.empty();
+ gorder_list.empty();
+}
+
void lex_start(THD *thd)
{
DBUG_ENTER("lex_start");
@@ -659,17 +683,18 @@ void LEX::start(THD *thd_arg)
DBUG_ASSERT(!explain);
+ builtin_select.lex_start(this);
+ lex_options= 0;
context_stack.empty();
+ //empty select_stack
+ select_stack_top= 0;
unit.init_query();
- current_select_number= 1;
- select_lex.linkage= UNSPECIFIED_TYPE;
- /* 'parent_lex' is used in init_query() so it must be before it. */
- select_lex.parent_lex= this;
- select_lex.init_query();
+ current_select_number= 0;
curr_with_clause= 0;
with_clauses_list= 0;
with_clauses_list_last_next= &with_clauses_list;
create_view= NULL;
+ field_list.empty();
value_list.empty();
update_list.empty();
set_var_list.empty();
@@ -683,17 +708,8 @@ void LEX::start(THD *thd_arg)
auxiliary_table_list.empty();
unit.next= unit.master= unit.link_next= unit.return_to= 0;
unit.prev= unit.link_prev= 0;
- unit.slave= current_select= all_selects_list= &select_lex;
- select_lex.master= &unit;
- select_lex.prev= &unit.slave;
- select_lex.link_next= select_lex.slave= select_lex.next= 0;
- select_lex.link_prev= (st_select_lex_node**)&(all_selects_list);
- select_lex.options= 0;
- select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
- select_lex.init_order();
- select_lex.group_list.empty();
- if (select_lex.group_list_ptrs)
- select_lex.group_list_ptrs->clear();
+ unit.slave= current_select= all_selects_list= &builtin_select;
+ sql_cache= LEX::SQL_CACHE_UNSPECIFIED;
describe= 0;
analyze_stmt= 0;
explain_json= false;
@@ -703,14 +719,7 @@ void LEX::start(THD *thd_arg)
safe_to_cache_query= 1;
parsing_options.reset();
empty_field_list_on_rset= 0;
- select_lex.select_number= 1;
part_info= 0;
- select_lex.in_sum_expr=0;
- select_lex.ftfunc_list_alloc.empty();
- select_lex.ftfunc_list= &select_lex.ftfunc_list_alloc;
- select_lex.group_list.empty();
- select_lex.order_list.empty();
- select_lex.gorder_list.empty();
m_sql_cmd= NULL;
duplicates= DUP_ERROR;
ignore= 0;
@@ -722,6 +731,8 @@ void LEX::start(THD *thd_arg)
query_tables= 0;
reset_query_tables_list(FALSE);
expr_allows_subselect= TRUE;
+ selects_allow_into= FALSE;
+ selects_allow_procedure= FALSE;
use_only_table_context= FALSE;
parse_vcol_expr= FALSE;
check_exists= FALSE;
@@ -731,8 +742,8 @@ void LEX::start(THD *thd_arg)
name= null_clex_str;
event_parse_data= NULL;
profile_options= PROFILE_NONE;
- nest_level=0 ;
- select_lex.nest_level_base= &unit;
+ nest_level= 0;
+ builtin_select.nest_level_base= &unit;
allow_sum_func= 0;
in_sum_func= NULL;
@@ -756,6 +767,13 @@ void LEX::start(THD *thd_arg)
vers_conditions.empty();
is_lex_started= TRUE;
+
+ next_is_main= FALSE;
+ next_is_down= FALSE;
+
+ wild= 0;
+ exchange= 0;
+
DBUG_VOID_RETURN;
}
@@ -1272,7 +1290,8 @@ int ORAlex(YYSTYPE *yylval, THD *thd)
int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
{
int token;
-
+ const int left_paren= (int) '(';
+
if (lookahead_token >= 0)
{
/*
@@ -1289,6 +1308,8 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
token= lex_one_token(yylval, thd);
add_digest_token(token, yylval);
+ SELECT_LEX *curr_sel= thd->lex->current_select;
+
switch(token) {
case WITH:
/*
@@ -1337,8 +1358,16 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
}
break;
case VALUES:
- if (thd->lex->current_select->parsing_place == IN_UPDATE_ON_DUP_KEY ||
- thd->lex->current_select->parsing_place == IN_PART_FUNC)
+ if (curr_sel &&
+ (curr_sel->parsing_place == BEFORE_OPT_LIST ||
+ curr_sel->parsing_place == AFTER_LIST))
+ {
+ curr_sel->parsing_place= NO_MATTER;
+ break;
+ }
+ if (curr_sel &&
+ (curr_sel->parsing_place == IN_UPDATE_ON_DUP_KEY ||
+ curr_sel->parsing_place == IN_PART_FUNC))
return VALUE_SYM;
token= lex_one_token(yylval, thd);
add_digest_token(token, yylval);
@@ -1352,6 +1381,43 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
lookahead_token= token;
return VALUES;
}
+ case VALUE_SYM:
+ if (curr_sel &&
+ (curr_sel->parsing_place == BEFORE_OPT_LIST ||
+ curr_sel->parsing_place == AFTER_LIST))
+ {
+ curr_sel->parsing_place= NO_MATTER;
+ return VALUES;
+ }
+ break;
+ case PARTITION_SYM:
+ case SELECT_SYM:
+ case UNION_SYM:
+ if (curr_sel &&
+ (curr_sel->parsing_place == BEFORE_OPT_LIST ||
+ curr_sel->parsing_place == AFTER_LIST))
+ {
+ curr_sel->parsing_place= NO_MATTER;
+ }
+ break;
+ case left_paren:
+ if (!curr_sel ||
+ curr_sel->parsing_place != BEFORE_OPT_LIST)
+ return token;
+ token= lex_one_token(yylval, thd);
+ add_digest_token(token, yylval);
+ lookahead_yylval= yylval;
+ yylval= NULL;
+ lookahead_token= token;
+ curr_sel->parsing_place= NO_MATTER;
+ if (token == LIKE)
+ return LEFT_PAREN_LIKE;
+ if (token == WITH)
+ return LEFT_PAREN_WITH;
+ if (token != left_paren && token != SELECT_SYM)
+ return LEFT_PAREN_ALT;
+ else
+ return left_paren;
break;
default:
break;
@@ -1688,7 +1754,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
return(TEXT_STRING);
}
case MY_LEX_COMMENT: // Comment
- lex->select_lex.options|= OPTION_FOUND_COMMENT;
+ lex->lex_options|= OPTION_LEX_FOUND_COMMENT;
while ((c= yyGet()) != '\n' && c) ;
yyUnget(); // Safety against eof
state= MY_LEX_START; // Try again
@@ -1699,7 +1765,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
state= MY_LEX_CHAR; // Probable division
break;
}
- lex->select_lex.options|= OPTION_FOUND_COMMENT;
+ lex->lex_options|= OPTION_LEX_FOUND_COMMENT;
/* Reject '/' '*', since we might need to turn off the echo */
yyUnget();
@@ -2207,8 +2273,8 @@ void trim_whitespace(CHARSET_INFO *cs, LEX_CSTRING *str, size_t * prefix_length)
void st_select_lex_node::init_query_common()
{
options= 0;
- sql_cache= SQL_CACHE_UNSPECIFIED;
- linkage= UNSPECIFIED_TYPE;
+ set_linkage(UNSPECIFIED_TYPE);
+ distinct= TRUE;
no_table_names_allowed= 0;
uncacheable= 0;
}
@@ -2216,7 +2282,7 @@ void st_select_lex_node::init_query_common()
void st_select_lex_unit::init_query()
{
init_query_common();
- linkage= GLOBAL_OPTIONS_TYPE;
+ set_linkage(GLOBAL_OPTIONS_TYPE);
select_limit_cnt= HA_POS_ERROR;
offset_limit_cnt= 0;
union_distinct= 0;
@@ -2258,16 +2324,6 @@ void st_select_lex::init_query()
having_fix_field_for_pushed_cond= 0;
context.select_lex= this;
context.init();
- /*
- Add the name resolution context of the current (sub)query to the
- stack of contexts for the whole query.
- TODO:
- push_context may return an error if there is no memory for a new
- element in the stack, however this method has no return value,
- thus push_context should be moved to a place where query
- initialization is checked for failure.
- */
- parent_lex->push_context(&context, parent_lex->thd->mem_root);
cond_count= between_count= with_wild= 0;
max_equal_elems= 0;
ref_pointer_array.reset();
@@ -2313,16 +2369,14 @@ void st_select_lex::init_select()
table_join_options= 0;
in_sum_expr= with_wild= 0;
options= 0;
- sql_cache= SQL_CACHE_UNSPECIFIED;
ftfunc_list_alloc.empty();
inner_sum_func_list= 0;
ftfunc_list= &ftfunc_list_alloc;
- order_list.elements= 0;
- order_list.first= 0;
- order_list.next= &order_list.first;
+ order_list.empty();
/* Set limit and offset to default values */
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */
+ is_set_query_expr_tail= false;
with_sum_func= 0;
with_all_modifier= 0;
is_correlated= 0;
@@ -2384,6 +2438,23 @@ void st_select_lex_node::add_slave(st_select_lex_node *slave_arg)
}
}
+void st_select_lex_node::link_chain_down(st_select_lex_node *first)
+{
+ st_select_lex_node *last_node;
+ st_select_lex_node *node= first;
+ do
+ {
+ last_node= node;
+ node->master= this;
+ node= node->next;
+ } while (node);
+ if ((last_node->next= slave))
+ {
+ slave->prev= &last_node->next;
+ }
+ first->prev= &slave;
+ slave= first;
+}
/*
include on level down (but do not link)
@@ -2433,7 +2504,7 @@ void st_select_lex_node::fast_exclude()
// Remove slave structure
for (; slave; slave= slave->next)
slave->fast_exclude();
-
+
}
@@ -2907,8 +2978,7 @@ void st_select_lex::print_order(String *str,
else
{
/* replace numeric reference with equivalent for ORDER constant */
- if (order->item[0]->type() == Item::INT_ITEM &&
- order->item[0]->basic_const_item())
+ if (order->item[0]->is_order_clause_position())
{
/* make it expression instead of integer constant */
str->append(STRING_WITH_LEN("''"));
@@ -3103,6 +3173,7 @@ LEX::LEX()
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
+ unit.slave= &builtin_select;
}
@@ -3129,12 +3200,12 @@ bool LEX::can_be_merged()
// TODO: do not forget implement case when select_lex.table_list.elements==0
/* find non VIEW subqueries/unions */
- bool selects_allow_merge= (select_lex.next_select() == 0 &&
- !(select_lex.uncacheable &
+ bool selects_allow_merge= (first_select_lex()->next_select() == 0 &&
+ !(first_select_lex()->uncacheable &
UNCACHEABLE_RAND));
if (selects_allow_merge)
{
- for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
+ for (SELECT_LEX_UNIT *tmp_unit= first_select_lex()->first_inner_unit();
tmp_unit;
tmp_unit= tmp_unit->next_unit())
{
@@ -3151,12 +3222,12 @@ bool LEX::can_be_merged()
}
return (selects_allow_merge &&
- select_lex.group_list.elements == 0 &&
- select_lex.having == 0 &&
- select_lex.with_sum_func == 0 &&
- select_lex.table_list.elements >= 1 &&
- !(select_lex.options & SELECT_DISTINCT) &&
- select_lex.select_limit == 0);
+ first_select_lex()->group_list.elements == 0 &&
+ first_select_lex()->having == 0 &&
+ first_select_lex()->with_sum_func == 0 &&
+ first_select_lex()->table_list.elements >= 1 &&
+ !(first_select_lex()->options & SELECT_DISTINCT) &&
+ first_select_lex()->select_limit == 0);
}
@@ -3509,7 +3580,7 @@ void LEX::set_trg_event_type_for_tables()
Do not iterate over sub-selects, only the tables in the outermost
SELECT_LEX can be modified, if any.
*/
- TABLE_LIST *tables= select_lex.get_table_list();
+ TABLE_LIST *tables= first_select_lex()->get_table_list();
while (tables)
{
@@ -3565,12 +3636,13 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
/*
and from local list if it is not empty
*/
- if ((*link_to_local= MY_TEST(select_lex.table_list.first)))
+ if ((*link_to_local= MY_TEST(first_select_lex()->table_list.first)))
{
- select_lex.context.table_list=
- select_lex.context.first_name_resolution_table= first->next_local;
- select_lex.table_list.first= first->next_local;
- select_lex.table_list.elements--; //safety
+ first_select_lex()->context.table_list=
+ first_select_lex()->context.first_name_resolution_table=
+ first->next_local;
+ first_select_lex()->table_list.first= first->next_local;
+ first_select_lex()->table_list.elements--; //safety
first->next_local= 0;
/*
Ensure that the global list has the same first table as the local
@@ -3601,7 +3673,7 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
void LEX::first_lists_tables_same()
{
- TABLE_LIST *first_table= select_lex.table_list.first;
+ TABLE_LIST *first_table= first_select_lex()->table_list.first;
if (query_tables != first_table && first_table != 0)
{
TABLE_LIST *next;
@@ -3626,6 +3698,23 @@ void LEX::first_lists_tables_same()
}
}
+void LEX::fix_first_select_number()
+{
+ SELECT_LEX *first= first_select_lex();
+ if (first && first->select_number != 1)
+ {
+ uint num= first->select_number;
+ for (SELECT_LEX *sel= all_selects_list;
+ sel;
+ sel= sel->next_select_in_list())
+ {
+ if (sel->select_number < num)
+ sel->select_number++;
+ }
+ first->select_number= 1;
+ }
+}
+
/*
Link table back that was unlinked with unlink_first_table()
@@ -3651,10 +3740,10 @@ void LEX::link_first_table_back(TABLE_LIST *first,
if (link_to_local)
{
- first->next_local= select_lex.table_list.first;
- select_lex.context.table_list= first;
- select_lex.table_list.first= first;
- select_lex.table_list.elements++; //safety
+ first->next_local= first_select_lex()->table_list.first;
+ first_select_lex()->context.table_list= first;
+ first_select_lex()->table_list.first= first;
+ first_select_lex()->table_list.elements++; //safety
}
}
}
@@ -3683,19 +3772,19 @@ void LEX::cleanup_after_one_table_open()
NOTE: all units will be connected to thd->lex->select_lex, because we
have not UNION on most upper level.
*/
- if (all_selects_list != &select_lex)
+ if (all_selects_list != first_select_lex())
{
derived_tables= 0;
- select_lex.exclude_from_table_unique_test= false;
+ first_select_lex()->exclude_from_table_unique_test= false;
/* cleunup underlying units (units of VIEW) */
- for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit();
+ for (SELECT_LEX_UNIT *un= first_select_lex()->first_inner_unit();
un;
un= un->next_unit())
un->cleanup();
/* reduce all selects list to default state */
- all_selects_list= &select_lex;
+ all_selects_list= first_select_lex();
/* remove underlying units (units of VIEW) subtree */
- select_lex.cut_subtree();
+ first_select_lex()->cut_subtree();
}
}
@@ -4350,7 +4439,7 @@ void SELECT_LEX::update_used_tables()
tab->covering_keys= tab->s->keys_for_keyread;
tab->covering_keys.intersect(tab->keys_in_use_for_query);
/*
- View/derived was merged. Need to recalculate read_set/vcol_set
+ View/derived was merged. Need to recalculate read_set
bitmaps here. For example:
CREATE VIEW v1 AS SELECT f1,f2,f3 FROM t1;
SELECT f1 FROM v1;
@@ -4359,8 +4448,6 @@ void SELECT_LEX::update_used_tables()
be in the read_set.
*/
bitmap_clear_all(tab->read_set);
- if (tab->vcol_set)
- bitmap_clear_all(tab->vcol_set);
break;
}
}
@@ -4561,7 +4648,7 @@ void st_select_lex::set_explain_type(bool on_the_fly)
using_materialization= TRUE;
}
- if (&master_unit()->thd->lex->select_lex == this)
+ if (master_unit()->thd->lex->first_select_lex() == this)
{
type= is_primary ? "PRIMARY" : "SIMPLE";
}
@@ -4756,8 +4843,8 @@ bool LEX::save_prep_leaf_tables()
Query_arena *arena= thd->stmt_arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
//It is used for DETETE/UPDATE so top level has only one SELECT
- DBUG_ASSERT(select_lex.next_select() == NULL);
- bool res= select_lex.save_prep_leaf_tables(thd);
+ DBUG_ASSERT(first_select_lex()->next_select() == NULL);
+ bool res= first_select_lex()->save_prep_leaf_tables(thd);
if (arena)
thd->restore_active_arena(arena, &backup);
@@ -5088,8 +5175,13 @@ bool LEX::is_partition_management() const
SELECT_LEX *LEX::exclude_last_select()
{
- DBUG_ENTER("SELECT_LEX::exclude_last_select");
- SELECT_LEX *exclude= current_select;
+ return exclude_not_first_select(current_select);
+}
+
+SELECT_LEX *LEX::exclude_not_first_select(SELECT_LEX *exclude)
+{
+ DBUG_ENTER("LEX::exclude_not_first_select");
+ DBUG_PRINT("enter", ("exclude %p #%u", exclude, exclude->select_number));
SELECT_LEX_UNIT *unit= exclude->master_unit();
SELECT_LEX *sl;
DBUG_ASSERT(unit->first_select() != exclude);
@@ -5100,89 +5192,255 @@ SELECT_LEX *LEX::exclude_last_select()
DBUG_PRINT("info", ("excl: %p unit: %p prev: %p", exclude, unit, sl));
if (!sl)
DBUG_RETURN(NULL);
- DBUG_ASSERT(exclude->next_select() == NULL);
- exclude->exclude_from_tree();
+ DBUG_ASSERT(&sl->next == exclude->prev);
+
+ exclude->prev= NULL;
+
current_select= sl;
DBUG_RETURN(exclude);
}
-/**
- Put given (new) SELECT_LEX level below after currect (last) SELECT
+SELECT_LEX_UNIT *LEX::alloc_unit()
+{
+ SELECT_LEX_UNIT *unit;
+ DBUG_ENTER("LEX::alloc_unit");
+ if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
+ DBUG_RETURN(NULL);
+
+ unit->init_query();
+ /* TODO: reentrant problem */
+ unit->thd= thd;
+ unit->link_next= 0;
+ unit->link_prev= 0;
+ /* TODO: remove return_to */
+ unit->return_to= NULL;
+ DBUG_RETURN(unit);
+}
- LAST SELECT -> DUMMY SELECT
- |
- V
- NEW UNIT
- |
- V
- NEW SELECT
- SELECT (*LAST*) ... FROM (SELECT (*NEW*) ... )
+SELECT_LEX *LEX::alloc_select(bool select)
+{
+ SELECT_LEX *select_lex;
+ DBUG_ENTER("LEX::alloc_select");
+ if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
+ DBUG_RETURN(NULL);
+ DBUG_PRINT("info", ("Allocate select: %p #%u statement lex: %p",
+ select_lex, thd->lex->stmt_lex->current_select_number,
+ thd->lex->stmt_lex));
+ /*
+ TODO: move following init to constructor when we get rid of builtin
+ select
+ */
+ select_lex->select_number= ++thd->lex->stmt_lex->current_select_number;
+ select_lex->parent_lex= this; /* Used in init_query. */
+ select_lex->init_query();
+ if (select)
+ select_lex->init_select();
+ select_lex->nest_level_base= &this->unit;
+ select_lex->include_global((st_select_lex_node**)&all_selects_list);
+ select_lex->context.resolve_in_select_list= TRUE;
+ DBUG_RETURN(select_lex);
+}
- @param nselect Select to put one level below
+SELECT_LEX_UNIT *
+LEX::create_unit(SELECT_LEX *first_sel)
+{
+ SELECT_LEX_UNIT *unit;
+ DBUG_ENTER("LEX::create_unit");
- @retval TRUE Error
- @retval FALSE OK
-*/
+ if (!(unit= alloc_unit()))
+ DBUG_RETURN(NULL);
-bool LEX::add_unit_in_brackets(SELECT_LEX *nselect)
+ unit->register_select_chain(first_sel);
+ if (first_sel->next_select())
+ {
+ unit->reset_distinct();
+ DBUG_ASSERT(!unit->fake_select_lex);
+ if (unit->add_fake_select_lex(thd))
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(unit);
+}
+
+SELECT_LEX_UNIT *
+SELECT_LEX::attach_selects_chain(SELECT_LEX *first_sel,
+ Name_resolution_context *context)
{
- DBUG_ENTER("LEX::add_unit_in_brackets");
- bool distinct= nselect->master_unit()->union_distinct == nselect;
- bool rc= add_select_to_union_list(distinct, nselect->linkage, 0);
- if (rc)
- DBUG_RETURN(TRUE);
- SELECT_LEX* dummy_select= current_select;
- dummy_select->automatic_brackets= TRUE;
- dummy_select->linkage= nselect->linkage;
+ SELECT_LEX_UNIT *unit;
+ DBUG_ENTER("SELECT_LEX::attach_select_chain");
+
+ if (!(unit= parent_lex->alloc_unit()))
+ DBUG_RETURN(NULL);
+
+ unit->register_select_chain(first_sel);
+ register_unit(unit, context);
+ if (first_sel->next_select())
+ {
+ unit->reset_distinct();
+ DBUG_ASSERT(!unit->fake_select_lex);
+ if (unit->add_fake_select_lex(parent_lex->thd))
+ DBUG_RETURN(NULL);
+ }
+
+ DBUG_RETURN(unit);
+}
+
+SELECT_LEX *
+LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
+{
+ SELECT_LEX *wrapping_sel;
+ Table_ident *ti;
+ DBUG_ENTER("LEX::wrap_unit_into_derived");
+
+ if (!(wrapping_sel= alloc_select(TRUE)))
+ DBUG_RETURN(NULL);
+ Name_resolution_context *context= &wrapping_sel->context;
+ context->init();
+ wrapping_sel->automatic_brackets= FALSE;
+
+ wrapping_sel->register_unit(unit, context);
/* stuff dummy SELECT * FROM (...) */
+
+ if (push_select(wrapping_sel)) // for Items & TABLE_LIST
+ DBUG_RETURN(NULL);
+
+ /* add SELECT list*/
+ {
+ Item *item= new (thd->mem_root)
+ Item_field(thd, context, NULL, NULL, &star_clex_str);
+ if (item == NULL)
+ goto err;
+ if (add_item_to_list(thd, item))
+ goto err;
+ (wrapping_sel->with_wild)++;
+ }
+
+ unit->first_select()->set_linkage(DERIVED_TABLE_TYPE);
+
+ ti= new (thd->mem_root) Table_ident(unit);
+ if (ti == NULL)
+ goto err;
+ {
+ TABLE_LIST *table_list;
+ LEX_CSTRING alias;
+ if (wrapping_sel->make_unique_derived_name(thd, &alias))
+ goto err;
+
+ if (!(table_list= wrapping_sel->add_table_to_list(thd, ti, &alias,
+ 0, TL_READ,
+ MDL_SHARED_READ)))
+ goto err;
+
+ context->resolve_in_table_list_only(table_list);
+ wrapping_sel->add_joined_table(table_list);
+ }
+
+ pop_select();
+
+ derived_tables|= DERIVED_SUBQUERY;
+
+ DBUG_RETURN(wrapping_sel);
+
+err:
+ pop_select();
+ DBUG_RETURN(NULL);
+}
+
+SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel)
+{
+ SELECT_LEX *dummy_select;
+ SELECT_LEX_UNIT *unit;
+ Table_ident *ti;
+ DBUG_ENTER("LEX::wrap_select_chain_into_derived");
+
+ if (!(dummy_select= alloc_select(TRUE)))
+ DBUG_RETURN(NULL);
Name_resolution_context *context= &dummy_select->context;
- context->init();
+ dummy_select->automatic_brackets= FALSE;
+
+ if (!(unit= dummy_select->attach_selects_chain(sel, context)))
+ DBUG_RETURN(NULL);
+
+ /* stuff dummy SELECT * FROM (...) */
+
+ if (push_select(dummy_select)) // for Items & TABLE_LIST
+ DBUG_RETURN(NULL);
/* add SELECT list*/
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
- if (unlikely(item == NULL))
- DBUG_RETURN(TRUE);
- if (unlikely(add_item_to_list(thd, item)))
- DBUG_RETURN(TRUE);
- (dummy_select->with_wild)++;
+ {
+ Item *item= new (thd->mem_root)
+ Item_field(thd, context, NULL, NULL, &star_clex_str);
+ if (item == NULL)
+ goto err;
+ if (add_item_to_list(thd, item))
+ goto err;
+ (dummy_select->with_wild)++;
+ }
- rc= mysql_new_select(this, 1, nselect);
- nselect->linkage= DERIVED_TABLE_TYPE;
- DBUG_ASSERT(nselect->outer_select() == dummy_select);
+ sel->set_linkage(DERIVED_TABLE_TYPE);
- current_select= dummy_select;
- current_select->nest_level--;
+ ti= new (thd->mem_root) Table_ident(unit);
+ if (ti == NULL)
+ goto err;
+ {
+ TABLE_LIST *table_list;
+ LEX_CSTRING alias;
+ if (dummy_select->make_unique_derived_name(thd, &alias))
+ goto err;
- SELECT_LEX_UNIT *unit= nselect->master_unit();
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (unlikely(ti == NULL))
- DBUG_RETURN(TRUE);
- char buff[10];
- LEX_CSTRING alias;
- alias.length= my_snprintf(buff, sizeof(buff),
- "__%u", dummy_select->select_number);
- alias.str= thd->strmake(buff, alias.length);
- if (unlikely(!alias.str))
- DBUG_RETURN(TRUE);
+ if (!(table_list= dummy_select->add_table_to_list(thd, ti, &alias,
+ 0, TL_READ,
+ MDL_SHARED_READ)))
+ goto err;
- TABLE_LIST *table_list;
- if (unlikely(!(table_list=
- dummy_select->add_table_to_list(thd, ti, &alias,
- 0, TL_READ,
- MDL_SHARED_READ))))
- DBUG_RETURN(TRUE);
- context->resolve_in_table_list_only(table_list);
- dummy_select->add_joined_table(table_list);
+ context->resolve_in_table_list_only(table_list);
+ dummy_select->add_joined_table(table_list);
+ }
+
+ pop_select();
derived_tables|= DERIVED_SUBQUERY;
- current_select= nselect;
- current_select->nest_level++;
- DBUG_RETURN(rc);
+ DBUG_RETURN(dummy_select);
+
+err:
+ pop_select();
+ DBUG_RETURN(NULL);
+}
+
+bool LEX::push_context(Name_resolution_context *context)
+{
+ DBUG_ENTER("LEX::push_context");
+ DBUG_PRINT("info", ("Context: %p Select: %p (%d)",
+ context, context->select_lex,
+ (context->select_lex ?
+ context->select_lex->select_number:
+ 0)));
+ bool res= context_stack.push_front(context, thd->mem_root);
+ DBUG_RETURN(res);
+}
+
+
+SELECT_LEX *LEX::create_priority_nest(SELECT_LEX *first_in_nest)
+{
+ DBUG_ENTER("LEX::create_priority_nest");
+ DBUG_ASSERT(first_in_nest->first_nested);
+ enum sub_select_type wr_unit_type= first_in_nest->get_linkage();
+ bool wr_distinct= first_in_nest->distinct;
+ SELECT_LEX *attach_to= first_in_nest->first_nested;
+ attach_to->cut_next();
+ SELECT_LEX *wrapper= wrap_select_chain_into_derived(first_in_nest);
+ if (wrapper)
+ {
+ first_in_nest->first_nested= NULL;
+ wrapper->set_linkage_and_distinct(wr_unit_type, wr_distinct);
+ wrapper->first_nested= attach_to->first_nested;
+ wrapper->set_master_unit(attach_to->master_unit());
+ attach_to->link_neighbour(wrapper);
+ }
+ DBUG_RETURN(wrapper);
}
@@ -5197,7 +5455,7 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect)
void LEX::check_automatic_up(enum sub_select_type type)
{
if (type != INTERSECT_TYPE &&
- current_select->linkage == INTERSECT_TYPE &&
+ current_select->get_linkage() == INTERSECT_TYPE &&
current_select->outer_select() &&
current_select->outer_select()->automatic_brackets)
{
@@ -5647,10 +5905,17 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
bounds->m_index->sp_lex_in_use= true;
sphead->reset_lex(thd, bounds->m_index);
DBUG_ASSERT(thd->lex != this);
- if (unlikely(!(item=
- new (thd->mem_root) Item_field(thd,
- thd->lex->current_context(),
- NullS, NullS, &name))))
+ /*
+ We pass NULL as Name_resolution_context here.
+ It's OK, fix_fields() will not be called for this Item_field created.
+ Item_field is only needed for LEX::sp_for_loop_cursor_declarations()
+ and is used to transfer the loop index variable name, "rec" in this example:
+ FOR rec IN (SELECT * FROM t1)
+ DO
+ SELECT rec.a, rec.b;
+ END FOR;
+ */
+ if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name)))
return true;
bounds->m_index->set_item_and_free_list(item, NULL);
if (thd->lex->sphead->restore_lex(thd))
@@ -5757,10 +6022,22 @@ bool LEX::sp_for_loop_intrange_declarations(THD *thd, Lex_for_loop_st *loop,
const LEX_CSTRING *index,
const Lex_for_loop_bounds_st &bounds)
{
- if (unlikely(!(loop->m_index=
- bounds.m_index->
- sp_add_for_loop_variable(thd, index,
- bounds.m_index->get_item()))))
+ Item *item;
+ if ((item= bounds.m_index->get_item())->type() == Item::FIELD_ITEM)
+ {
+ // We're here is the lower bound is unknown identifier
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name());
+ return true;
+ }
+ if ((item= bounds.m_upper_bound->get_item())->type() == Item::FIELD_ITEM)
+ {
+ // We're here is the upper bound is unknown identifier
+ my_error(ER_SP_UNDECLARED_VAR, MYF(0), item->full_name());
+ return true;
+ }
+ if (!(loop->m_index=
+ bounds.m_index->sp_add_for_loop_variable(thd, index,
+ bounds.m_index->get_item())))
return true;
if (unlikely(!(loop->m_upper_bound=
bounds.m_upper_bound->
@@ -6673,7 +6950,6 @@ Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name,
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
return NULL;
}
-
Query_fragment pos(thd, sphead, start, end);
Item_param *item= new (thd->mem_root) Item_param(thd, name,
pos.pos(), pos.length());
@@ -6704,6 +6980,38 @@ bool LEX::add_resignal_statement(THD *thd, const sp_condition_value *v)
}
+/*
+ Make an Item when an identifier is found in the FOR loop bounds:
+ FOR rec IN cursor
+ FOR var IN var1 .. xxx
+ FOR var IN row1.field1 .. xxx
+ When we parse the first expression after the "IN" keyword,
+ we don't know yet if it's a cursor name, or a scalar SP variable name,
+ or a field of a ROW SP variable. Here we create Item_field to remember
+ the fully qualified name. Later sp_for_loop_cursor_declarations()
+ detects how to treat this name properly.
+*/
+Item *LEX::create_item_for_loop_bound(THD *thd,
+ const LEX_CSTRING *a,
+ const LEX_CSTRING *b,
+ const LEX_CSTRING *c)
+{
+ /*
+ Pass NULL as the name resolution context.
+ This is OK, fix_fields() won't be called for this Item_field.
+ */
+ return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c);
+}
+
+
+bool LEX::check_expr_allows_fields_or_error(THD *thd, const char *name) const
+{
+ if (select_stack_top > 0)
+ return false; // OK, fields are allowed
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), name, thd->where);
+ return true; // Error, fields are not allowed
+}
+
Item *LEX::create_item_ident_nospvar(THD *thd,
const Lex_ident_sys_st *a,
const Lex_ident_sys_st *b)
@@ -6726,12 +7034,11 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), a->str, thd->where);
return NULL;
}
- if ((current_select->parsing_place != IN_HAVING) ||
- (current_select->get_in_sum_expr() > 0))
- return new (thd->mem_root) Item_field(thd, current_context(),
- NullS, a->str, b);
- return new (thd->mem_root) Item_ref(thd, current_context(),
- NullS, a->str, b);
+
+ if (current_select->parsing_place == FOR_LOOP_BOUND)
+ return create_item_for_loop_bound(thd, &null_clex_str, a, b);
+
+ return create_item_ident_field(thd, NullS, a->str, b);
}
@@ -6943,12 +7250,11 @@ Item *LEX::create_item_ident(THD *thd,
my_error(ER_TABLENAME_NOT_ALLOWED_HERE, MYF(0), b->str, thd->where);
return NULL;
}
- if (current_select->parsing_place != IN_HAVING ||
- current_select->get_in_sum_expr() > 0)
- return new (thd->mem_root) Item_field(thd, current_context(),
- schema, b->str, c);
- return new (thd->mem_root) Item_ref(thd, current_context(),
- schema, b->str, c);
+
+ if (current_select->parsing_place == FOR_LOOP_BOUND)
+ return create_item_for_loop_bound(thd, &null_clex_str, b, c);
+
+ return create_item_ident_field(thd, schema, b->str, c);
}
@@ -6981,11 +7287,9 @@ Item *LEX::create_item_limit(THD *thd, const Lex_ident_cli_st *ca)
#endif
safe_to_cache_query= 0;
- if (unlikely(item->type() != Item::INT_ITEM))
- {
- my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
+ if (!item->is_valid_limit_clause_variable_with_error())
return NULL;
- }
+
item->limit_clause_param= true;
return item;
}
@@ -7015,11 +7319,8 @@ Item *LEX::create_item_limit(THD *thd,
if (unlikely(!(item= create_item_spvar_row_field(thd, rh, &sa, &sb, spv,
ca->pos(), cb->end()))))
return NULL;
- if (unlikely(item->type() != Item::INT_ITEM))
- {
- my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
+ if (!item->is_valid_limit_clause_variable_with_error())
return NULL;
- }
item->limit_clause_param= true;
return item;
}
@@ -7039,15 +7340,20 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
}
-Item *LEX::create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name)
+Item *LEX::create_item_ident_field(THD *thd, const char *db,
+ const char *table,
+ const Lex_ident_sys_st *name)
{
+ if (check_expr_allows_fields_or_error(thd, name->str))
+ return NULL;
+
if (current_select->parsing_place != IN_HAVING ||
current_select->get_in_sum_expr() > 0)
return new (thd->mem_root) Item_field(thd, current_context(),
- NullS, NullS, name);
+ db, table, name);
return new (thd->mem_root) Item_ref(thd, current_context(),
- NullS, NullS, name);
+ db, table, name);
}
@@ -7097,6 +7403,11 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
if (lex_string_eq(name, STRING_WITH_LEN("SQLERRM")))
return new (thd->mem_root) Item_func_sqlerrm(thd);
}
+
+ if (current_select->parsing_place == FOR_LOOP_BOUND)
+ return create_item_for_loop_bound(thd, &null_clex_str, &null_clex_str,
+ name);
+
return create_item_ident_nosp(thd, name);
}
@@ -7390,8 +7701,8 @@ void st_select_lex::collect_grouping_fields(THD *thd,
{
if ((*ord->item)->eq((Item*)item, 0))
{
- Grouping_tmp_field *grouping_tmp_field=
- new Grouping_tmp_field(master_unit()->derived->table->field[i], item);
+ Field_pair *grouping_tmp_field=
+ new Field_pair(master_unit()->derived->table->field[i], item);
grouping_tmp_fields.push_back(grouping_tmp_field);
}
}
@@ -7422,8 +7733,7 @@ void st_select_lex::collect_grouping_fields(THD *thd,
*/
void
-st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
- TABLE_LIST *derived)
+st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond)
{
cond->clear_extraction_flag();
if (cond->type() == Item::COND_ITEM)
@@ -7436,7 +7746,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
Item *item;
while ((item=li++))
{
- check_cond_extraction_for_grouping_fields(item, derived);
+ check_cond_extraction_for_grouping_fields(item);
if (item->get_extraction_flag() != NO_EXTRACTION_FL)
{
count++;
@@ -7485,7 +7795,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
to figure out whether a subformula depends only on these fields or not.
@note
The built condition C is always implied by the condition cond
- (cond => C). The method tries to build the most restictive such
+ (cond => C). The method tries to build the least restictive such
condition (i.e. for any other condition C' such that cond => C'
we have C => C').
@note
@@ -7561,6 +7871,140 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond,
}
+bool st_select_lex::set_nest_level(int new_nest_level)
+{
+ DBUG_ENTER("st_select_lex::set_nest_level");
+ DBUG_PRINT("enter", ("select #%d %p nest level: %d",
+ select_number, this, new_nest_level));
+ if (new_nest_level > (int) MAX_SELECT_NESTING)
+ {
+ my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ nest_level= new_nest_level;
+ new_nest_level++;
+ for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit())
+ {
+ if (u->set_nest_level(new_nest_level))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+bool st_select_lex_unit::set_nest_level(int new_nest_level)
+{
+ DBUG_ENTER("st_select_lex_unit::set_nest_level");
+ for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->set_nest_level(new_nest_level))
+ DBUG_RETURN(TRUE);
+ }
+ if (fake_select_lex &&
+ fake_select_lex->set_nest_level(new_nest_level))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+
+bool st_select_lex::check_parameters(SELECT_LEX *main_select)
+{
+ DBUG_ENTER("st_select_lex::check_parameters");
+ DBUG_PRINT("enter", ("select #%d %p nest level: %d",
+ select_number, this, nest_level));
+
+
+ if ((options & OPTION_PROCEDURE_CLAUSE) &&
+ (!parent_lex->selects_allow_procedure ||
+ next_select() != NULL ||
+ this != master_unit()->first_select() ||
+ nest_level != 0))
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "PROCEDURE");
+ DBUG_RETURN(TRUE);
+ }
+
+ if ((options & SELECT_HIGH_PRIORITY) && this != main_select)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "HIGH_PRIORITY");
+ DBUG_RETURN(TRUE);
+ }
+ if ((options & OPTION_BUFFER_RESULT) && this != main_select)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_BUFFER_RESULT");
+ DBUG_RETURN(TRUE);
+ }
+ if ((options & OPTION_FOUND_ROWS) && this != main_select)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CALC_FOUND_ROWS");
+ DBUG_RETURN(TRUE);
+ }
+ if (options & OPTION_NO_QUERY_CACHE)
+ {
+ /*
+ Allow this flag only on the first top-level SELECT statement, if
+ SQL_CACHE wasn't specified.
+ */
+ if (this != main_select)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE");
+ DBUG_RETURN(TRUE);
+ }
+ if (parent_lex->sql_cache == LEX::SQL_CACHE)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE");
+ DBUG_RETURN(TRUE);
+ }
+ parent_lex->safe_to_cache_query=0;
+ parent_lex->sql_cache= LEX::SQL_NO_CACHE;
+ }
+ if (options & OPTION_TO_QUERY_CACHE)
+ {
+ /*
+ Allow this flag only on the first top-level SELECT statement, if
+ SQL_NO_CACHE wasn't specified.
+ */
+ if (this != main_select)
+ {
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE");
+ DBUG_RETURN(TRUE);
+ }
+ if (parent_lex->sql_cache == LEX::SQL_NO_CACHE)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE");
+ DBUG_RETURN(TRUE);
+ }
+ parent_lex->safe_to_cache_query=1;
+ parent_lex->sql_cache= LEX::SQL_CACHE;
+ }
+
+ for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit())
+ {
+ if (u->check_parameters(main_select))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+bool st_select_lex_unit::check_parameters(SELECT_LEX *main_select)
+{
+ for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->check_parameters(main_select))
+ return TRUE;
+ }
+ return fake_select_lex && fake_select_lex->check_parameters(main_select);
+}
+
+
+bool LEX::check_main_unit_semantics()
+{
+ if (unit.set_nest_level(0) ||
+ unit.check_parameters(first_select_lex()))
+ return TRUE;
+ return FALSE;
+}
+
int set_statement_var_if_exists(THD *thd, const char *var_name,
size_t var_name_length, ulonglong value)
{
@@ -7615,10 +8059,10 @@ bool LEX::create_or_alter_view_finalize(THD *thd, Table_ident *table_ident)
{
sql_command= SQLCOM_CREATE_VIEW;
/* first table in list is target VIEW name */
- if (unlikely(!select_lex.add_table_to_list(thd, table_ident, NULL,
+ if (!first_select_lex()->add_table_to_list(thd, table_ident, NULL,
TL_OPTION_UPDATING,
TL_IGNORE,
- MDL_EXCLUSIVE)))
+ MDL_EXCLUSIVE))
return true;
query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
return false;
@@ -7911,6 +8355,130 @@ Item *Lex_trim_st::make_item_func_trim(THD *thd) const
}
+/**
+ @brief
+ Extract from given item a condition pushable into WHERE clause
+
+ @param thd the thread handle
+ @param cond the item to extract a condition to be pushed
+ into WHERE
+ @param remaining_cond the condition that will remain of cond after
+ the pushdown of its parts into the WHERE clause
+ @param transformer the transformer callback function to be
+ applied to the condition so it can be pushed
+ down into the WHERE clause of this select
+ @param arg parameter to be passed to the transformer
+
+ @details
+ This method checks if cond entirely or its parts can be
+ pushed into the WHERE clause of this select and prepares it for pushing.
+
+ First it checks wherever this select doesn't have any aggregation function
+ in its projection and GROUP BY clause. If so cond can be entirely
+ pushed into the WHERE clause of this select but before its fields should
+ be transformed with transformer_for_where to make it pushable.
+
+ Otherwise the method checks wherever any condition depending only on
+ grouping fields can be extracted from cond. If there is any it prepares it
+ for pushing using grouping_field_transformer_for_where and if it happens to
+ be a conjunct of cond it removes it from cond. It saves the result of
+ removal in remaining_cond.
+ The extracted condition is saved in cond_pushed_into_where of this select.
+
+ @note
+ When looking for pushable condition the method considers only the grouping
+ fields from the list grouping_tmp_fields whose elements are of the type
+ Field_pair. This list must be prepared before the call of the
+ function.
+
+ @note
+ This method is called for pushdown conditions into materialized
+ derived tables/views optimization.
+ Item::derived_field_transformer_for_where is passed as the actual
+ callback function.
+ Also it is called for pushdown conditions into materialized IN subqueries.
+ Item::in_subq_field_transformer_for_where is passed as the actual
+ callback function.
+*/
+
+void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond,
+ Item **remaining_cond,
+ Item_transformer transformer,
+ uchar *arg)
+{
+ if (!cond_pushdown_is_allowed())
+ return;
+ thd->lex->current_select= this;
+ if (have_window_funcs())
+ {
+ Item *cond_over_partition_fields;
+ check_cond_extraction_for_grouping_fields(cond);
+ cond_over_partition_fields=
+ build_cond_for_grouping_fields(thd, cond, true);
+ if (cond_over_partition_fields)
+ cond_over_partition_fields= cond_over_partition_fields->transform(thd,
+ &Item::grouping_field_transformer_for_where,
+ (uchar*) this);
+ if (cond_over_partition_fields)
+ {
+ cond_over_partition_fields->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond_over_partition_fields;
+ }
+
+ return;
+ }
+
+ if (!join->group_list && !with_sum_func)
+ {
+ cond=
+ cond->transform(thd, transformer, arg);
+ if (cond)
+ {
+ cond->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond;
+ }
+
+ return;
+ }
+
+ /*
+ Figure out what can be extracted from cond
+ that could be pushed into the WHERE clause of this select
+ */
+ Item *cond_over_grouping_fields;
+ check_cond_extraction_for_grouping_fields(cond);
+ cond_over_grouping_fields=
+ build_cond_for_grouping_fields(thd, cond, true);
+
+ /*
+ Transform the references to the columns from the cond
+ pushed into the WHERE clause of this select to make them usable in
+ the new context
+ */
+ if (cond_over_grouping_fields)
+ cond_over_grouping_fields= cond_over_grouping_fields->transform(thd,
+ &Item::grouping_field_transformer_for_where,
+ (uchar*) this);
+
+ if (cond_over_grouping_fields)
+ {
+
+ /*
+ In cond remove top conjuncts that has been pushed into the WHERE
+ clause of this select
+ */
+ cond= remove_pushed_top_conjuncts(thd, cond);
+
+ cond_over_grouping_fields->walk(
+ &Item::cleanup_excluding_const_fields_processor, 0, 0);
+ cond_pushed_into_where= cond_over_grouping_fields;
+ }
+
+ *remaining_cond= cond;
+}
+
Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
Lex_ident_cli_st *cname, List<Item> *args)
{
@@ -8177,9 +8745,716 @@ bool LEX::tvc_finalize_derived()
thd->parse_error();
return true;
}
- if (current_select->linkage == GLOBAL_OPTIONS_TYPE ||
+ if (current_select->get_linkage() == GLOBAL_OPTIONS_TYPE ||
unlikely(mysql_new_select(this, 1, NULL)))
return true;
- current_select->linkage= DERIVED_TABLE_TYPE;
+ current_select->set_linkage(DERIVED_TABLE_TYPE);
return tvc_finalize();
}
+
+
+void st_select_lex_unit::reset_distinct()
+{
+ union_distinct= NULL;
+ for(SELECT_LEX *sl= first_select()->next_select();
+ sl;
+ sl= sl->next_select())
+ {
+ if (sl->distinct)
+ {
+ union_distinct= sl;
+ }
+ }
+}
+
+
+void st_select_lex_unit::fix_distinct(st_select_lex_unit *new_unit)
+{
+ if (union_distinct)
+ {
+ if (this != union_distinct->master_unit())
+ {
+ DBUG_ASSERT(new_unit == union_distinct->master_unit());
+ new_unit->union_distinct= union_distinct;
+ reset_distinct();
+ }
+ else
+ new_unit->reset_distinct();
+ }
+}
+
+
+void st_select_lex_unit::register_select_chain(SELECT_LEX *first_sel)
+{
+ DBUG_ASSERT(first_sel != 0);
+ slave= first_sel;
+ first_sel->prev= &slave;
+ for(SELECT_LEX *sel=first_sel; sel; sel= sel->next_select())
+ {
+ sel->master= (st_select_lex_node *)this;
+ uncacheable|= sel->uncacheable;
+ }
+}
+
+
+void st_select_lex::register_unit(SELECT_LEX_UNIT *unit,
+ Name_resolution_context *outer_context)
+{
+ if ((unit->next= slave))
+ slave->prev= &unit->next;
+ unit->prev= &slave;
+ slave= unit;
+ unit->master= this;
+ uncacheable|= unit->uncacheable;
+
+ for(SELECT_LEX *sel= unit->first_select();sel; sel= sel->next_select())
+ {
+ sel->context.outer_context= outer_context;
+ }
+}
+
+
+void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit)
+{
+ for (;
+ unit;
+ unit= unit->next_unit())
+ for(SELECT_LEX *child= unit->first_select();
+ child;
+ child= child->next_select())
+ {
+ /*
+ A subselect can add fields to an outer select.
+ Reserve space for them.
+ */
+ select_n_where_fields+= child->select_n_where_fields;
+ /*
+ Aggregate functions in having clause may add fields
+ to an outer select. Count them also.
+ */
+ select_n_having_items+= child->select_n_having_items;
+ }
+}
+
+
+bool LEX::main_select_push()
+{
+ DBUG_ENTER("LEX::main_select_push");
+ current_select_number= 1;
+ builtin_select.select_number= 1;
+ if (push_select(&builtin_select))
+ DBUG_RETURN(TRUE);
+ DBUG_RETURN(FALSE);
+}
+
+void Lex_select_lock::set_to(SELECT_LEX *sel)
+{
+ if (defined_lock)
+ {
+ if (sel->master_unit() &&
+ sel == sel->master_unit()->fake_select_lex)
+ sel->master_unit()->set_lock_to_the_last_select(*this);
+ else
+ {
+ sel->parent_lex->safe_to_cache_query= 0;
+ if (update_lock)
+ {
+ sel->lock_type= TL_WRITE;
+ sel->set_lock_for_tables(TL_WRITE);
+ }
+ else
+ {
+ sel->lock_type= TL_READ_WITH_SHARED_LOCKS;
+ sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
+ }
+ }
+ }
+}
+
+bool Lex_order_limit_lock::set_to(SELECT_LEX *sel)
+{
+ /*TODO: lock */
+ //if (lock.defined_lock && sel == sel->master_unit()->fake_select_lex)
+ // return TRUE;
+ if (lock.defined_timeout)
+ {
+ THD *thd= sel->parent_lex->thd;
+ if (set_statement_var_if_exists(thd,
+ C_STRING_WITH_LEN("lock_wait_timeout"),
+ lock.timeout) ||
+ set_statement_var_if_exists(thd,
+ C_STRING_WITH_LEN("innodb_lock_wait_timeout"),
+ lock.timeout))
+ return TRUE;
+ }
+ lock.set_to(sel);
+ sel->explicit_limit= limit.explicit_limit;
+ sel->select_limit= limit.select_limit;
+ sel->offset_limit= limit.offset_limit;
+ if (order_list)
+ {
+ if (sel->get_linkage() != GLOBAL_OPTIONS_TYPE &&
+ sel->olap != UNSPECIFIED_OLAP_TYPE &&
+ (sel->get_linkage() != UNION_TYPE || sel->braces))
+ {
+ my_error(ER_WRONG_USAGE, MYF(0),
+ "CUBE/ROLLUP", "ORDER BY");
+ return TRUE;
+ }
+ sel->order_list= *(order_list);
+ }
+ sel->is_set_query_expr_tail= true;
+ return FALSE;
+}
+
+
+static void change_item_list_context(List<Item> *list,
+ Name_resolution_context *context)
+{
+ List_iterator_fast<Item> it (*list);
+ Item *item;
+ while((item= it++))
+ {
+ item->walk(&Item::change_context_processor, FALSE, (void *)context);
+ }
+}
+
+
+bool LEX::insert_select_hack(SELECT_LEX *sel)
+{
+ DBUG_ENTER("LEX::insert_select_hack");
+
+ DBUG_ASSERT(first_select_lex() == &builtin_select);
+ DBUG_ASSERT(sel != NULL);
+
+ DBUG_ASSERT(builtin_select.first_inner_unit() == NULL);
+
+ if (builtin_select.link_prev)
+ {
+ if ((*builtin_select.link_prev= builtin_select.link_next))
+ ((st_select_lex *)builtin_select.link_next)->link_prev=
+ builtin_select.link_prev;
+ builtin_select.link_prev= NULL; // indicator of removal
+ }
+
+ set_main_unit(sel->master_unit());
+
+ DBUG_ASSERT(builtin_select.table_list.elements == 1);
+ TABLE_LIST *insert_table= builtin_select.table_list.first;
+
+ if (!(insert_table->next_local= sel->table_list.first))
+ {
+ sel->table_list.next= &insert_table->next_local;
+ }
+ sel->table_list.first= insert_table;
+ sel->table_list.elements++;
+ insert_table->select_lex= sel;
+
+ sel->context.first_name_resolution_table= insert_table;
+ builtin_select.context= sel->context;
+ change_item_list_context(&field_list, &sel->context);
+
+ if (sel->tvc && !sel->next_select() &&
+ (sql_command == SQLCOM_INSERT_SELECT ||
+ sql_command == SQLCOM_REPLACE_SELECT))
+ {
+ DBUG_PRINT("info", ("'Usual' INSERT detected"));
+ many_values= sel->tvc->lists_of_values;
+ sel->options= sel->tvc->select_options;
+ sel->tvc= NULL;
+ if (sql_command == SQLCOM_INSERT_SELECT)
+ sql_command= SQLCOM_INSERT;
+ else
+ sql_command= SQLCOM_REPLACE;
+ }
+
+
+ for (SELECT_LEX *sel= all_selects_list;
+ sel;
+ sel= sel->next_select_in_list())
+ {
+ if (sel->select_number != 1)
+ sel->select_number--;
+ };
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Create an Item_singlerow_subselect for a query expression.
+*/
+Item *LEX::create_item_query_expression(THD *thd,
+ const char *tok_start,
+ st_select_lex_unit *unit)
+{
+ if (!expr_allows_subselect || sql_command == SQLCOM_PURGE)
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, tok_start);
+ return NULL;
+ }
+
+ // Add the subtree of subquery to the current SELECT_LEX
+ SELECT_LEX *curr_sel= select_stack_head();
+ DBUG_ASSERT(current_select == curr_sel);
+ if (!curr_sel)
+ curr_sel= &builtin_select;
+ curr_sel->register_unit(unit, &curr_sel->context);
+ curr_sel->add_statistics(unit);
+
+ return new (thd->mem_root)
+ Item_singlerow_subselect(thd, unit->first_select());
+}
+
+
+/**
+ Process unit parsed in brackets
+*/
+
+bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit)
+{
+ SELECT_LEX *first_in_nest= unit->pre_last_parse->next_select()->first_nested;
+ if (first_in_nest->first_nested != first_in_nest)
+ {
+ /* There is a priority jump starting from first_in_nest */
+ if (create_priority_nest(first_in_nest) == NULL)
+ return true;
+ }
+ push_select(unit->fake_select_lex);
+ return false;
+}
+
+
+/**
+ Process tail of unit parsed in brackets
+*/
+SELECT_LEX *LEX::parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock * l)
+{
+ pop_select();
+ if (l)
+ {
+ (l)->set_to(unit->fake_select_lex);
+ }
+ return unit->first_select();
+}
+
+
+/**
+ Process select parsed in brackets
+*/
+
+SELECT_LEX *LEX::parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l)
+{
+ pop_select();
+ if (l)
+ {
+ if (sel->next_select())
+ {
+ SELECT_LEX_UNIT *unit= sel->master_unit();
+ if (!unit)
+ unit= create_unit(sel);
+ if (!unit)
+ return NULL;
+ if (!unit->fake_select_lex->is_set_query_expr_tail)
+ l->set_to(unit->fake_select_lex);
+ else
+ {
+ sel= wrap_unit_into_derived(unit);
+ if (!sel)
+ return NULL;
+ l->set_to(sel);
+ }
+ }
+ else if (!sel->is_set_query_expr_tail)
+ {
+ l->set_to(sel);
+ }
+ else
+ {
+ SELECT_LEX_UNIT *unit= create_unit(sel);
+ if (!unit)
+ return NULL;
+ sel= wrap_unit_into_derived(unit);
+ if (!sel)
+ return NULL;
+ l->set_to(sel);
+ }
+ }
+ return sel;
+}
+
+
+/**
+ Process select parsed in brackets
+*/
+
+SELECT_LEX *LEX::parsed_select_in_brackets(SELECT_LEX *sel,
+ Lex_order_limit_lock * l)
+{
+ sel->braces= TRUE;
+ return parsed_select(sel, l);
+}
+
+
+SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
+ enum sub_select_type unit_type,
+ bool distinct)
+{
+ SELECT_LEX_UNIT *res;
+ SELECT_LEX *sel1;
+ SELECT_LEX *sel2;
+ if (!s1->next_select())
+ sel1= s1;
+ else
+ {
+ sel1= wrap_unit_into_derived(s1->master_unit());
+ if (!sel1)
+ return NULL;
+ }
+ if (!s2->next_select())
+ sel2= s2;
+ else
+ {
+ sel2= wrap_unit_into_derived(s2->master_unit());
+ if (!sel2)
+ return NULL;
+ }
+ sel1->link_neighbour(sel2);
+ sel2->set_linkage_and_distinct(unit_type, distinct);
+ sel2->first_nested= sel1->first_nested= sel1;
+ res= create_unit(sel1);
+ if (res == NULL)
+ return NULL;
+ res->pre_last_parse= sel1;
+ return res;
+}
+
+
+SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *s2,
+ enum sub_select_type unit_type,
+ bool distinct, bool oracle)
+{
+ SELECT_LEX *sel1;
+ if (!s2->next_select())
+ sel1= s2;
+ else
+ {
+ sel1= wrap_unit_into_derived(s2->master_unit());
+ if (!sel1)
+ return NULL;
+ }
+ SELECT_LEX *last= unit->pre_last_parse->next_select();
+
+ int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage());
+ if (cmp == 0)
+ {
+ sel1->first_nested= last->first_nested;
+ }
+ else if (cmp > 0)
+ {
+ last->first_nested= unit->pre_last_parse;
+ sel1->first_nested= last;
+ }
+ else /* cmp < 0 */
+ {
+ SELECT_LEX *first_in_nest= last->first_nested;
+ if (first_in_nest->first_nested != first_in_nest)
+ {
+ /* There is a priority jump starting from first_in_nest */
+ if ((last= create_priority_nest(first_in_nest)) == NULL)
+ return NULL;
+ }
+ sel1->first_nested= last->first_nested;
+ }
+ last->link_neighbour(sel1);
+ sel1->set_master_unit(unit);
+ sel1->set_linkage_and_distinct(unit_type, distinct);
+ unit->pre_last_parse= last;
+ return unit;
+}
+
+/**
+ Process parsed select in body
+*/
+
+SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel,
+ Lex_order_limit_lock * l)
+{
+ if (!(sel= parsed_select(sel, l)))
+ return NULL;
+
+ SELECT_LEX_UNIT *res= create_unit(sel);
+ return res;
+}
+
+/**
+ Process parsed unit in body
+*/
+
+bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
+{
+ SELECT_LEX *first_in_nest=
+ unit->pre_last_parse->next_select()->first_nested;
+ if (first_in_nest->first_nested != first_in_nest)
+ {
+ /* There is a priority jump starting from first_in_nest */
+ if (create_priority_nest(first_in_nest) == NULL)
+ return true;
+ }
+ push_select(unit->fake_select_lex);
+ return false;
+}
+
+/**
+ Process parsed tail of unit in body
+
+ TODO: make processing for double tail case
+*/
+
+SELECT_LEX_UNIT *LEX::parsed_body_unit_tail(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock * l)
+{
+ pop_select();
+ if (l)
+ {
+ (l)->set_to(unit->fake_select_lex);
+ }
+ return unit;
+}
+
+/**
+ Process subselect parsing
+*/
+
+SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit, char *place)
+{
+ if (!expr_allows_subselect ||
+ sql_command == (int)SQLCOM_PURGE)
+ {
+ thd->parse_error(ER_SYNTAX_ERROR, place);
+ return NULL;
+ }
+
+ // Add the subtree of subquery to the current SELECT_LEX
+ SELECT_LEX *curr_sel= select_stack_head();
+ DBUG_ASSERT(current_select == curr_sel);
+ if (curr_sel)
+ {
+ curr_sel->register_unit(unit, &curr_sel->context);
+ curr_sel->add_statistics(unit);
+ }
+
+ return unit->first_select();
+}
+
+
+/**
+ Process INSERT-like select
+*/
+
+bool LEX::parsed_insert_select(SELECT_LEX *first_select)
+{
+ if (sql_command == SQLCOM_INSERT ||
+ sql_command == SQLCOM_REPLACE)
+ {
+ if (sql_command == SQLCOM_INSERT)
+ sql_command= SQLCOM_INSERT_SELECT;
+ else
+ sql_command= SQLCOM_REPLACE_SELECT;
+ }
+ insert_select_hack(first_select);
+ if (check_main_unit_semantics())
+ return true;
+
+ // fix "main" select
+ SELECT_LEX *blt= pop_select();
+ DBUG_ASSERT(blt == &builtin_select);
+ push_select(first_select);
+ return false;
+}
+
+
+bool LEX::parsed_TVC_start()
+{
+ SELECT_LEX *sel;
+ many_values.empty();
+ insert_list= 0;
+ if (!(sel= alloc_select(TRUE)) ||
+ push_select(sel))
+ return true;
+ sel->init_select();
+ sel->braces= FALSE; // just initialisation
+ return false;
+}
+
+
+SELECT_LEX *LEX::parsed_TVC_end()
+{
+
+ SELECT_LEX *res= pop_select(); // above TVC select
+ if (!(res->tvc=
+ new (thd->mem_root) table_value_constr(many_values,
+ res,
+ res->options)))
+ return NULL;
+ many_values.empty();
+ return res;
+}
+
+
+TABLE_LIST *LEX::parsed_derived_select(SELECT_LEX *sel, int for_system_time,
+ LEX_CSTRING *alias)
+{
+ TABLE_LIST *res;
+ derived_tables|= DERIVED_SUBQUERY;
+ sel->set_linkage(DERIVED_TABLE_TYPE);
+ sel->braces= FALSE;
+ // Add the subtree of subquery to the current SELECT_LEX
+ SELECT_LEX *curr_sel= select_stack_head();
+ DBUG_ASSERT(current_select == curr_sel);
+ SELECT_LEX_UNIT *unit= sel->master_unit();
+ if (!unit)
+ {
+ unit= create_unit(sel);
+ if (!unit)
+ return NULL;
+ }
+ curr_sel->register_unit(unit, &curr_sel->context);
+ curr_sel->add_statistics(unit);
+
+ Table_ident *ti= new (thd->mem_root) Table_ident(unit);
+ if (ti == NULL)
+ return NULL;
+ if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0,
+ TL_READ, MDL_SHARED_READ)))
+ return NULL;
+ if (for_system_time)
+ {
+ res->vers_conditions= vers_conditions;
+ }
+ return res;
+}
+
+TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
+ int for_system_time,
+ LEX_CSTRING *alias)
+{
+ TABLE_LIST *res;
+ derived_tables|= DERIVED_SUBQUERY;
+ unit->first_select()->set_linkage(DERIVED_TABLE_TYPE);
+
+ // Add the subtree of subquery to the current SELECT_LEX
+ SELECT_LEX *curr_sel= select_stack_head();
+ DBUG_ASSERT(current_select == curr_sel);
+ curr_sel->register_unit(unit, &curr_sel->context);
+ curr_sel->add_statistics(unit);
+
+ Table_ident *ti= new (thd->mem_root) Table_ident(unit);
+ if (ti == NULL)
+ return NULL;
+ if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0,
+ TL_READ, MDL_SHARED_READ)))
+ return NULL;
+ if (for_system_time)
+ {
+ res->vers_conditions= vers_conditions;
+ }
+ return res;
+}
+
+bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check)
+{
+ SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list;
+ set_main_unit(unit);
+ if (check_main_unit_semantics())
+ return true;
+ first_select_lex()->table_list.push_front(save);
+ current_select= first_select_lex();
+ size_t len= thd->m_parser_state->m_lip.get_cpp_ptr() -
+ create_view->select.str;
+ void *create_view_select= thd->memdup(create_view->select.str, len);
+ create_view->select.length= len;
+ create_view->select.str= (char *) create_view_select;
+ size_t not_used;
+ trim_whitespace(thd->charset(),
+ &create_view->select, &not_used);
+ create_view->check= check;
+ parsing_options.allows_variable= TRUE;
+ return false;
+}
+
+bool LEX::select_finalize(st_select_lex_unit *expr)
+{
+ sql_command= SQLCOM_SELECT;
+ selects_allow_into= TRUE;
+ selects_allow_procedure= TRUE;
+ set_main_unit(expr);
+ return check_main_unit_semantics();
+}
+
+
+/*
+ "IN" and "EXISTS" subselect can appear in two statement types:
+
+ 1. Statements that can have table columns, such as SELECT, DELETE, UPDATE
+ 2. Statements that cannot have table columns, e.g:
+ RETURN ((1) IN (SELECT * FROM t1))
+ IF ((1) IN (SELECT * FROM t1))
+
+ Statements of the first type call master_select_push() in the beginning.
+ In such case everything is properly linked.
+
+ Statements of the second type do not call mastr_select_push().
+ Here we catch the second case and relink thd->lex->builtin_select and
+ select_lex to properly point to each other.
+
+ QQ: Shouldn't subselects of other type also call relink_hack()?
+ QQ: Can we do it at constructor time instead?
+*/
+
+void LEX::relink_hack(st_select_lex *select_lex)
+{
+ if (!select_stack_top) // Statements of the second type
+ {
+ if (!select_lex->get_master()->get_master())
+ ((st_select_lex *) select_lex->get_master())->
+ set_master(&builtin_select);
+ if (!builtin_select.get_slave())
+ builtin_select.set_slave(select_lex->get_master());
+ }
+}
+
+
+
+bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l)
+{
+ if (l.defined_lock)
+ {
+ SELECT_LEX *sel= first_select();
+ while (sel->next_select())
+ sel= sel->next_select();
+ if (sel->braces)
+ {
+ my_error(ER_WRONG_USAGE, MYF(0), "lock options",
+ "End SELECT expression");
+ return TRUE;
+ }
+ l.set_to(sel);
+ }
+ return FALSE;
+}
+
+/**
+ Generate unique name for generated derived table for this SELECT
+*/
+
+bool SELECT_LEX::make_unique_derived_name(THD *thd, LEX_CSTRING *alias)
+{
+ // uint32 digits + two underscores + trailing '\0'
+ char buff[MAX_INT_WIDTH + 2 + 1];
+ alias->length= my_snprintf(buff, sizeof(buff), "__%u", select_number);
+ alias->str= thd->strmake(buff, alias->length);
+ return !alias->str;
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 49e10421911..24788158d26 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -162,6 +162,23 @@ public:
};
+/**
+ ORDER BY ... LIMIT parameters;
+*/
+class Lex_order_limit_lock: public Sql_alloc
+{
+public:
+ SQL_I_List<st_order> *order_list; /* ORDER clause */
+ Lex_select_lock lock;
+ Lex_select_limit limit;
+
+ Lex_order_limit_lock() :order_list(NULL)
+ {}
+
+ bool set_to(st_select_lex *sel);
+};
+
+
enum sub_select_type
{
UNSPECIFIED_TYPE,
@@ -169,6 +186,14 @@ enum sub_select_type
UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE,
GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE
};
+
+inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2)
+{
+ DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE);
+ DBUG_ASSERT(op2 >= UNION_TYPE && op2 <= EXCEPT_TYPE);
+ return (op1 == INTERSECT_TYPE ? 1 : 0) - (op2 == INTERSECT_TYPE ? 1 : 0);
+}
+
enum unit_common_op {OP_MIX, OP_UNION, OP_INTERSECT, OP_EXCEPT};
enum enum_view_suid
@@ -287,7 +312,8 @@ struct LEX_TYPE
This is not within #ifdef because we want "EXPLAIN PARTITIONS ..." to produce
additional "partitions" column even if partitioning is not compiled in.
*/
-#define DESCRIBE_PARTITIONS 4
+#define DESCRIBE_PARTITIONS 4
+#define DESCRIBE_EXTENDED2 8
#ifdef MYSQL_SERVER
@@ -526,7 +552,7 @@ public:
unit is container of either
- One SELECT
- UNION of selects
- select_lex and unit are both inherited form select_lex_node
+ select_lex and unit are both inherited form st_select_lex_node
neighbors are two select_lex or units on the same level
All select describing structures linked with following pointers:
@@ -651,13 +677,6 @@ public:
ulonglong options;
/*
- In sql_cache we store SQL_CACHE flag as specified by user to be
- able to restore SELECT statement from internal structures.
- */
- enum e_sql_cache { SQL_CACHE_UNSPECIFIED, SQL_NO_CACHE, SQL_CACHE };
- e_sql_cache sql_cache;
-
- /*
result of this query can't be cached, bit field, can be :
UNCACHEABLE_DEPENDENT_GENERATED
UNCACHEABLE_DEPENDENT_INJECTED
@@ -667,11 +686,15 @@ public:
UNCACHEABLE_PREPARE
*/
uint8 uncacheable;
+private:
enum sub_select_type linkage;
+public:
bool is_linkage_set() const
{
return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE;
}
+ enum sub_select_type get_linkage() { return linkage; }
+ bool distinct;
bool no_table_names_allowed; /* used for global order by */
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
@@ -689,13 +712,33 @@ public:
}
inline st_select_lex_node* get_master() { return master; }
+ inline st_select_lex_node* get_slave() { return slave; }
void include_down(st_select_lex_node *upper);
void add_slave(st_select_lex_node *slave_arg);
void include_neighbour(st_select_lex_node *before);
+ void link_chain_down(st_select_lex_node *first);
+ void link_neighbour(st_select_lex_node *neighbour)
+ {
+ DBUG_ASSERT(next == NULL);
+ DBUG_ASSERT(neighbour != NULL);
+ next= neighbour;
+ neighbour->prev= &next;
+ }
+ void cut_next() { next= NULL; }
void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref);
void include_global(st_select_lex_node **plink);
void exclude();
void exclude_from_tree();
+ void exclude_from_global()
+ {
+ if (!link_prev)
+ return;
+ if (((*link_prev)= link_next))
+ link_next->link_prev= link_prev;
+ link_next= NULL;
+ link_prev= NULL;
+ }
+
void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; }
void move_node(st_select_lex_node *where_to_move)
@@ -711,6 +754,22 @@ public:
st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert,
st_select_lex_node *end_chain_node);
void move_as_slave(st_select_lex_node *new_master);
+ void set_linkage(enum sub_select_type l)
+ {
+ DBUG_ENTER("st_select_lex_node::set_linkage");
+ DBUG_PRINT("info", ("node: %p linkage: %d->%d", this, linkage, l));
+ linkage= l;
+ DBUG_VOID_RETURN;
+ }
+ /*
+ This method created for reiniting LEX in mysql_admin_table() and can be
+ used only if you are going remove all SELECT_LEX & units except belonger
+ to LEX (LEX::unit & LEX::select, for other purposes there are
+ SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree.
+
+ It is also used in parsing to detach builtin select.
+ */
+ void cut_subtree() { slave= 0; }
friend class st_select_lex_unit;
friend bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel);
friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
@@ -720,6 +779,8 @@ public:
friend bool mysql_derived_merge(THD *thd, LEX *lex,
TABLE_LIST *orig_table_list);
friend bool TABLE_LIST::init_derived(THD *thd, bool init_view);
+
+ friend class st_select_lex;
private:
void fast_exclude();
};
@@ -765,9 +826,9 @@ public:
{
}
-
TABLE *table; /* temporary table using for appending UNION results */
select_result *result;
+ st_select_lex *pre_last_parse;
bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
optimized_2,
@@ -854,7 +915,7 @@ public:
{
return reinterpret_cast<st_select_lex*>(slave);
}
- inline void set_with_clause(With_clause *with_cl);
+ void set_with_clause(With_clause *with_cl);
st_select_lex_unit* next_unit()
{
return reinterpret_cast<st_select_lex_unit*>(next);
@@ -897,6 +958,18 @@ public:
int save_union_explain(Explain_query *output);
int save_union_explain_part2(Explain_query *output);
unit_common_op common_op();
+
+ void reset_distinct();
+ void fix_distinct(st_select_lex_unit *new_unit);
+
+ void register_select_chain(SELECT_LEX *first_sel);
+
+ bool set_nest_level(int new_nest_level);
+ bool check_parameters(SELECT_LEX *main_select);
+
+ bool set_lock_to_the_last_select(Lex_select_lock l);
+
+ friend class st_select_lex;
};
typedef class st_select_lex_unit SELECT_LEX_UNIT;
@@ -904,25 +977,42 @@ typedef Bounds_checked_array<Item*> Ref_ptr_array;
/*
- Structure which consists of the field and the item which
- produces this field.
+ Structure which consists of the field and the item that
+ corresponds to this field.
*/
-
-class Grouping_tmp_field :public Sql_alloc
+class Field_pair :public Sql_alloc
{
public:
- Field *tmp_field;
- Item *producing_item;
- Grouping_tmp_field(Field *fld, Item *item)
- :tmp_field(fld), producing_item(item) {}
+ Field *field;
+ Item *corresponding_item;
+ Field_pair(Field *fld, Item *item)
+ :field(fld), corresponding_item(item) {}
};
+
/*
SELECT_LEX - store information of parsed SELECT statment
*/
class st_select_lex: public st_select_lex_node
{
public:
+ /*
+ Currently the field first_nested is used only by parser.
+ It containa either a reference to the first select
+ of the nest of selects to which 'this' belongs to, or
+ in the case of priority jump it contains a reference to
+ the select to which the priority nest has to be attached to.
+ If there is no priority jump then the first select of the
+ nest contains the reference to itself in first_nested.
+ Example:
+ select1 union select2 intersect select
+ Here we have a priority jump at select2.
+ So select2->first_nested points to select1,
+ while select3->first_nested points to select2 and
+ select1->first_nested points to select1.
+ */
+ st_select_lex *first_nested;
+
Name_resolution_context context;
LEX_CSTRING db;
Item *where, *having; /* WHERE & HAVING clauses */
@@ -1018,6 +1108,7 @@ public:
SQL_I_List<ORDER> order_list; /* ORDER clause */
SQL_I_List<ORDER> gorder_list;
Item *select_limit, *offset_limit; /* LIMIT clause parameters */
+ bool is_set_query_expr_tail;
/// Array of pointers to top elements of all_fields list
Ref_ptr_array ref_pointer_array;
@@ -1140,7 +1231,8 @@ public:
nesting_map name_visibility_map;
table_map with_dep;
- List<Grouping_tmp_field> grouping_tmp_fields;
+ /* the structure to store fields that are used in the GROUP BY of this select */
+ List<Field_pair> grouping_tmp_fields;
/* it is for correct printing SELECT options */
thr_lock_type lock_type;
@@ -1158,6 +1250,14 @@ public:
void init_query();
void init_select();
st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; }
+ inline void set_master_unit(st_select_lex_unit *master_unit)
+ {
+ master= (st_select_lex_node *)master_unit;
+ }
+ void set_master(st_select_lex *master_arg)
+ {
+ master= master_arg;
+ }
st_select_lex_unit* first_inner_unit()
{
return (st_select_lex_unit*) slave;
@@ -1209,12 +1309,6 @@ public:
List<Item>* get_item_list();
ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type);
- inline void init_order()
- {
- order_list.elements= 0;
- order_list.first= 0;
- order_list.next= &order_list.first;
- }
/*
This method created for reiniting LEX in mysql_admin_table() and can be
used only if you are going remove all SELECT_LEX & units except belonger
@@ -1345,9 +1439,8 @@ public:
With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
bool check_unrestricted_recursive(bool only_standard_compliant);
bool check_subqueries_with_recursive_references();
- void collect_grouping_fields(THD *thd, ORDER *grouping_list);
- void check_cond_extraction_for_grouping_fields(Item *cond,
- TABLE_LIST *derived);
+ void collect_grouping_fields(THD *thd, ORDER *grouping_list);
+ void check_cond_extraction_for_grouping_fields(Item *cond);
Item *build_cond_for_grouping_fields(THD *thd, Item *cond,
bool no_to_clones);
@@ -1373,6 +1466,11 @@ public:
bool cond_pushdown_is_allowed() const
{ return !olap && !explicit_limit && !tvc; }
+ void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond,
+ Item **remaining_cond,
+ Item_transformer transformer,
+ uchar *arg);
+
private:
bool m_non_agg_field_used;
bool m_agg_func_used;
@@ -1390,6 +1488,35 @@ public:
DBUG_ASSERT(this != sel);
select_n_where_fields+= sel->select_n_where_fields;
}
+ inline void set_linkage_and_distinct(enum sub_select_type l, bool d)
+ {
+ DBUG_ENTER("SELECT_LEX::set_linkage_and_distinct");
+ DBUG_PRINT("info", ("select: %p distinct %d", this, d));
+ set_linkage(l);
+ DBUG_ASSERT(l == UNION_TYPE ||
+ l == INTERSECT_TYPE ||
+ l == EXCEPT_TYPE);
+ if (d && master_unit() && master_unit()->union_distinct != this)
+ master_unit()->union_distinct= this;
+ distinct= d;
+ with_all_modifier= !distinct;
+ DBUG_VOID_RETURN;
+ }
+ bool set_nest_level(int new_nest_level);
+ bool check_parameters(SELECT_LEX *main_select);
+ void mark_select()
+ {
+ DBUG_ENTER("st_select_lex::mark_select()");
+ DBUG_PRINT("info", ("Select #%d", select_number));
+ DBUG_VOID_RETURN;
+ }
+ void register_unit(SELECT_LEX_UNIT *unit,
+ Name_resolution_context *outer_context);
+ SELECT_LEX_UNIT *attach_selects_chain(SELECT_LEX *sel,
+ Name_resolution_context *context);
+ void add_statistics(SELECT_LEX_UNIT *unit);
+ bool make_unique_derived_name(THD *thd, LEX_CSTRING *alias);
+ void lex_start(LEX *plex);
};
typedef class st_select_lex SELECT_LEX;
@@ -2789,8 +2916,13 @@ class Query_arena_memroot;
struct LEX: public Query_tables_list
{
SELECT_LEX_UNIT unit; /* most upper unit */
- SELECT_LEX select_lex; /* first SELECT_LEX */
+ inline SELECT_LEX *first_select_lex() {return unit.first_select();}
+
+private:
+ SELECT_LEX builtin_select;
/* current SELECT_LEX in parsing */
+
+public:
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
@@ -2887,6 +3019,12 @@ private:
bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop);
bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
+ /*
+ Check if Item_field and Item_ref are allowed in the current statement.
+ @retval false OK (fields are allowed)
+ @retval true ERROR (fields are not allowed). Error is raised.
+ */
+ bool check_expr_allows_fields_or_error(THD *thd, const char *name) const;
public:
void parse_error(uint err_number= ER_SYNTAX_ERROR);
inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
@@ -2914,6 +3052,8 @@ public:
required a local context, the parser pops the top-most context.
*/
List<Name_resolution_context> context_stack;
+ SELECT_LEX *select_stack[MAX_SELECT_NESTING + 1];
+ uint select_stack_top;
SQL_I_List<ORDER> proc_list;
SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list;
@@ -2953,6 +3093,8 @@ public:
syntax error back.
*/
bool expr_allows_subselect;
+ bool selects_allow_into;
+ bool selects_allow_procedure;
/*
A special command "PARSE_VCOL_EXPR" is defined for the parser
to translate a defining expression of a virtual column into an
@@ -3007,7 +3149,17 @@ public:
enum enum_yes_no_unknown tx_chain, tx_release;
bool safe_to_cache_query;
bool subqueries, ignore;
+ bool next_is_main; // use "main" SELECT_LEX for nrxt allocation;
+ bool next_is_down; // use "main" SELECT_LEX for nrxt allocation;
st_parsing_options parsing_options;
+ uint8 lex_options; // see OPTION_LEX_*
+ /*
+ In sql_cache we store SQL_CACHE flag as specified by user to be
+ able to restore SELECT statement from internal structures.
+ */
+ enum e_sql_cache { SQL_CACHE_UNSPECIFIED, SQL_NO_CACHE, SQL_CACHE };
+ e_sql_cache sql_cache;
+
Alter_info alter_info;
/*
For CREATE TABLE statement last element of table list which is not
@@ -3206,20 +3358,24 @@ public:
SELECT_LEX *sl;
SELECT_LEX_UNIT *un;
for (sl= current_select, un= sl->master_unit();
- un != &unit;
- sl= sl->outer_select(), un= sl->master_unit())
+ un && un != &unit;
+ sl= sl->outer_select(), un= (sl ? sl->master_unit() : NULL))
{
- sl->uncacheable|= cause;
- un->uncacheable|= cause;
+ sl->uncacheable|= cause;
+ un->uncacheable|= cause;
}
- select_lex.uncacheable|= cause;
+ if (sl)
+ sl->uncacheable|= cause;
}
+ if (first_select_lex())
+ first_select_lex()->uncacheable|= cause;
}
void set_trg_event_type_for_tables();
TABLE_LIST *unlink_first_table(bool *link_to_local);
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
void first_lists_tables_same();
+ void fix_first_select_number();
bool can_be_merged();
bool can_use_merged();
@@ -3257,14 +3413,83 @@ public:
void cleanup_after_one_table_open();
- bool push_context(Name_resolution_context *context, MEM_ROOT *mem_root)
+ bool push_context(Name_resolution_context *context);
+
+ void pop_context()
{
- return context_stack.push_front(context, mem_root);
+ DBUG_ENTER("LEX::pop_context");
+ Name_resolution_context *context= context_stack.pop();
+ DBUG_PRINT("info", ("Pop context %p Select: %p (%d)",
+ context, context->select_lex,
+ (context->select_lex ?
+ context->select_lex->select_number:
+ 0)));
+ DBUG_VOID_RETURN;
}
- void pop_context()
+ SELECT_LEX *select_stack_head()
+ {
+ if (likely(select_stack_top))
+ return select_stack[select_stack_top - 1];
+ return NULL;
+ }
+
+ bool push_select(SELECT_LEX *select_lex)
+ {
+ DBUG_ENTER("LEX::push_select");
+ DBUG_PRINT("info", ("Top Select was %p (%d) depth: %u pushed: %p (%d)",
+ select_stack_head(),
+ select_stack_top,
+ (select_stack_top ?
+ select_stack_head()->select_number :
+ 0),
+ select_lex, select_lex->select_number));
+ if (unlikely(select_stack_top > MAX_SELECT_NESTING))
+ {
+ my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (push_context(&select_lex->context))
+ DBUG_RETURN(TRUE);
+ select_stack[select_stack_top++]= select_lex;
+ current_select= select_lex;
+ DBUG_RETURN(FALSE);
+ }
+
+ SELECT_LEX *pop_select()
+ {
+ DBUG_ENTER("LEX::pop_select");
+ SELECT_LEX *select_lex;
+ if (likely(select_stack_top))
+ select_lex= select_stack[--select_stack_top];
+ else
+ select_lex= 0;
+ DBUG_PRINT("info", ("Top Select is %p (%d) depth: %u poped: %p (%d)",
+ select_stack_head(),
+ select_stack_top,
+ (select_stack_top ?
+ select_stack_head()->select_number :
+ 0),
+ select_lex,
+ (select_lex ? select_lex->select_number : 0)));
+ DBUG_ASSERT(select_lex);
+
+ pop_context();
+
+ if (unlikely(!select_stack_top))
+ {
+ current_select= NULL;
+ DBUG_PRINT("info", ("Top Select is empty"));
+ }
+ else
+ current_select= select_stack[select_stack_top - 1];
+
+ DBUG_RETURN(select_lex);
+ }
+
+ SELECT_LEX *current_select_or_default()
{
- context_stack.pop();
+ return current_select ? current_select : &builtin_select;
}
bool copy_db_to(LEX_CSTRING *to);
@@ -3273,6 +3498,7 @@ public:
{
return context_stack.head();
}
+
/*
Restore the LEX and THD in case of a parse error.
*/
@@ -3301,9 +3527,8 @@ public:
on its top. So select_lex (as the first added) will be at the tail
of the list.
*/
- if (&select_lex == all_selects_list && !sroutines.records)
+ if (first_select_lex() == all_selects_list && !sroutines.records)
{
- DBUG_ASSERT(!all_selects_list->next_select_in_list());
return TRUE;
}
return FALSE;
@@ -3342,9 +3567,6 @@ public:
int case_stmt_action_expr(Item* expr);
int case_stmt_action_when(Item *when, bool simple);
int case_stmt_action_then();
- bool add_select_to_union_list(bool is_union_distinct,
- enum sub_select_type type,
- bool is_top_level);
bool setup_select_in_parentheses();
bool set_trigger_new_row(const LEX_CSTRING *name, Item *val);
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
@@ -3469,7 +3691,12 @@ public:
return create_item_qualified_asterisk(thd, &a, &b);
}
- Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name);
+ Item *create_item_ident_field(THD *thd, const char *db, const char *table,
+ const Lex_ident_sys_st *name);
+ Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name)
+ {
+ return create_item_ident_field(thd, NullS, NullS, name);
+ }
Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
const char *start, const char *end);
Item *create_item_ident(THD *thd, Lex_ident_cli_st *cname)
@@ -3607,6 +3834,10 @@ public:
const Lex_ident_cli_st *var_name,
const Lex_ident_cli_st *field_name);
+ Item *create_item_query_expression(THD *thd,
+ const char *tok_start,
+ st_select_lex_unit *unit);
+
Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace);
Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c);
Item *make_item_func_substr(THD *thd, Item *a, Item *b);
@@ -3801,6 +4032,17 @@ public:
sp_for_loop_intrange_finalize(thd, loop);
}
bool sp_for_loop_outer_block_finalize(THD *thd, const Lex_for_loop_st &loop);
+
+ /*
+ Make an Item when an identifier is found in the FOR loop bounds:
+ FOR rec IN cursor
+ FOR rec IN var1 .. var2
+ FOR rec IN row1.field1 .. xxx
+ */
+ Item *create_item_for_loop_bound(THD *thd,
+ const LEX_CSTRING *a,
+ const LEX_CSTRING *b,
+ const LEX_CSTRING *c);
/* End of FOR LOOP methods */
bool add_signal_statement(THD *thd, const class sp_condition_value *value);
@@ -3923,7 +4165,7 @@ public:
bool if_exists() const { return create_info.if_exists(); }
SELECT_LEX *exclude_last_select();
- bool add_unit_in_brackets(SELECT_LEX *nselect);
+ SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude);
void check_automatic_up(enum sub_select_type type);
bool create_or_alter_view_finalize(THD *thd, Table_ident *table_ident);
bool add_alter_view(THD *thd, uint16 algorithm, enum_view_suid suid,
@@ -3931,7 +4173,6 @@ public:
bool add_create_view(THD *thd, DDL_options_st ddl,
uint16 algorithm, enum_view_suid suid,
Table_ident *table_ident);
-
bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
stored_procedure_type type_arg);
@@ -3950,7 +4191,7 @@ public:
*/
bool check_simple_select(const LEX_CSTRING *option)
{
- if (current_select != &select_lex)
+ if (current_select != &builtin_select)
{
char command[80];
strmake(command, option->str, MY_MIN(option->length, sizeof(command)-1));
@@ -3968,6 +4209,63 @@ public:
}
bool tvc_finalize();
bool tvc_finalize_derived();
+
+ bool make_select_in_brackets(SELECT_LEX* dummy_select,
+ SELECT_LEX *nselect, bool automatic);
+
+ SELECT_LEX_UNIT *alloc_unit();
+ SELECT_LEX *alloc_select(bool is_select);
+ SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
+ SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit);
+ SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel);
+ bool main_select_push();
+ bool insert_select_hack(SELECT_LEX *sel);
+ SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest);
+
+ void set_main_unit(st_select_lex_unit *u)
+ {
+ unit.options= u->options;
+ unit.uncacheable= u->uncacheable;
+ unit.register_select_chain(u->first_select());
+ unit.first_select()->options|= builtin_select.options;
+ unit.fake_select_lex= u->fake_select_lex;
+ unit.union_distinct= u->union_distinct;
+ unit.set_with_clause(u->with_clause);
+ builtin_select.exclude_from_global();
+ }
+ bool check_main_unit_semantics();
+
+ // reaction on different parsed parts (bodies are in sql_yacc.yy)
+ bool parsed_unit_in_brackets(SELECT_LEX_UNIT *unit);
+ SELECT_LEX *parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l);
+ SELECT_LEX *parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock * l);
+ SELECT_LEX *parsed_select_in_brackets(SELECT_LEX *sel,
+ Lex_order_limit_lock * l);
+ SELECT_LEX_UNIT *parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
+ enum sub_select_type unit_type,
+ bool distinct);
+ SELECT_LEX_UNIT *parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
+ SELECT_LEX *s2,
+ enum sub_select_type unit_type,
+ bool distinct, bool oracle);
+ SELECT_LEX_UNIT *parsed_body_select(SELECT_LEX *sel,
+ Lex_order_limit_lock * l);
+ bool parsed_body_unit(SELECT_LEX_UNIT *unit);
+ SELECT_LEX_UNIT *parsed_body_unit_tail(SELECT_LEX_UNIT *unit,
+ Lex_order_limit_lock * l);
+ SELECT_LEX *parsed_subselect(SELECT_LEX_UNIT *unit, char *place);
+ bool parsed_insert_select(SELECT_LEX *firs_select);
+ bool parsed_TVC_start();
+ SELECT_LEX *parsed_TVC_end();
+ TABLE_LIST *parsed_derived_select(SELECT_LEX *sel, int for_system_time,
+ LEX_CSTRING *alias);
+ TABLE_LIST *parsed_derived_unit(SELECT_LEX_UNIT *unit,
+ int for_system_time,
+ LEX_CSTRING *alias);
+ bool parsed_create_view(SELECT_LEX_UNIT *unit, int check);
+ bool select_finalize(st_select_lex_unit *expr);
+ void relink_hack(st_select_lex *select_lex);
};
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 39a1c3375e0..27827b42be5 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -611,7 +611,7 @@ struct ilink
struct ilink **prev,*next;
static void *operator new(size_t size) throw ()
{
- return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATALERROR));
+ return (void*)my_malloc((uint)size, MYF(MY_WME | MY_FAE | ME_FATAL));
}
static void operator delete(void* ptr_arg, size_t)
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index ddb5029c78a..dd6e723c953 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -390,10 +390,13 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list,
if (mysql_handle_single_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) ||
mysql_handle_single_derived(thd->lex, table_list, DT_PREPARE))
DBUG_RETURN(TRUE);
- if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
- &thd->lex->select_lex.top_join_list,
+ if (setup_tables_and_check_access(thd,
+ &thd->lex->first_select_lex()->context,
+ &thd->lex->first_select_lex()->
+ top_join_list,
table_list,
- thd->lex->select_lex.leaf_tables, FALSE,
+ thd->lex->first_select_lex()->leaf_tables,
+ FALSE,
INSERT_ACL | UPDATE_ACL,
INSERT_ACL | UPDATE_ACL, FALSE))
DBUG_RETURN(-1);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c68e91bbef3..201cb4f1dbe 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2008,10 +2008,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
Init TABLE_LIST members necessary when the undelrying
table is view.
*/
- table_list.select_lex= &(thd->lex->select_lex);
+ table_list.select_lex= thd->lex->first_select_lex();
thd->lex->
- select_lex.table_list.link_in_list(&table_list,
- &table_list.next_local);
+ first_select_lex()->table_list.link_in_list(&table_list,
+ &table_list.next_local);
thd->lex->add_to_query_tables(&table_list);
if (is_infoschema_db(&table_list.db))
@@ -2575,23 +2575,24 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
DBUG_RETURN(1);
#else
{
- if (lex->select_lex.db.str == NULL &&
- lex->copy_db_to(&lex->select_lex.db))
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
{
DBUG_RETURN(1);
}
schema_select_lex= new (thd->mem_root) SELECT_LEX();
schema_select_lex->table_list.first= NULL;
if (lower_case_table_names == 1)
- lex->select_lex.db.str= thd->strdup(lex->select_lex.db.str);
- schema_select_lex->db= lex->select_lex.db;
+ lex->first_select_lex()->db.str=
+ thd->strdup(lex->first_select_lex()->db.str);
+ schema_select_lex->db= lex->first_select_lex()->db;
/*
check_db_name() may change db.str if lower_case_table_names == 1,
but that's ok as the db is allocted above in this case.
*/
- if (check_db_name((LEX_STRING*) &lex->select_lex.db))
+ if (check_db_name((LEX_STRING*) &lex->first_select_lex()->db))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), lex->select_lex.db.str);
+ my_error(ER_WRONG_DB_NAME, MYF(0), lex->first_select_lex()->db.str);
DBUG_RETURN(1);
}
break;
@@ -2630,7 +2631,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
default:
break;
}
-
+ if (schema_select_lex)
+ schema_select_lex->set_master_unit(&lex->unit);
SELECT_LEX *select_lex= lex->current_select;
if (make_schema_select(thd, select_lex, get_schema_table(schema_table_idx)))
DBUG_RETURN(1);
@@ -3227,7 +3229,7 @@ mysql_execute_command(THD *thd)
int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= select_lex->table_list.first;
/* list of all tables in query */
@@ -3266,6 +3268,7 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
*/
lex->first_lists_tables_same();
+ lex->fix_first_select_number();
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
/* set context for commands which do not use setup_tables */
@@ -7521,7 +7524,7 @@ bool check_stack_overrun(THD *thd, long margin,
if (ebuff) {
my_snprintf(ebuff, MYSQL_ERRMSG_SIZE, ER_THD(thd, ER_STACK_OVERRUN_NEED_MORE),
stack_used, my_thread_stack_size, margin);
- my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));
+ my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATAL));
delete [] ebuff;
}
return 1;
@@ -7591,16 +7594,21 @@ void THD::reset_for_next_command(bool do_clear_error)
DBUG_ASSERT(!in_sub_stmt);
if (likely(do_clear_error))
+ {
clear_error(1);
-
+ /*
+ The following variable can't be reset in clear_error() as
+ clear_error() is called during auto_repair of table
+ */
+ error_printed_to_log= 0;
+ }
free_list= 0;
/*
We also assign stmt_lex in lex_start(), but during bootstrap this
code is executed first.
*/
DBUG_ASSERT(lex == &main_lex);
- main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1;
- DBUG_PRINT("info", ("Lex and stmt_lex: %p", &main_lex));
+ main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 0;
/*
Those two lines below are theoretically unneeded as
THD::cleanup_after_query() should take care of this already.
@@ -7686,11 +7694,7 @@ mysql_init_select(LEX *lex)
SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
lex->wild= 0;
- if (select_lex == &lex->select_lex)
- {
- DBUG_ASSERT(lex->result == 0);
- lex->exchange= 0;
- }
+ lex->exchange= 0;
}
@@ -7711,6 +7715,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
{
THD *thd= lex->thd;
bool new_select= select_lex == NULL;
+ int old_nest_level= lex->current_select->nest_level;
DBUG_ENTER("mysql_new_select");
if (new_select)
@@ -7722,27 +7727,19 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
select_lex->init_query();
select_lex->init_select();
}
- lex->nest_level++;
- if (lex->nest_level > (int) MAX_SELECT_NESTING)
- {
- my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
- DBUG_RETURN(1);
- }
- select_lex->nest_level= lex->nest_level;
select_lex->nest_level_base= &thd->lex->unit;
if (move_down)
{
+ lex->nest_level++;
+ if (select_lex->set_nest_level(old_nest_level + 1))
+ DBUG_RETURN(1);
SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
- if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
+ if (!(unit= lex->alloc_unit()))
DBUG_RETURN(1);
- unit->init_query();
- unit->thd= thd;
unit->include_down(lex->current_select);
- unit->link_next= 0;
- unit->link_prev= 0;
unit->return_to= lex->current_select;
select_lex->include_down(unit);
/*
@@ -7776,15 +7773,13 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
"SELECT ... PROCEDURE ANALYSE()");
DBUG_RETURN(TRUE);
}
- // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible
- DBUG_ASSERT(!lex->current_select->order_list.first ||
- lex->current_select->braces);
- // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1; -- not possible
- DBUG_ASSERT(!lex->current_select->explicit_limit ||
- lex->current_select->braces);
+ SELECT_LEX_NODE *save_slave= select_lex->slave;
select_lex->include_neighbour(lex->current_select);
- SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ select_lex->slave= save_slave;
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ if (select_lex->set_nest_level(old_nest_level))
+ DBUG_RETURN(1);
if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
DBUG_RETURN(1);
select_lex->context.outer_context=
@@ -7840,9 +7835,10 @@ void mysql_init_multi_delete(LEX *lex)
{
lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
- lex->select_lex.select_limit= 0;
+ lex->first_select_lex()->select_limit= 0;
lex->unit.select_limit_cnt= HA_POS_ERROR;
- lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
+ lex->first_select_lex()->table_list.
+ save_and_clear(&lex->auxiliary_table_list);
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
}
@@ -8156,7 +8152,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length)
thd->reset_for_next_command();
if (!parse_sql(thd, & parser_state, NULL, true) &&
- all_tables_not_ok(thd, lex->select_lex.table_list.first))
+ all_tables_not_ok(thd, lex->first_select_lex()->table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
}
@@ -8238,6 +8234,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_CSTRING alias_str;
LEX *lex= thd->lex;
DBUG_ENTER("add_table_to_list");
+ DBUG_PRINT("enter", ("Table '%s' (%p) Select %p (%u)",
+ (alias ? alias->str : table->table.str),
+ table,
+ this, select_number));
if (unlikely(!table))
DBUG_RETURN(0); // End of memory
@@ -8331,7 +8331,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->schema_table_name= ptr->table_name;
ptr->schema_table= schema_table;
}
- ptr->select_lex= lex->current_select;
+ ptr->select_lex= this;
/*
We can't cache internal temporary tables between prepares as the
table may be deleted before next exection.
@@ -8438,8 +8438,6 @@ bool st_select_lex::init_nested_join(THD *thd)
nested_join= ptr->nested_join=
((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
- if (unlikely(join_list->push_front(ptr, thd->mem_root)))
- DBUG_RETURN(1);
ptr->embedding= embedding;
ptr->join_list= join_list;
ptr->alias.str="(nested_join)";
@@ -8547,7 +8545,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
ptr->join_using_fields= prev_join_using;
}
}
- join_list->push_front(ptr, thd->mem_root);
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
DBUG_RETURN(ptr);
}
@@ -8739,7 +8736,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
{
SELECT_LEX *first_sl= first_select();
- DBUG_ENTER("add_fake_select_lex");
+ DBUG_ENTER("st_select_lex_unit::add_fake_select_lex");
DBUG_ASSERT(!fake_select_lex);
if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
@@ -8749,16 +8746,19 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
fake_select_lex->select_number= INT_MAX;
fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
fake_select_lex->make_empty_select();
- fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
+ fake_select_lex->set_linkage(GLOBAL_OPTIONS_TYPE);
fake_select_lex->select_limit= 0;
+ fake_select_lex->no_table_names_allowed= 1;
+
fake_select_lex->context.outer_context=first_sl->context.outer_context;
/* allow item list resolving in fake select for ORDER BY */
fake_select_lex->context.resolve_in_select_list= TRUE;
fake_select_lex->context.select_lex= fake_select_lex;
fake_select_lex->nest_level_base= first_select()->nest_level_base;
- fake_select_lex->nest_level=first_select()->nest_level;
+ if (fake_select_lex->set_nest_level(first_select()->nest_level))
+ DBUG_RETURN(1);
if (!is_unit_op())
{
@@ -8771,7 +8771,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
fake_select_lex->no_table_names_allowed= 1;
thd_arg->lex->current_select= fake_select_lex;
}
- thd_arg->lex->pop_context();
+ //thd_arg->lex->pop_context("add fake");
DBUG_RETURN(0);
}
@@ -8807,7 +8807,7 @@ push_new_name_resolution_context(THD *thd,
left_op->first_leaf_for_name_resolution();
on_context->last_name_resolution_table=
right_op->last_leaf_for_name_resolution();
- return thd->lex->push_context(on_context, thd->mem_root);
+ return thd->lex->push_context(on_context);
}
@@ -9236,7 +9236,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
{
TABLE_LIST *table;
LEX *lex= thd->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
DBUG_ENTER("multi_update_precheck");
if (select_lex->item_list.elements != lex->value_list.elements)
@@ -9272,7 +9272,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
/*
Is there tables of subqueries?
*/
- if (&lex->select_lex != lex->all_selects_list)
+ if (lex->first_select_lex() != lex->all_selects_list)
{
DBUG_PRINT("info",("Checking sub query list"));
for (table= tables; table; table= table->next_global)
@@ -9306,7 +9306,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
{
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
DBUG_ENTER("multi_delete_precheck");
@@ -9423,7 +9423,7 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl,
bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
{
- TABLE_LIST *tables= lex->select_lex.table_list.first;
+ TABLE_LIST *tables= lex->first_select_lex()->table_list.first;
TABLE_LIST *target_tbl;
DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
@@ -9465,7 +9465,8 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
bool update_precheck(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("update_precheck");
- if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
+ if (thd->lex->first_select_lex()->item_list.elements !=
+ thd->lex->value_list.elements)
{
my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0));
DBUG_RETURN(TRUE);
@@ -9556,7 +9557,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex)
else
create_table->open_type= OT_BASE_ONLY;
- if (!lex->select_lex.item_list.elements)
+ if (!lex->first_select_lex()->item_list.elements)
{
/*
Avoid opening and locking target table for ordinary CREATE TABLE
@@ -9587,7 +9588,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table)
{
LEX *lex= thd->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
ulong want_priv;
bool error= TRUE; // Error message is given
DBUG_ENTER("create_table_precheck");
@@ -9729,8 +9730,9 @@ Item *negate_expression(THD *thd, Item *expr)
{
/* it is NOT(NOT( ... )) */
Item *arg= ((Item_func *) expr)->arguments()[0];
+ const Type_handler *fh= arg->fixed_type_handler();
enum_parsing_place place= thd->lex->current_select->parsing_place;
- if (arg->is_bool_type() || place == IN_WHERE || place == IN_HAVING)
+ if ((fh && fh->is_bool_type()) || place == IN_WHERE || place == IN_HAVING)
return arg;
/*
if it is not boolean function then we have to emulate value of
@@ -10098,6 +10100,9 @@ bool parse_sql(THD *thd, Parser_state *parser_state,
((thd->variables.sql_mode & MODE_ORACLE) ?
ORAparse(thd) :
MYSQLparse(thd)) != 0;
+ DBUG_ASSERT(opt_bootstrap || mysql_parse_status ||
+ thd->lex->select_stack_top == 0);
+ thd->lex->current_select= thd->lex->first_select_lex();
/*
Check that if MYSQLparse() failed either thd->is_error() is set, or an
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index ffe632d5409..3133b94fa5b 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -525,15 +525,10 @@ static bool create_full_part_field_array(THD *thd, TABLE *table,
full_part_field_array may be NULL if storage engine supports native
partitioning.
*/
- table->vcol_set= table->read_set= &part_info->full_part_field_set;
+ table->read_set= &part_info->full_part_field_set;
if ((ptr= part_info->full_part_field_array))
for (; *ptr; ptr++)
- {
- if ((*ptr)->vcol_info)
- table->mark_virtual_col(*ptr);
- else
- bitmap_fast_test_and_set(table->read_set, (*ptr)->field_index);
- }
+ table->mark_column_with_deps(*ptr);
table->default_column_bitmaps();
end:
@@ -835,7 +830,8 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
goto end;
table->get_fields_in_item_tree= true;
- func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context);
+ func_expr->walk(&Item::change_context_processor, 0,
+ &lex.first_select_lex()->context);
thd->where= "partition function";
/*
In execution we must avoid the use of thd->change_item_tree since
@@ -2644,7 +2640,7 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info,
default:
DBUG_ASSERT(0);
/* We really shouldn't get here, no use in continuing from here */
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
DBUG_RETURN(NULL);
}
if (part_info->part_type == VERSIONING_PARTITION)
@@ -5991,7 +5987,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
lpt->pack_frm_data,
lpt->pack_frm_len))))
{
- file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR));
+ file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATAL));
}
if (mysql_trans_commit_alter_copy_data(thd))
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 99fe09d5afe..2cc3f247e95 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -51,7 +51,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd)
/* Moved from mysql_execute_command */
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
/* first table of first SELECT_LEX */
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
/*
@@ -743,7 +743,7 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
int error;
ha_partition *partition;
ulong timeout= thd->variables.lock_wait_timeout;
- TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
+ TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first;
Alter_info *alter_info= &thd->lex->alter_info;
uint table_counter, i;
List<String> partition_names_list;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2ffecbab617..b0b0c815fa1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1342,7 +1342,7 @@ static int mysql_test_update(Prepared_statement *stmt,
THD *thd= stmt->thd;
uint table_count= 0;
TABLE_LIST *update_source_table;
- SELECT_LEX *select= &stmt->lex->select_lex;
+ SELECT_LEX *select= stmt->lex->first_select_lex();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
@@ -1398,10 +1398,10 @@ static int mysql_test_update(Prepared_statement *stmt,
table_list->table->grant.want_privilege= want_privilege;
table_list->register_want_access(want_privilege);
#endif
- thd->lex->select_lex.no_wrap_view_item= TRUE;
+ thd->lex->first_select_lex()->no_wrap_view_item= TRUE;
res= setup_fields(thd, Ref_ptr_array(),
select->item_list, MARK_COLUMNS_READ, 0, NULL, 0);
- thd->lex->select_lex.no_wrap_view_item= FALSE;
+ thd->lex->first_select_lex()->no_wrap_view_item= FALSE;
if (res)
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1466,10 +1466,10 @@ static bool mysql_test_delete(Prepared_statement *stmt,
goto error;
}
- DBUG_RETURN(mysql_prepare_delete(thd, table_list,
- lex->select_lex.with_wild,
- lex->select_lex.item_list,
- &lex->select_lex.where,
+ DBUG_RETURN(mysql_prepare_delete(thd, table_list,
+ lex->first_select_lex()->with_wild,
+ lex->first_select_lex()->item_list,
+ &lex->first_select_lex()->where,
&delete_while_scanning));
error:
DBUG_RETURN(TRUE);
@@ -1501,7 +1501,7 @@ static int mysql_test_select(Prepared_statement *stmt,
SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_test_select");
- lex->select_lex.context.resolve_in_select_list= TRUE;
+ lex->first_select_lex()->context.resolve_in_select_list= TRUE;
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (tables)
@@ -1514,7 +1514,7 @@ static int mysql_test_select(Prepared_statement *stmt,
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send(thd)))
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR),
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL),
static_cast<int>(sizeof(select_send)));
goto error;
}
@@ -1535,7 +1535,7 @@ static int mysql_test_select(Prepared_statement *stmt,
if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare())
{
/* Make copy of item list, as change_columns may change it */
- List<Item> fields(lex->select_lex.item_list);
+ List<Item> fields(lex->first_select_lex()->item_list);
/* Change columns if a procedure like analyse() */
if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields))
@@ -1693,7 +1693,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- lex->select_lex.context.resolve_in_select_list= TRUE;
+ lex->first_select_lex()->context.resolve_in_select_list= TRUE;
if (specific_prepare && (*specific_prepare)(thd))
DBUG_RETURN(TRUE);
@@ -1761,7 +1761,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
DBUG_ENTER("mysql_test_create_table");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
bool res= FALSE;
bool link_to_local;
TABLE_LIST *create_table= lex->query_tables;
@@ -2081,11 +2081,11 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
{
THD *thd= stmt->thd;
- thd->lex->current_select= &thd->lex->select_lex;
+ thd->lex->current_select= thd->lex->first_select_lex();
if (add_item_to_list(thd, new (thd->mem_root)
Item_null(thd)))
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 0);
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), 0);
goto error;
}
@@ -2120,13 +2120,14 @@ error:
static int mysql_insert_select_prepare_tester(THD *thd)
{
- SELECT_LEX *first_select= &thd->lex->select_lex;
+ SELECT_LEX *first_select= thd->lex->first_select_lex();
TABLE_LIST *second_table= first_select->table_list.first->next_local;
/* Skip first table, which is the table we are inserting in */
first_select->table_list.first= second_table;
- thd->lex->select_lex.context.table_list=
- thd->lex->select_lex.context.first_name_resolution_table= second_table;
+ thd->lex->first_select_lex()->context.table_list=
+ thd->lex->first_select_lex()->context.first_name_resolution_table=
+ second_table;
return mysql_insert_select_prepare(thd);
}
@@ -2161,7 +2162,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
return 1;
/* store it, because mysql_insert_select_prepare_tester change it */
- first_local_table= lex->select_lex.table_list.first;
+ first_local_table= lex->first_select_lex()->table_list.first;
DBUG_ASSERT(first_local_table != 0);
res=
@@ -2169,7 +2170,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
&mysql_insert_select_prepare_tester,
OPTION_SETUP_TABLES_DONE);
/* revert changes made by mysql_insert_select_prepare_tester */
- lex->select_lex.table_list.first= first_local_table;
+ lex->first_select_lex()->table_list.first= first_local_table;
return res;
}
@@ -2195,7 +2196,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt,
SQL_HANDLER *ha_table;
DBUG_ENTER("mysql_test_handler_read");
- lex->select_lex.context.resolve_in_select_list= TRUE;
+ lex->first_select_lex()->context.resolve_in_select_list= TRUE;
/*
We don't have to test for permissions as this is already done during
@@ -2205,7 +2206,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt,
lex->ident.str,
lex->insert_list,
lex->ha_rkey_mode,
- lex->select_lex.where)))
+ lex->first_select_lex()->where)))
DBUG_RETURN(1);
if (!stmt->is_sql_prepare())
@@ -2244,7 +2245,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
TABLE_LIST *tables;
enum enum_sql_command sql_command= lex->sql_command;
int res= 0;
@@ -2253,10 +2254,11 @@ static bool check_prepared_statement(Prepared_statement *stmt)
sql_command, stmt->param_count));
lex->first_lists_tables_same();
+ lex->fix_first_select_number();
tables= lex->query_tables;
/* set context for commands which do not use setup_tables */
- lex->select_lex.context.resolve_in_table_list_only(select_lex->
+ lex->first_select_lex()->context.resolve_in_table_list_only(select_lex->
get_table_list());
/* Reset warning count for each query that uses tables */
@@ -3021,7 +3023,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
{
tables->reinit_before_use(thd);
}
- lex->current_select= &lex->select_lex;
+ lex->current_select= lex->first_select_lex();
if (lex->result)
@@ -4559,8 +4561,8 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy)
if (is_sql_prepare() || lex->describe)
return FALSE;
- if (lex->select_lex.item_list.elements !=
- copy->lex->select_lex.item_list.elements)
+ if (lex->first_select_lex()->item_list.elements !=
+ copy->lex->first_select_lex()->item_list.elements)
{
/** Column counts mismatch, update the client */
thd->server_status|= SERVER_STATUS_METADATA_CHANGED;
@@ -4717,7 +4719,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
alloc_query(thd, (char*) expanded_query->ptr(),
expanded_query->length()))
{
- my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), expanded_query->length());
+ my_error(ER_OUTOFMEMORY, MYF(ME_FATAL), expanded_query->length());
goto error;
}
/*
@@ -5297,16 +5299,8 @@ bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
bool Protocol_local::store_decimal(const my_decimal *value)
{
- char buf[DECIMAL_MAX_STR_LENGTH];
- String str(buf, sizeof (buf), &my_charset_bin);
- int rc;
-
- rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);
-
- if (rc)
- return TRUE;
-
- return store_column(str.ptr(), str.length());
+ StringBuffer<DECIMAL_MAX_STR_LENGTH> str;
+ return value->to_string(&str) ? store_column(str.ptr(), str.length()) : true;
}
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index e48b6195bb7..fa12b645041 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -183,7 +183,11 @@
#define OPTION_ALLOW_BATCH (1ULL << 36) // THD, intern (slave)
#define OPTION_SKIP_REPLICATION (1ULL << 37) // THD, user
#define OPTION_RPL_SKIP_PARALLEL (1ULL << 38)
-#define OPTION_FOUND_COMMENT (1ULL << 39) // SELECT, intern, parser
+#define OPTION_NO_QUERY_CACHE (1ULL << 39) // SELECT, user
+#define OPTION_PROCEDURE_CLAUSE (1ULL << 40) // Internal usage
+
+
+#define OPTION_LEX_FOUND_COMMENT (1ULL << 0) // intern, parser
/* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT
@@ -228,6 +232,7 @@
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
+#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY (1ULL << 32)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
@@ -254,7 +259,8 @@
OPTIMIZER_SWITCH_EXISTS_TO_IN | \
OPTIMIZER_SWITCH_ORDERBY_EQ_PROP | \
OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED | \
- OPTIMIZER_SWITCH_SPLIT_MATERIALIZED)
+ OPTIMIZER_SWITCH_SPLIT_MATERIALIZED | \
+ OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY)
/*
Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
@@ -356,6 +362,9 @@ enum enum_parsing_place
IN_ORDER_BY,
IN_UPDATE_ON_DUP_KEY,
IN_PART_FUNC,
+ BEFORE_OPT_LIST,
+ AFTER_LIST,
+ FOR_LOOP_BOUND,
PARSING_PLACE_SIZE /* always should be the last */
};
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index 13f03fed5f3..6ca21aebb37 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -110,7 +110,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
};
ST_FIELD_INFO *field_info;
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
int i;
for (i= 0; schema_table->fields_info[i].field_name != NULL; i++)
@@ -402,7 +402,7 @@ bool PROFILING::show_profiles()
QUERY_PROFILE *prof;
List<Item> field_list;
MEM_ROOT *mem_root= thd->mem_root;
- SELECT_LEX *sel= &thd->lex->select_lex;
+ SELECT_LEX *sel= thd->lex->first_select_lex();
SELECT_LEX_UNIT *unit= &thd->lex->unit;
ha_rows idx= 0;
Protocol *protocol= thd->protocol;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 4c0035b9c48..2ee175293de 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3841,8 +3841,7 @@ int reset_master(THD* thd, rpl_gtid *init_state, uint32 init_state_len,
if (!mysql_bin_log.is_open())
{
my_message(ER_FLUSH_MASTER_BINLOG_CLOSED,
- ER_THD(thd, ER_FLUSH_MASTER_BINLOG_CLOSED),
- MYF(ME_BELL+ME_WAITTANG));
+ ER_THD(thd, ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(0));
return 1;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7ff29bb081c..3b927510c80 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -351,7 +351,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option)
{
bool res;
- SELECT_LEX *select_lex = &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
DBUG_ENTER("handle_select");
MYSQL_SELECT_START(thd->query());
@@ -1048,7 +1048,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
while ((select_el= select_it++))
{
- if (select_el->with_sum_func)
+ if (select_el->with_sum_func())
found_sum_func_elem= true;
if (select_el->with_field)
found_field_elem= true;
@@ -1216,14 +1216,14 @@ JOIN::prepare(TABLE_LIST *tables_init,
item->max_length)))
real_order= TRUE;
- if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM)
item->split_sum_func(thd, ref_ptrs, all_fields, 0);
}
if (!real_order)
order= NULL;
}
- if (having && having->with_sum_func)
+ if (having && having->with_sum_func())
having->split_sum_func2(thd, ref_ptrs, all_fields,
&having, SPLIT_SUM_SKIP_REGISTERED);
if (select_lex->inner_sum_func_list)
@@ -1393,6 +1393,7 @@ err:
bool JOIN::build_explain()
{
+ DBUG_ENTER("JOIN::build_explain");
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE;
@@ -1410,8 +1411,7 @@ bool JOIN::build_explain()
thd->mem_root= old_mem_root;
DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created
if (res)
- return 1;
-
+ DBUG_RETURN(1);
uint select_nr= select_lex->select_number;
JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
for (uint i= 0; i < aggr_tables; i++, curr_tab++)
@@ -1429,7 +1429,7 @@ bool JOIN::build_explain()
get_using_temporary_read_tracker();
}
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -1594,7 +1594,7 @@ JOIN::optimize_inner()
{
/*
Item_cond_and can't be fixed after creation, so we do not check
- conds->fixed
+ conds->is_fixed()
*/
conds->fix_fields(thd, &conds);
conds->change_ref_to_fields(thd, tables_list);
@@ -1638,7 +1638,7 @@ JOIN::optimize_inner()
if (arena)
thd->restore_active_arena(arena, &backup);
}
-
+
if (optimize_constant_subqueries())
DBUG_RETURN(1);
@@ -1649,9 +1649,28 @@ JOIN::optimize_inner()
(void) having->walk(&Item::cleanup_is_expensive_cache_processor,
0, (void *) 0);
- if (setup_jtbm_semi_joins(this, join_list, &conds))
+ List<Item> eq_list;
+
+ if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list))
DBUG_RETURN(1);
+ if (eq_list.elements != 0)
+ {
+ Item *new_cond;
+
+ if (eq_list.elements == 1)
+ new_cond= eq_list.pop();
+ else
+ new_cond= new (thd->mem_root) Item_cond_and(thd, eq_list);
+
+ if (new_cond &&
+ ((new_cond->fix_fields(thd, &new_cond) ||
+ !(conds= and_items(thd, conds, new_cond)) ||
+ conds->fix_fields(thd, &conds))))
+ DBUG_RETURN(TRUE);
+ }
+ eq_list.empty();
+
if (select_lex->cond_pushed_into_where)
{
conds= and_conds(thd, conds, select_lex->cond_pushed_into_where);
@@ -1682,6 +1701,31 @@ JOIN::optimize_inner()
DBUG_RETURN(1);
}
+ if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY))
+ {
+ TABLE_LIST *tbl;
+ List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
+ while ((tbl= li++))
+ if (tbl->jtbm_subselect)
+ {
+ if (tbl->jtbm_subselect->pushdown_cond_for_in_subquery(thd, conds))
+ DBUG_RETURN(1);
+ }
+ }
+
+ if (setup_jtbm_semi_joins(this, join_list, eq_list))
+ DBUG_RETURN(1);
+
+ if (eq_list.elements != 0)
+ {
+ conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal,
+ eq_list, &cond_value);
+
+ if (!conds &&
+ cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE)
+ DBUG_RETURN(TRUE);
+ }
+
if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED))
{
TABLE_LIST *tbl;
@@ -1998,7 +2042,7 @@ int JOIN::optimize_stage2()
if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
- conds= new (thd->mem_root) Item_int(thd, (longlong) 1,1); // Always true
+ conds= new (thd->mem_root) Item_bool(thd, true); // Always true
}
if (impossible_where)
@@ -2137,7 +2181,7 @@ int JOIN::optimize_stage2()
if (conds && const_table_map != found_const_table_map &&
(select_options & SELECT_DESCRIBE))
{
- conds=new (thd->mem_root) Item_int(thd, (longlong) 0, 1); // Always false
+ conds=new (thd->mem_root) Item_bool(thd, false); // Always false
}
/* Cache constant expressions in WHERE, HAVING, ON clauses. */
@@ -2420,13 +2464,13 @@ int JOIN::optimize_stage2()
elements may be lost during further having
condition transformation in JOIN::exec.
*/
- if (having && const_table_map && !having->with_sum_func)
+ if (having && const_table_map && !having->with_sum_func())
{
having->update_used_tables();
having= having->remove_eq_conds(thd, &select_lex->having_value, true);
if (select_lex->having_value == Item::COND_FALSE)
{
- having= new (thd->mem_root) Item_int(thd, (longlong) 0,1);
+ having= new (thd->mem_root) Item_bool(thd, false);
zero_result_cause= "Impossible HAVING noticed after reading const tables";
error= 0;
select_lex->mark_const_derived(zero_result_cause);
@@ -3760,6 +3804,15 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
bool need_tmp_table, bool need_order,
bool distinct)
{
+ DBUG_ENTER("JOIN::save_explain_data");
+ DBUG_PRINT("enter", ("Save explain Select_lex: %u (%p) parent lex: %p stmt_lex: %p present select: %u (%p)",
+ select_lex->select_number, select_lex,
+ select_lex->parent_lex, thd->lex->stmt_lex,
+ (output->get_select(select_lex->select_number) ?
+ select_lex->select_number : 0),
+ (output->get_select(select_lex->select_number) ?
+ output->get_select(select_lex->select_number)
+ ->select_lex : NULL)));
/*
If there is SELECT in this statement with the same number it must be the
same SELECT
@@ -3786,8 +3839,9 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
/* It's a degenerate join */
message= zero_result_cause ? zero_result_cause : "No tables used";
}
- return save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order,
- distinct, message);
+ bool rc= save_explain_data_intern(thd->lex->explain, need_tmp_table,
+ need_order, distinct, message);
+ DBUG_RETURN(rc);
}
/*
@@ -3809,11 +3863,11 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
{
if (!(join_tab[i].filesort->tracker=
new Filesort_tracker(thd->lex->analyze_stmt)))
- return 1;
+ DBUG_RETURN(1);
}
}
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -4170,10 +4224,10 @@ mysql_select(THD *thd,
is it single SELECT in derived table, called in derived table
creation
*/
- if (select_lex->linkage != DERIVED_TABLE_TYPE ||
+ if (select_lex->get_linkage() != DERIVED_TABLE_TYPE ||
(select_options & SELECT_DESCRIBE))
{
- if (select_lex->linkage != GLOBAL_OPTIONS_TYPE)
+ if (select_lex->get_linkage() != GLOBAL_OPTIONS_TYPE)
{
/*
Original join tabs might be overwritten at first
@@ -4787,7 +4841,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
if (join->cond_value == Item::COND_FALSE)
{
join->impossible_where= true;
- conds= new (join->thd->mem_root) Item_int(join->thd, (longlong) 0, 1);
+ conds= new (join->thd->mem_root) Item_bool(join->thd, false);
}
join->cond_equal= NULL;
@@ -10534,7 +10588,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
below to check if we should use 'quick' instead.
*/
DBUG_PRINT("info", ("Item_int"));
- tmp= new (thd->mem_root) Item_int(thd, (longlong) 1, 1); // Always true
+ tmp= new (thd->mem_root) Item_bool(thd, true); // Always true
}
}
@@ -10662,7 +10716,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
Yet attributes of the just built condition are not needed.
Thus we call sel->cond->quick_fix_field for safety.
*/
- if (sel->cond && !sel->cond->fixed)
+ if (sel->cond && !sel->cond->is_fixed())
sel->cond->quick_fix_field();
if (sel->test_quick_select(thd, tab->keys,
@@ -12663,7 +12717,8 @@ void JOIN::join_free()
!(select_options & SELECT_NO_UNLOCK) &&
!select_lex->subquery_in_having &&
(select_lex == (thd->lex->unit.fake_select_lex ?
- thd->lex->unit.fake_select_lex : &thd->lex->select_lex)))
+ thd->lex->unit.fake_select_lex :
+ thd->lex->first_select_lex())))
{
/*
TODO: unlock tables even if the join isn't top level select in the
@@ -12955,7 +13010,7 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order)
order->used= 0;
// Not item_sum(), RAND() and no reference to table outside of sub select
if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT))
- && !order->item[0]->with_sum_func &&
+ && !order->item[0]->with_sum_func() &&
join->join_tab)
{
for (JOIN_TAB **tab=join->map2table;
@@ -13046,7 +13101,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
for (order=first_order; order ; order=order->next)
{
table_map order_tables=order->item[0]->used_tables();
- if (order->item[0]->with_sum_func ||
+ if (order->item[0]->with_sum_func() ||
/*
If the outer table of an outer join is const (either by itself or
after applying WHERE condition), grouping on a field from such a
@@ -13222,7 +13277,7 @@ ORDER *simple_remove_const(ORDER *order, COND *where)
ORDER *first= NULL, *prev= NULL;
for (; order; order= order->next)
{
- DBUG_ASSERT(!order->item[0]->with_sum_func); // should never happen
+ DBUG_ASSERT(!order->item[0]->with_sum_func()); // should never happen
if (!const_expression_in_where(where, order->item[0]))
{
if (!first)
@@ -13471,9 +13526,9 @@ finish:
FALSE otherwise
*/
-static bool check_simple_equality(THD *thd, const Item::Context &ctx,
- Item *left_item, Item *right_item,
- COND_EQUAL *cond_equal)
+bool check_simple_equality(THD *thd, const Item::Context &ctx,
+ Item *left_item, Item *right_item,
+ COND_EQUAL *cond_equal)
{
Item *orig_left_item= left_item;
Item *orig_right_item= right_item;
@@ -13926,7 +13981,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
if (!cond_args->elements &&
!cond_equal.current_level.elements &&
!eq_list.elements)
- return new (thd->mem_root) Item_int(thd, (longlong) 1, 1);
+ return new (thd->mem_root) Item_bool(thd, true);
List_iterator_fast<Item_equal> it(cond_equal.current_level);
while ((item_equal= it++))
@@ -14033,7 +14088,7 @@ COND *Item_func_eq::build_equal_items(THD *thd,
Item_equal *item_equal;
int n= cond_equal.current_level.elements + eq_list.elements;
if (n == 0)
- return new (thd->mem_root) Item_int(thd, (longlong) 1, 1);
+ return new (thd->mem_root) Item_bool(thd, true);
else if (n == 1)
{
if ((item_equal= cond_equal.current_level.pop()))
@@ -14424,7 +14479,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
List<Item> eq_list;
Item_func_eq *eq_item= 0;
if (((Item *) item_equal)->const_item() && !item_equal->val_int())
- return new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ return new (thd->mem_root) Item_bool(thd, false);
Item *item_const= item_equal->get_const();
Item_equal_fields_iterator it(*item_equal);
Item *head;
@@ -14432,7 +14487,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
Item *current_sjm_head= NULL;
DBUG_ASSERT(!cond ||
- cond->type() == Item::INT_ITEM ||
+ cond->is_bool_literal() ||
(cond->type() == Item::FUNC_ITEM &&
((Item_func *) cond)->functype() == Item_func::EQ_FUNC) ||
(cond->type() == Item::COND_ITEM &&
@@ -14553,13 +14608,13 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
cond AND eq_1 AND eq_2 AND eq_3 AND ...
- 'cond' is a parameter for this function, which may be NULL, an Item_int(1),
+ 'cond' is a parameter for this function, which may be NULL, an Item_bool(1),
or an Item_func_eq or an Item_cond_and.
We want to return a well-formed condition: no nested Item_cond_and objects,
or Item_cond_and with a single child:
- if 'cond' is an Item_cond_and, we add eq_i as its tail
- - if 'cond' is Item_int(1), we return eq_i
+ - if 'cond' is Item_bool(1), we return eq_i
- otherwise, we create our own Item_cond_and and put 'cond' at the front of
it.
- if we have only one condition to return, we don't create an Item_cond_and
@@ -14571,10 +14626,10 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels,
switch (eq_list.elements)
{
case 0:
- res= cond ? cond : new (thd->mem_root) Item_int(thd, (longlong) 1, 1);
+ res= cond ? cond : new (thd->mem_root) Item_bool(thd, true);
break;
case 1:
- if (!cond || cond->type() == Item::INT_ITEM)
+ if (!cond || cond->is_bool_literal())
res= eq_item;
break;
default:
@@ -14716,7 +14771,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab,
eq_cond= 0;
break;
}
- else if (eq_cond->type() == Item::INT_ITEM && !eq_cond->val_bool())
+ else if (eq_cond->is_bool_literal() && !eq_cond->val_bool())
{
/*
This occurs when eliminate_item_equal() founds that cond is
@@ -14741,7 +14796,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab,
else
{
/* Do not add an equality condition if it's always true */
- if (eq_cond->type() != Item::INT_ITEM &&
+ if (!eq_cond->is_bool_literal() &&
cond_list->push_front(eq_cond, thd->mem_root))
eq_cond= 0;
}
@@ -15255,7 +15310,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
conds= and_conds(join->thd, conds, table->on_expr);
conds->top_level_item();
/* conds is always a new item as both cond and on_expr existed */
- DBUG_ASSERT(!conds->fixed);
+ DBUG_ASSERT(!conds->is_fixed());
conds->fix_fields(join->thd, &conds);
}
else
@@ -16323,9 +16378,8 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
{
Field *field= ((Item_field*) real_item)->field;
- if (((field->type() == MYSQL_TYPE_DATE) ||
- (field->type() == MYSQL_TYPE_DATETIME)) &&
- (field->flags & NOT_NULL_FLAG))
+ if ((field->flags & NOT_NULL_FLAG) &&
+ field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero())
{
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
/*
@@ -16341,7 +16395,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
*/
- Item *item0= new(thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ Item *item0= new(thd->mem_root) Item_bool(thd, false);
Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0);
if (!eq_cond)
return this;
@@ -16411,7 +16465,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
cond= new_cond;
/*
Item_func_eq can't be fixed after creation so we do not check
- cond->fixed, also it do not need tables so we use 0 as second
+ cond->is_fixed(), also it do not need tables so we use 0 as second
argument.
*/
cond->fix_fields(thd, &cond);
@@ -16571,60 +16625,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
Create internal temporary table
****************************************************************************/
-/**
- Create field for temporary table from given field.
-
- @param thd Thread handler
- @param org_field field from which new field will be created
- @param name New field name
- @param table Temporary table
- @param item !=NULL if item->result_field should point to new field.
- This is relevant for how fill_record() is going to work:
- If item != NULL then fill_record() will update
- the record in the original table.
- If item == NULL then fill_record() will update
- the temporary table
-
- @retval
- NULL on error
- @retval
- new_created field
-*/
-
-Field *create_tmp_field_from_field(THD *thd, Field *org_field,
- LEX_CSTRING *name, TABLE *table,
- Item_field *item)
-{
- Field *new_field;
-
- new_field= org_field->make_new_field(thd->mem_root, table,
- table == org_field->table);
- if (new_field)
- {
- new_field->init(table);
- new_field->orig_table= org_field->orig_table;
- if (item)
- item->result_field= new_field;
- else
- new_field->field_name= *name;
- new_field->flags|= org_field->flags & NO_DEFAULT_VALUE_FLAG;
- if (org_field->maybe_null() || (item && item->maybe_null))
- new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
- if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
- org_field->type() == MYSQL_TYPE_VARCHAR)
- table->s->db_create_options|= HA_OPTION_PACK_RECORD;
- else if (org_field->type() == FIELD_TYPE_DOUBLE)
- ((Field_double *) new_field)->not_fixed= TRUE;
- new_field->vcol_info= 0;
- new_field->cond_selectivity= 1.0;
- new_field->next_equal_field= NULL;
- new_field->option_list= NULL;
- new_field->option_struct= NULL;
- }
- return new_field;
-}
-
-
Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
{
const Type_handler *h= &type_handler_long;
@@ -16634,6 +16634,22 @@ Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
*this, table);
}
+Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param,
+ bool is_explicit_null)
+{
+ DBUG_ASSERT(!param->make_copy_field());
+ DBUG_ASSERT(!is_result_field());
+ Field *result;
+ if ((result= tmp_table_field_from_field_type(table)))
+ {
+ if (result && is_explicit_null)
+ result->is_created_from_null_item= true;
+ }
+ return result;
+}
+
Field *Item_sum::create_tmp_field(bool group, TABLE *table)
{
@@ -16665,57 +16681,6 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
}
-static void create_tmp_field_from_item_finalize(THD *thd,
- Field *new_field,
- Item *item,
- Item ***copy_func,
- bool modify_item)
-{
- if (copy_func &&
- (item->is_result_field() ||
- (item->real_item()->is_result_field())))
- *((*copy_func)++) = item; // Save for copy_funcs
- if (modify_item)
- item->set_result_field(new_field);
- if (item->type() == Item::NULL_ITEM)
- new_field->is_created_from_null_item= TRUE;
-}
-
-
-/**
- Create field for temporary table using type of given item.
-
- @param thd Thread handler
- @param item Item to create a field for
- @param table Temporary table
- @param copy_func If set and item is a function, store copy of
- item in this array
- @param modify_item 1 if item->result_field should point to new
- item. This is relevent for how fill_record()
- is going to work:
- If modify_item is 1 then fill_record() will
- update the record in the original table.
- If modify_item is 0 then fill_record() will
- update the temporary table
-
- @retval
- 0 on error
- @retval
- new_created field
-*/
-
-static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
- Item ***copy_func, bool modify_item)
-{
- Field *UNINIT_VAR(new_field);
- DBUG_ASSERT(thd == table->in_use);
- if ((new_field= item->create_tmp_field(false, table)))
- create_tmp_field_from_item_finalize(thd, new_field, item,
- copy_func, modify_item);
- return new_field;
-}
-
-
/**
Create field for information schema table.
@@ -16753,19 +16718,182 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table)
/**
+ Create a temporary field for Item_field (or its descendant),
+ either direct or referenced by an Item_ref.
+*/
+Field *
+Item_field::create_tmp_field_from_item_field(TABLE *new_table,
+ Item_ref *orig_item,
+ const Tmp_field_param *param)
+{
+ DBUG_ASSERT(!is_result_field());
+ Field *result;
+ /*
+ If item have to be able to store NULLs but underlaid field can't do it,
+ create_tmp_field_from_field() can't be used for tmp field creation.
+ */
+ if (((maybe_null && in_rollup) ||
+ (new_table->in_use->create_tmp_table_for_derived && /* for mat. view/dt */
+ orig_item && orig_item->maybe_null)) &&
+ !field->maybe_null())
+ {
+ /*
+ The item the ref points to may have maybe_null flag set while
+ the ref doesn't have it. This may happen for outer fields
+ when the outer query decided at some point after name resolution phase
+ that this field might be null. Take this into account here.
+ */
+ Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null);
+ const Type_handler *handler= type_handler()->
+ type_handler_for_tmp_table(this);
+ result= handler->make_and_init_table_field(orig_item ? &orig_item->name : &name,
+ rec, *this, new_table);
+ }
+ else if (param->table_cant_handle_bit_fields() &&
+ field->type() == MYSQL_TYPE_BIT)
+ {
+ const Type_handler *handler= type_handler_long_or_longlong();
+ result= handler->make_and_init_table_field(&name,
+ Record_addr(maybe_null),
+ *this, new_table);
+ }
+ else
+ {
+ LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name;
+ bool tmp_maybe_null= param->modify_item() ? maybe_null :
+ field->maybe_null();
+ result= field->create_tmp_field(new_table->in_use->mem_root, new_table,
+ tmp_maybe_null);
+ if (result)
+ result->field_name= *tmp;
+ }
+ if (result && param->modify_item())
+ result_field= result;
+ return result;
+}
+
+
+Field *Item_field::create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ DBUG_ASSERT(!is_result_field());
+ Field *result;
+ src->set_field(field);
+ if (!(result= create_tmp_field_from_item_field(table, NULL, param)))
+ return NULL;
+ /*
+ Fields that are used as arguments to the DEFAULT() function already have
+ their data pointers set to the default value during name resolution. See
+ Item_default_value::fix_fields.
+ */
+ if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result))
+ src->set_default_field(field);
+ return result;
+}
+
+
+Field *Item_ref::create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ Item *item= real_item();
+ DBUG_ASSERT(is_result_field());
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ Field *result;
+ Item_field *field= (Item_field*) item;
+ Tmp_field_param prm2(*param);
+ prm2.set_modify_item(false);
+ src->set_field(field->field);
+ if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2)))
+ return NULL;
+ if (param->modify_item())
+ result_field= result;
+ return result;
+ }
+ return Item_result_field::create_tmp_field_ex(table, src, param);
+}
+
+
+void Item_result_field::get_tmp_field_src(Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ if (param->make_copy_field())
+ {
+ DBUG_ASSERT(result_field);
+ src->set_field(result_field);
+ }
+ else
+ {
+ src->set_item_result_field(this); // Save for copy_funcs
+ }
+}
+
+
+Field *Item_result_field::create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ /*
+ Possible Item types:
+ - Item_cache_wrapper (only for CREATE..SELECT ?)
+ - Item_func
+ - Item_subselect
+ */
+ DBUG_ASSERT(is_result_field());
+ DBUG_ASSERT(type() != NULL_ITEM);
+ get_tmp_field_src(src, param);
+ Field *result;
+ if ((result= tmp_table_field_from_field_type(table)) && param->modify_item())
+ result_field= result;
+ return result;
+}
+
+
+Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ DBUG_ASSERT(is_result_field());
+ DBUG_ASSERT(type() != NULL_ITEM);
+ get_tmp_field_src(src, param);
+ Field *result;
+ if ((result= create_table_field_from_handler(table)) && param->modify_item())
+ result_field= result;
+ return result;
+}
+
+
+Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
+ Tmp_field_src *src,
+ const Tmp_field_param *param)
+{
+ Field *result;
+ get_tmp_field_src(src, param);
+ if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root,
+ table)))
+ {
+ result->field_name= name;
+ if (param->modify_item())
+ result_field= result;
+ }
+ return result;
+}
+
+/**
Create field for temporary table.
- @param thd Thread handler
- @param table Temporary table
- @param item Item to create a field for
- @param type Type of item (normally item->type)
- @param copy_func If set and item is a function, store copy of item
+ @param table Temporary table
+ @param item Item to create a field for
+ @param type Type of item (normally item->type)
+ @param copy_func If set and item is a function, store copy of item
in this array
@param from_field if field will be created using other field as example,
pointer example field will be written here
- @param default_field If field has a default value field, store it here
- @param group 1 if we are going to do a relative group by on result
- @param modify_item 1 if item->result_field should point to new item.
+ @param default_field If field has a default value field, store it here
+ @param group 1 if we are going to do a relative group by on result
+ @param modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
work:
If modify_item is 1 then fill_record() will update
@@ -16774,175 +16902,28 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table)
the temporary table
@retval
- 0 on error
+ 0 on error
@retval
new_created field
+ Create a temporary field for Item_field (or its descendant),
+ either direct or referenced by an Item_ref.
*/
-
-Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
+Field *create_tmp_field(TABLE *table, Item *item,
Item ***copy_func, Field **from_field,
Field **default_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field)
{
- Field *result;
- Item::Type orig_type= type;
- Item *orig_item= 0;
-
- DBUG_ASSERT(thd == table->in_use);
-
- if (type != Item::FIELD_ITEM &&
- item->real_item()->type() == Item::FIELD_ITEM)
- {
- orig_item= item;
- item= item->real_item();
- type= Item::FIELD_ITEM;
- }
-
- switch (type) {
- case Item::TYPE_HOLDER:
- case Item::SUM_FUNC_ITEM:
- {
- result= item->create_tmp_field(group, table);
- if (!result)
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
- return result;
- }
- case Item::FIELD_ITEM:
- case Item::DEFAULT_VALUE_ITEM:
- case Item::INSERT_VALUE_ITEM:
- case Item::TRIGGER_FIELD_ITEM:
- {
- Item_field *field= (Item_field*) item;
- bool orig_modify= modify_item;
- if (orig_type == Item::REF_ITEM)
- modify_item= 0;
- /*
- If item have to be able to store NULLs but underlaid field can't do it,
- create_tmp_field_from_field() can't be used for tmp field creation.
- */
- if (((field->maybe_null && field->in_rollup) ||
- (thd->create_tmp_table_for_derived && /* for mat. view/dt */
- orig_item && orig_item->maybe_null)) &&
- !field->field->maybe_null())
- {
- bool save_maybe_null= FALSE;
- /*
- The item the ref points to may have maybe_null flag set while
- the ref doesn't have it. This may happen for outer fields
- when the outer query decided at some point after name resolution phase
- that this field might be null. Take this into account here.
- */
- if (orig_item)
- {
- save_maybe_null= item->maybe_null;
- item->maybe_null= orig_item->maybe_null;
- }
- result= create_tmp_field_from_item(thd, item, table, NULL,
- modify_item);
- *from_field= field->field;
- if (result && modify_item)
- field->result_field= result;
- if (orig_item)
- {
- item->maybe_null= save_maybe_null;
- result->field_name= orig_item->name;
- }
- }
- else if (table_cant_handle_bit_fields && field->field->type() ==
- MYSQL_TYPE_BIT)
- {
- const Type_handler *handler= item->type_handler_long_or_longlong();
- *from_field= field->field;
- if ((result=
- handler->make_and_init_table_field(&item->name,
- Record_addr(item->maybe_null),
- *item, table)))
- create_tmp_field_from_item_finalize(thd, result, item,
- copy_func, modify_item);
- if (result && modify_item)
- field->result_field= result;
- }
- else
- {
- LEX_CSTRING *tmp= orig_item ? &orig_item->name : &item->name;
- result= create_tmp_field_from_field(thd, (*from_field= field->field),
- tmp, table,
- modify_item ? field :
- NULL);
- }
-
- if (orig_type == Item::REF_ITEM && orig_modify)
- ((Item_ref*)orig_item)->set_result_field(result);
- /*
- Fields that are used as arguments to the DEFAULT() function already have
- their data pointers set to the default value during name resolution. See
- Item_default_value::fix_fields.
- */
- if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result))
- *default_field= field->field;
- return result;
- }
- /* Fall through */
- case Item::FUNC_ITEM:
- if (((Item_func *) item)->functype() == Item_func::FUNC_SP)
- {
- Item_func_sp *item_func_sp= (Item_func_sp *) item;
- Field *sp_result_field= item_func_sp->get_sp_result_field();
-
- if (make_copy_field)
- {
- DBUG_ASSERT(item_func_sp->result_field);
- *from_field= item_func_sp->result_field;
- }
- else
- {
- *((*copy_func)++)= item;
- }
- Field *result_field=
- create_tmp_field_from_field(thd,
- sp_result_field,
- &item_func_sp->name,
- table,
- NULL);
-
- if (modify_item)
- item->set_result_field(result_field);
-
- return result_field;
- }
-
- /* Fall through */
- case Item::COND_ITEM:
- case Item::FIELD_AVG_ITEM:
- case Item::FIELD_STD_ITEM:
- case Item::SUBSELECT_ITEM:
- /* The following can only happen with 'CREATE TABLE ... SELECT' */
- case Item::PROC_ITEM:
- case Item::INT_ITEM:
- case Item::REAL_ITEM:
- case Item::DECIMAL_ITEM:
- case Item::STRING_ITEM:
- case Item::DATE_ITEM:
- case Item::REF_ITEM:
- case Item::NULL_ITEM:
- case Item::VARBIN_ITEM:
- case Item::CACHE_ITEM:
- case Item::WINDOW_FUNC_ITEM: // psergey-winfunc:
- case Item::EXPR_CACHE_ITEM:
- case Item::PARAM_ITEM:
- if (make_copy_field)
- {
- DBUG_ASSERT(((Item_result_field*)item)->result_field);
- *from_field= ((Item_result_field*)item)->result_field;
- }
- return create_tmp_field_from_item(thd, item, table,
- (make_copy_field ? 0 : copy_func),
- modify_item);
- default: // Dosen't have to be stored
- return 0;
- }
+ Tmp_field_src src;
+ Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields,
+ make_copy_field);
+ Field *result= item->create_tmp_field_ex(table, &src, &prm);
+ *from_field= src.field();
+ *default_field= src.default_field();
+ if (src.item_result_field())
+ *((*copy_func)++)= src.item_result_field();
+ return result;
}
/*
@@ -16958,7 +16939,7 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count)
{
uint bitmap_size= bitmap_buffer_size(field_count);
- DBUG_ASSERT(table->s->virtual_fields == 0 && table->def_vcol_set == 0);
+ DBUG_ASSERT(table->s->virtual_fields == 0);
my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count,
FALSE);
@@ -17223,7 +17204,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
if (not_all_columns)
{
- if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
+ if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM)
{
if (item->used_tables() & OUTER_REF_TABLE_BIT)
item->update_used_tables();
@@ -17253,7 +17234,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
{
Item *tmp_item;
Field *new_field=
- create_tmp_field(thd, table, arg, arg->type(), &copy_func,
+ create_tmp_field(table, arg, &copy_func,
tmp_from_field, &default_field[fieldnr],
group != 0,not_all_columns,
distinct, false);
@@ -17303,7 +17284,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
else
{
/*
- The last parameter to create_tmp_field() is a bit tricky:
+ The last parameter to create_tmp_field_ex() is a bit tricky:
We need to set it to 0 in union, to get fill_record() to modify the
temporary table.
@@ -17317,7 +17298,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
Field *new_field= (param->schema_table) ?
item->create_field_for_schema(thd, table) :
- create_tmp_field(thd, table, item, type, &copy_func,
+ create_tmp_field(table, item, &copy_func,
tmp_from_field, &default_field[fieldnr],
group != 0,
!force_copy_fields &&
@@ -17331,8 +17312,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
item->marker == 4 || param->bit_fields_as_long,
force_copy_fields);
-
- if (unlikely(!new_field))
+ if (!new_field)
{
if (unlikely(thd->is_fatal_error))
goto err; // Got OOM
@@ -17913,12 +17893,10 @@ bool Virtual_tmp_table::add(List<Spvar_definition> &field_list)
while ((cdef= it++))
{
Field *tmp;
- if (!(tmp= cdef->make_field(s, in_use->mem_root, 0,
- (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0),
- f_maybe_null(cdef->pack_flag) ? 1 : 0,
- &cdef->field_name)))
+ Record_addr addr(f_maybe_null(cdef->pack_flag));
+ if (!(tmp= cdef->make_field(s, in_use->mem_root, &addr, &cdef->field_name)))
DBUG_RETURN(true);
- add(tmp);
+ add(tmp);
}
DBUG_RETURN(false);
}
@@ -18038,7 +18016,7 @@ bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd,
bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value)
{
- DBUG_ASSERT(value->fixed);
+ DBUG_ASSERT(value->is_fixed());
DBUG_ASSERT(value->cols() == s->fields);
for (uint i= 0; i < value->cols(); i++)
{
@@ -18461,7 +18439,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
We don't want this error to be converted to a warning, e.g. in case of
INSERT IGNORE ... SELECT.
*/
- table->file->print_error(error, MYF(ME_FATALERROR));
+ table->file->print_error(error, MYF(ME_FATAL));
DBUG_RETURN(1);
}
new_table= *table;
@@ -18484,7 +18462,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
new_table.no_rows= table->no_rows;
if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo,
recinfo,
- thd->lex->select_lex.options |
+ thd->lex->first_select_lex()->options |
thd->variables.option_bits))
goto err2;
if (open_tmp_table(&new_table))
@@ -22616,7 +22594,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
if (unlikely(copy_blobs(first_field)))
{
my_message(ER_OUTOFMEMORY, ER_THD(thd,ER_OUTOFMEMORY),
- MYF(ME_FATALERROR));
+ MYF(ME_FATAL));
error=0;
goto err;
}
@@ -22891,12 +22869,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
uint counter;
enum_resolution_type resolution;
- /*
- Local SP variables may be int but are expressions, not positions.
- (And they can't be used before fix_fields is called for them).
- */
- if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item() &&
- !from_window_spec)
+ if (order_item->is_order_clause_position() && !from_window_spec)
{ /* Order by position */
uint count;
if (order->counter_used)
@@ -23010,7 +22983,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
inspite of that fix_fields() calls find_item_in_list() one more
time.
- We check order_item->fixed because Item_func_group_concat can put
+ We check order_item->is_fixed() because Item_func_group_concat can put
arguments for which fix_fields already was called.
*/
if (order_item->fix_fields_if_needed_for_order_by(thd, order->item) ||
@@ -23120,7 +23093,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
all_fields, true, true, from_window_spec))
return 1;
(*ord->item)->marker= UNDEF_POS; /* Mark found */
- if ((*ord->item)->with_sum_func && context_analysis_place == IN_GROUP_BY)
+ if ((*ord->item)->with_sum_func() && context_analysis_place == IN_GROUP_BY)
{
my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name());
return 1;
@@ -23278,7 +23251,7 @@ create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array,
li.rewind();
while ((item=li++))
{
- if (!item->const_item() && !item->with_sum_func && !item->marker)
+ if (!item->const_item() && !item->with_sum_func() && !item->marker)
{
/*
Don't put duplicate columns from the SELECT list into the
@@ -23375,9 +23348,11 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param,
}
else
{
+ With_sum_func_cache *cache= field->get_with_sum_func_cache();
param->func_count++;
- if (reset_with_sum_func)
- field->with_sum_func=0;
+ // "field" can point to Item_std_field, so "cache" can be NULL here.
+ if (reset_with_sum_func && cache)
+ cache->reset_with_sum_func();
}
}
}
@@ -23517,7 +23492,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group)
{
/*
Group strings are taken as varstrings and require an length field.
- A field is not yet created by create_tmp_field()
+ A field is not yet created by create_tmp_field_ex()
and the sizes should match up.
*/
key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;
@@ -23527,7 +23502,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group)
default:
/* This case should never be choosen */
DBUG_ASSERT(0);
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
}
}
parts++;
@@ -23781,7 +23756,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
real_pos->real_type() == Item::SUBSELECT_ITEM ||
real_pos->type() == Item::CACHE_ITEM ||
real_pos->type() == Item::COND_ITEM) &&
- !real_pos->with_sum_func)
+ !real_pos->with_sum_func())
{ // Save for send fields
pos= real_pos;
/* TODO:
@@ -23988,7 +23963,7 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
for (uint i= 0; (item= it++); i++)
{
Field *field;
- if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
+ if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM)
item_field= item;
else if (item->type() == Item::FIELD_ITEM)
{
@@ -24296,7 +24271,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
}
if (unlikely(thd->is_fatal_error))
DBUG_RETURN(TRUE);
- if (!cond->fixed)
+ if (!cond->is_fixed())
{
Item *tmp_item= (Item*) cond;
cond->fix_fields(thd, &tmp_item);
@@ -24515,7 +24490,7 @@ bool JOIN::rollup_init()
Marking the expression item as 'with_sum_func' will ensure this.
*/
if (changed)
- item->with_sum_func= 1;
+ item->get_with_sum_func_cache()->set_with_sum_func();
}
}
return 0;
@@ -25003,7 +24978,8 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
*/
if (real_table->merged_for_insert)
{
- TABLE_LIST *view_child= real_table->view->select_lex.table_list.first;
+ TABLE_LIST *view_child=
+ real_table->view->first_select_lex()->table_list.first;
for (;view_child; view_child= view_child->next_local)
{
if (view_child->table == table)
@@ -25456,8 +25432,9 @@ int JOIN::save_explain_data_intern(Explain_query *output,
{
JOIN *join= this; /* Legacy: this code used to be a non-member function */
DBUG_ENTER("JOIN::save_explain_data_intern");
- DBUG_PRINT("info", ("Select %p, type %s, message %s",
- join->select_lex, join->select_lex->type,
+ DBUG_PRINT("info", ("Select %p (%u), type %s, message %s",
+ join->select_lex, join->select_lex->select_number,
+ join->select_lex->type,
message ? message : "NULL"));
DBUG_ASSERT(have_query_plan == QEP_AVAILABLE);
/* fake_select_lex is created/printed by Explain_union */
@@ -25483,7 +25460,7 @@ int JOIN::save_explain_data_intern(Explain_query *output,
explain->select_id= join->select_lex->select_number;
explain->select_type= join->select_lex->type;
- explain->linkage= select_lex->linkage;
+ explain->linkage= select_lex->get_linkage();
explain->using_temporary= need_tmp;
explain->using_filesort= need_order_arg;
/* Setting explain->message means that all other members are invalid */
@@ -25506,7 +25483,7 @@ int JOIN::save_explain_data_intern(Explain_query *output,
explain->select_id= select_lex->select_number;
explain->select_type= select_lex->type;
- explain->linkage= select_lex->linkage;
+ explain->linkage= select_lex->get_linkage();
explain->using_temporary= need_tmp;
explain->using_filesort= need_order_arg;
explain->message= "Storage engine handles GROUP BY";
@@ -25529,7 +25506,7 @@ int JOIN::save_explain_data_intern(Explain_query *output,
join->select_lex->set_explain_type(true);
xpl_sel->select_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type;
- xpl_sel->linkage= select_lex->linkage;
+ xpl_sel->linkage= select_lex->get_linkage();
if (select_lex->master_unit()->derived)
xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED;
@@ -25673,7 +25650,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
for such queries, we'll get here before having called
subquery_expr->fix_fields(), which will cause failure to
*/
- if (unit->item && !unit->item->fixed)
+ if (unit->item && !unit->item->is_fixed())
{
Item *ref= unit->item;
if (unit->item->fix_fields(thd, &ref))
@@ -26112,6 +26089,18 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
{
str->append("/* select#");
str->append_ulonglong(select_number);
+ if (thd->lex->describe & DESCRIBE_EXTENDED2)
+ {
+ str->append("/");
+ str->append_ulonglong(nest_level);
+
+ if (master_unit()->fake_select_lex &&
+ master_unit()->first_select() == this)
+ {
+ str->append(" Filter Select: ");
+ master_unit()->fake_select_lex->print(thd, str, query_type);
+ }
+ }
str->append(" */ ");
}
@@ -26143,18 +26132,21 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("sql_buffer_result "));
if (options & OPTION_FOUND_ROWS)
str->append(STRING_WITH_LEN("sql_calc_found_rows "));
- switch (sql_cache)
+ if (this == parent_lex->first_select_lex())
{
- case SQL_NO_CACHE:
- str->append(STRING_WITH_LEN("sql_no_cache "));
- break;
- case SQL_CACHE:
- str->append(STRING_WITH_LEN("sql_cache "));
- break;
- case SQL_CACHE_UNSPECIFIED:
- break;
- default:
- DBUG_ASSERT(0);
+ switch (parent_lex->sql_cache)
+ {
+ case LEX::SQL_NO_CACHE:
+ str->append(STRING_WITH_LEN("sql_no_cache "));
+ break;
+ case LEX::SQL_CACHE:
+ str->append(STRING_WITH_LEN("sql_cache "));
+ break;
+ case LEX::SQL_CACHE_UNSPECIFIED:
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
}
//Item List
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 2cc47f6ec3b..4140a0293f8 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1473,6 +1473,11 @@ public:
Dynamic_array<KEYUSE_EXT> *ext_keyuses_for_splitting;
JOIN_TAB *sort_and_group_aggr_tab;
+ /*
+ Flag is set to true if select_lex was found to be degenerated before
+ the optimize_cond() call in JOIN::optimize_inner() method.
+ */
+ bool is_orig_degenerated;
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
@@ -1568,6 +1573,7 @@ public:
emb_sjm_nest= NULL;
sjm_lookup_tables= 0;
sjm_scan_tables= 0;
+ is_orig_degenerated= false;
}
/* True if the plan guarantees that it will be returned zero or one row */
@@ -1747,6 +1753,7 @@ public:
bool fix_all_splittings_in_plan();
bool transform_in_predicates_into_in_subq(THD *thd);
+ bool add_equalities_to_where_condition(THD *thd, List<Item> &eq_list);
private:
/**
Create a temporary table to be used for processing DISTINCT/ORDER
@@ -1811,10 +1818,6 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
void copy_fields(TMP_TABLE_PARAM *param);
bool copy_funcs(Item **func_ptr, const THD *thd);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
-Field* create_tmp_field_from_field(THD *thd, Field* org_field,
- LEX_CSTRING *name, TABLE *table,
- Item_field *item);
-
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
/* functions from opt_sum.cc */
@@ -2066,12 +2069,6 @@ bool mysql_select(THD *thd,
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
-Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
- Item ***copy_func, Field **from_field,
- Field **def_field,
- bool group, bool modify_item,
- bool table_cant_handle_bit_fields,
- bool make_copy_field);
/*
General routine to change field->ptr of a NULL-terminated array of Field
@@ -2339,7 +2336,7 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
extern bool test_if_ref(Item *,
Item_field *left_item,Item *right_item);
-inline bool optimizer_flag(THD *thd, uint flag)
+inline bool optimizer_flag(THD *thd, ulonglong flag)
{
return (thd->variables.optimizer_switch & flag);
}
@@ -2455,4 +2452,13 @@ int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort);
JOIN_TAB *first_explain_order_tab(JOIN* join);
JOIN_TAB *next_explain_order_tab(JOIN* join, JOIN_TAB* tab);
+bool check_simple_equality(THD *thd, const Item::Context &ctx,
+ Item *left_item, Item *right_item,
+ COND_EQUAL *cond_equal);
+
+void propagate_new_equalities(THD *thd, Item *cond,
+ List<Item_equal> *new_equalities,
+ COND_EQUAL *inherited,
+ bool *is_simplifiable_cond);
+
#endif /* SQL_SELECT_INCLUDED */
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index 1fb2e5e7714..1ed0bb38e64 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -220,8 +220,8 @@ bool check_sequence_fields(LEX *lex, List<Create_field> *fields)
err:
my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0),
- lex->select_lex.table_list.first->db.str,
- lex->select_lex.table_list.first->table_name.str, reason);
+ lex->first_select_lex()->table_list.first->db.str,
+ lex->first_select_lex()->table_list.first->table_name.str, reason);
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 33b28afd734..ea6ef7d86fb 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1034,9 +1034,9 @@ find_files(THD *thd, Dynamic_array<LEX_CSTRING*> *files, LEX_CSTRING *db,
if (!(dirp = my_dir(path, MY_THREAD_SPECIFIC | (db ? 0 : MY_WANT_STAT))))
{
if (my_errno == ENOENT)
- my_error(ER_BAD_DB_ERROR, MYF(ME_BELL | ME_WAITTANG), db->str);
+ my_error(ER_BAD_DB_ERROR, MYF(0), db->str);
else
- my_error(ER_CANT_READ_DIR, MYF(ME_BELL | ME_WAITTANG), path, my_errno);
+ my_error(ER_CANT_READ_DIR, MYF(0), path, my_errno);
DBUG_RETURN(FIND_FILES_DIR);
}
@@ -2184,6 +2184,12 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info);
+ DBUG_EXECUTE_IF("sql_type",
+ packet->append(" /* ");
+ packet->append(field->type_handler()->version().ptr());
+ packet->append(" */ ");
+ );
+
if (field->has_charset() && !(sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
if (field->charset() != share->table_charset)
@@ -4143,8 +4149,9 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
case SQLCOM_SHOW_TABLE_STATUS:
case SQLCOM_SHOW_TRIGGERS:
case SQLCOM_SHOW_EVENTS:
- thd->make_lex_string(&lookup_field_values->db_value,
- lex->select_lex.db.str, lex->select_lex.db.length);
+ thd->make_lex_string(&lookup_field_values->db_value,
+ lex->first_select_lex()->db.str,
+ lex->first_select_lex()->db.length);
if (wild)
{
thd->make_lex_string(&lookup_field_values->table_value,
@@ -4537,10 +4544,10 @@ fill_schema_table_by_open(THD *thd, MEM_ROOT *mem_root,
temporary LEX. The latter is required to correctly open views and
produce table describing their structure.
*/
- if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
+ if (make_table_list(thd, lex->first_select_lex(), &db_name, &table_name))
goto end;
- table_list= lex->select_lex.table_list.first;
+ table_list= lex->first_select_lex()->table_list.first;
if (is_show_fields_or_keys)
{
@@ -6715,7 +6722,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
& 'field_translation_end' are uninitialized is this
case.
*/
- List<Item> *fields= &tables->view->select_lex.item_list;
+ List<Item> *fields= &tables->view->first_select_lex()->item_list;
List_iterator<Item> it(*fields);
Item *item;
Item_field *field;
@@ -7368,7 +7375,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
break;
default:
DBUG_ASSERT(0);
- my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
+ my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL));
DBUG_RETURN(1);
}
table->field[7]->set_notnull();
@@ -7730,9 +7737,9 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
TABLE *table= tables->table;
CHARSET_INFO *cs= system_charset_info;
OPEN_TABLE_LIST *open_list;
- if (unlikely(!(open_list= list_open_tables(thd, thd->lex->select_lex.db.str,
- wild))) &&
- unlikely(thd->is_fatal_error))
+ if (!(open_list= list_open_tables(thd, thd->lex->first_select_lex()->db.str,
+ wild))
+ && thd->is_fatal_error)
DBUG_RETURN(1);
for (; open_list ; open_list=open_list->next)
@@ -8226,7 +8233,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
tmp_table_param->table_charset= cs;
tmp_table_param->field_count= field_count;
tmp_table_param->schema_table= 1;
- SELECT_LEX *select_lex= thd->lex->current_select;
+ SELECT_LEX *select_lex= table_list->select_lex;
bool keep_row_order= is_show_command(thd);
if (!(table= create_tmp_table(thd, tmp_table_param,
field_list, (ORDER*) 0, 0, 0,
@@ -8263,7 +8270,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= schema_table->fields_info;
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
for (; field_info->field_name; field_info++)
{
if (field_info->old_name)
@@ -8323,14 +8330,14 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
char tmp[128];
String buffer(tmp,sizeof(tmp), thd->charset());
LEX *lex= thd->lex;
- Name_resolution_context *context= &lex->select_lex.context;
+ Name_resolution_context *context= &lex->first_select_lex()->context;
ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
LEX_CSTRING field_name= {field_info->field_name,
strlen(field_info->field_name) };
buffer.length(0);
buffer.append(field_info->old_name);
- buffer.append(&lex->select_lex.db);
+ buffer.append(&lex->first_select_lex()->db);
if (lex->wild && lex->wild->ptr())
{
buffer.append(STRING_WITH_LEN(" ("));
@@ -8363,7 +8370,7 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
for (; *field_num >= 0; field_num++)
{
@@ -8394,7 +8401,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {0, 2, 1, 3, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
for (; *field_num >= 0; field_num++)
{
@@ -8421,7 +8428,7 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
int fields_arr[]= {2, 3, 4, 27, 24, 23, 22, 26, 28, 29, 30, -1};
int *field_num= fields_arr;
ST_FIELD_INFO *field_info;
- Name_resolution_context *context= &thd->lex->select_lex.context;
+ Name_resolution_context *context= &thd->lex->first_select_lex()->context;
for (; *field_num >= 0; field_num++)
{
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index a92d40f6bb3..83abaebd4fd 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -323,7 +323,7 @@ end:
set= m_set_signal_information.m_item[i];
if (set)
{
- if (set->fixed)
+ if (set->is_fixed())
set->cleanup();
}
}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 5d5cc90431b..e7acabe8bee 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -103,8 +103,7 @@ bool String::realloc_raw(size_t alloc_length)
(thread_specific ?
MY_THREAD_SPECIFIC : 0)))))
{
- if (str_length > len - 1)
- str_length= 0;
+ DBUG_ASSERT(str_length < len);
if (str_length) // Avoid bugs in memcpy on AIX
memcpy(new_ptr,Ptr,str_length);
new_ptr[str_length]=0;
diff --git a/sql/sql_string.h b/sql/sql_string.h
index d110e10647a..d9d3f10777c 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -761,6 +761,17 @@ public:
};
+class String_space: public String
+{
+public:
+ String_space(uint n)
+ {
+ if (fill(n, ' '))
+ set("", 0, &my_charset_bin);
+ }
+};
+
+
static inline bool check_if_only_end_space(CHARSET_INFO *cs,
const char *str,
const char *end)
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index daf8491a67f..92fcba4972f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4260,11 +4260,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
/* Give warnings for not supported table options */
-#if defined(WITH_ARIA_STORAGE_ENGINE)
extern handlerton *maria_hton;
- if (file->partition_ht() != maria_hton)
-#endif
- if (create_info->transactional)
+ if (file->partition_ht() != maria_hton && create_info->transactional &&
+ !file->has_transaction_manager())
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION),
@@ -4892,7 +4890,7 @@ int create_table_impl(THD *thd,
/*
Restart statement transactions for the case of CREATE ... SELECT.
*/
- if (thd->lex->select_lex.item_list.elements &&
+ if (thd->lex->first_select_lex()->item_list.elements &&
restart_trans_for_tables(thd, thd->lex->query_tables))
goto err;
}
@@ -9565,8 +9563,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
}
DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
- /* We can abort alter table for any table type */
- thd->abort_on_warning= !ignore && thd->is_strict_mode();
/*
Create .FRM for new version of table with a temporary name.
@@ -9596,7 +9592,6 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
C_ALTER_TABLE_FRM_ONLY, NULL,
&key_info, &key_count, &frm);
reenable_binlog(thd);
- thd->abort_on_warning= false;
if (unlikely(error))
{
my_free(const_cast<uchar*>(frm.str));
@@ -10065,19 +10060,17 @@ err_new_table_cleanup:
if (unlikely(alter_ctx.error_if_not_empty &&
thd->get_stmt_da()->current_row_for_warning()))
{
- const char *f_val= 0;
- enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
+ const char *f_val= "0000-00-00";
+ const char *f_type= "date";
switch (alter_ctx.datetime_field->real_field_type())
{
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_NEWDATE:
- f_val= "0000-00-00";
- t_type= MYSQL_TIMESTAMP_DATE;
break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_DATETIME2:
f_val= "0000-00-00 00:00:00";
- t_type= MYSQL_TIMESTAMP_DATETIME;
+ f_type= "datetime";
break;
default:
/* Shouldn't get here. */
@@ -10085,9 +10078,10 @@ err_new_table_cleanup:
}
bool save_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= true;
- make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- f_val, strlength(f_val), t_type,
- alter_ctx.datetime_field->field_name.str);
+ thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
+ f_type, f_val,
+ alter_ctx.datetime_field->
+ field_name.str);
thd->abort_on_warning= save_abort_on_warning;
}
@@ -10216,10 +10210,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
- /* Set read map for all fields in from table */
from->default_column_bitmaps();
- bitmap_set_all(from->read_set);
- from->file->column_bitmaps_signal();
/* We can abort alter table for any table type */
thd->abort_on_warning= !ignore && thd->is_strict_mode();
@@ -10249,7 +10240,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if (def->field == from->found_next_number_field)
thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
}
- (copy_end++)->set(*ptr,def->field,0);
+ if (!(*ptr)->vcol_info)
+ {
+ bitmap_set_bit(from->read_set, def->field->field_index);
+ (copy_end++)->set(*ptr,def->field,0);
+ }
}
else
{
@@ -10292,8 +10287,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
Filesort_tracker dummy_tracker(false);
Filesort fsort(order, HA_POS_ERROR, true, NULL);
- if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
- setup_order(thd, thd->lex->select_lex.ref_pointer_array,
+ if (thd->lex->first_select_lex()->setup_ref_array(thd, order_num) ||
+ setup_order(thd, thd->lex->first_select_lex()->ref_pointer_array,
&tables, fields, all_fields, order))
goto err;
@@ -10318,6 +10313,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
from_row_end= from->vers_end_field();
}
+ if (from_row_end)
+ bitmap_set_bit(from->read_set, from_row_end->field_index);
+
+ from->file->column_bitmaps_signal();
+
THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
@@ -10667,7 +10667,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
ha_checksum crc= 0;
uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
- t->use_all_columns();
+ t->use_all_stored_columns();
if (t->file->ha_rnd_init(1))
protocol->store_null();
diff --git a/sql/sql_time.cc b/sql/sql_time.cc
index 35ef1e50c36..c1300c78ad9 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -313,8 +313,7 @@ adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec)
if (check_time_range(ltime, dec, &warnings))
return true;
if (warnings)
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_TIME, NullS);
+ current_thd->push_warning_truncated_wrong_value("time", str.ptr());
return false;
}
@@ -399,11 +398,14 @@ str_to_datetime_with_warn(CHARSET_INFO *cs,
THD *thd= current_thd;
bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status);
if (ret_val || status.warnings)
+ {
+ const ErrConvString err(str, length, &my_charset_bin);
make_truncated_value_warning(thd,
ret_val ? Sql_condition::WARN_LEVEL_WARN :
Sql_condition::time_warn_level(status.warnings),
- str, length, flags & TIME_TIME_ONLY ?
+ &err, flags & TIME_TIME_ONLY ?
MYSQL_TIMESTAMP_TIME : l_time->time_type, NullS);
+ }
DBUG_EXECUTE_IF("str_to_datetime_warn",
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_YES, str););
@@ -411,77 +413,11 @@ str_to_datetime_with_warn(CHARSET_INFO *cs,
}
-/**
- converts a pair of numbers (integer part, microseconds) to MYSQL_TIME
-
- @param neg sign of the time value
- @param nr integer part of the number to convert
- @param sec_part microsecond part of the number
- @param ltime converted value will be written here
- @param fuzzydate conversion flags (TIME_INVALID_DATE, etc)
- @param str original number, as an ErrConv. For the warning
- @param field_name field name or NULL if not a field. For the warning
-
- @returns 0 for success, 1 for a failure
-*/
-static bool number_to_time_with_warn(bool neg, ulonglong nr, ulong sec_part,
- MYSQL_TIME *ltime, ulonglong fuzzydate,
- const ErrConv *str,
- const char *field_name)
-{
- int was_cut;
- longlong res;
- enum_mysql_timestamp_type ts_type;
- bool have_warnings;
-
- if (fuzzydate & TIME_TIME_ONLY)
- {
- fuzzydate= TIME_TIME_ONLY; // clear other flags
- ts_type= MYSQL_TIMESTAMP_TIME;
- res= number_to_time(neg, nr, sec_part, ltime, &was_cut);
- have_warnings= MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut);
- }
- else
- {
- ts_type= MYSQL_TIMESTAMP_DATETIME;
- if (neg)
- {
- res= -1;
- }
- else
- {
- res= number_to_datetime(nr, sec_part, ltime, fuzzydate, &was_cut);
- have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE);
- }
- }
-
- if (res < 0 || have_warnings)
- {
- make_truncated_value_warning(current_thd,
- Sql_condition::WARN_LEVEL_WARN, str,
- res < 0 ? MYSQL_TIMESTAMP_ERROR : ts_type,
- field_name);
- }
- return res < 0;
-}
-
-
bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
ulonglong fuzzydate, const char *field_name)
{
const ErrConvDouble str(value);
- bool neg= value < 0;
-
- if (neg)
- value= -value;
-
- if (value > LONGLONG_MAX)
- value= static_cast<double>(LONGLONG_MAX);
-
- longlong nr= static_cast<ulonglong>(floor(value));
- uint sec_part= static_cast<ulong>((value - floor(value))*TIME_SECOND_PART_FACTOR);
- return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate, &str,
- field_name);
+ return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
}
@@ -489,11 +425,7 @@ bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
ulonglong fuzzydate, const char *field_name)
{
const ErrConvDecimal str(value);
- ulonglong nr;
- ulong sec_part;
- bool neg= my_decimal2seconds(value, &nr, &sec_part);
- return number_to_time_with_warn(neg, nr, sec_part, ltime, fuzzydate, &str,
- field_name);
+ return Sec6(value).convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
}
@@ -501,8 +433,8 @@ bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
ulonglong fuzzydate, const char *field_name)
{
const ErrConvInteger str(neg ? - (longlong) value : (longlong) value, !neg);
- return number_to_time_with_warn(neg, value, 0, ltime,
- fuzzydate, &str, field_name);
+ Sec6 sec(neg, value, 0);
+ return sec.convert_to_mysql_time(ltime, fuzzydate, &str, field_name);
}
@@ -549,7 +481,7 @@ void localtime_to_TIME(MYSQL_TIME *to, struct tm *from)
}
-void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds)
+void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds)
{
long t_seconds;
// to->neg is not cleared, it may already be set to a useful value
@@ -932,9 +864,7 @@ void make_truncated_value_warning(THD *thd,
timestamp_type time_type,
const char *field_name)
{
- char warn_buff[MYSQL_ERRMSG_SIZE];
const char *type_str;
- CHARSET_INFO *cs= &my_charset_latin1;
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
@@ -948,23 +878,9 @@ void make_truncated_value_warning(THD *thd,
type_str= "datetime";
break;
}
- if (field_name)
- cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
- ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
- type_str, sval->ptr(), field_name,
- (ulong) thd->get_stmt_da()->current_row_for_warning());
- else
- {
- if (time_type > MYSQL_TIMESTAMP_ERROR)
- cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
- ER_THD(thd, ER_TRUNCATED_WRONG_VALUE),
- type_str, sval->ptr());
- else
- cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
- ER_THD(thd, ER_WRONG_VALUE), type_str, sval->ptr());
- }
- push_warning(thd, level,
- ER_TRUNCATED_WRONG_VALUE, warn_buff);
+ return thd->push_warning_wrong_or_truncated_value(level,
+ time_type <= MYSQL_TIMESTAMP_ERROR,
+ type_str, sval->ptr(), field_name);
}
@@ -1130,7 +1046,7 @@ null_date:
bool
calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int l_sign, longlong *seconds_out, long *microseconds_out)
+ int l_sign, ulonglong *seconds_out, ulong *microseconds_out)
{
long days;
bool neg;
@@ -1172,8 +1088,8 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
microseconds= -microseconds;
neg= 1;
}
- *seconds_out= microseconds/1000000L;
- *microseconds_out= (long) (microseconds%1000000L);
+ *seconds_out= (ulonglong) microseconds/1000000L;
+ *microseconds_out= (ulong) (microseconds%1000000L);
return neg;
}
@@ -1181,8 +1097,8 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int l_sign, MYSQL_TIME *l_time3, ulonglong fuzzydate)
{
- longlong seconds;
- long microseconds;
+ ulonglong seconds;
+ ulong microseconds;
bzero((char *) l_time3, sizeof(*l_time3));
l_time3->neg= calc_time_diff(l_time1, l_time2, l_sign,
&seconds, &microseconds);
@@ -1201,7 +1117,7 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
("invalid" means > TIME_MAX_SECOND)
*/
set_if_smaller(seconds, INT_MAX32);
- calc_time_from_sec(l_time3, (long) seconds, microseconds);
+ calc_time_from_sec(l_time3, (ulong) seconds, microseconds);
return ((fuzzydate & TIME_NO_ZERO_DATE) && (seconds == 0) &&
(microseconds == 0));
}
@@ -1335,8 +1251,8 @@ mix_date_and_time_complex(MYSQL_TIME *ldate, const MYSQL_TIME *ltime)
{
DBUG_ASSERT(ldate->time_type == MYSQL_TIMESTAMP_DATE ||
ldate->time_type == MYSQL_TIMESTAMP_DATETIME);
- longlong seconds;
- long days, useconds;
+ ulonglong seconds;
+ ulong days, useconds;
int sign= ltime->neg ? 1 : -1;
ldate->neg= calc_time_diff(ldate, ltime, sign, &seconds, &useconds);
@@ -1442,34 +1358,13 @@ time_to_datetime_with_warn(THD *thd,
check_date(to, fuzzydate, &warn)))
{
ErrConvTime str(from);
- make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- &str, MYSQL_TIMESTAMP_DATETIME, 0);
+ thd->push_warning_truncated_wrong_value("datetime", str.ptr());
return true;
}
return false;
}
-bool datetime_to_time_with_warn(THD *thd, const MYSQL_TIME *dt,
- MYSQL_TIME *tm, uint dec)
-{
- if (thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)
- {
- *tm= *dt;
- datetime_to_time(tm);
- return false;
- }
- else /* new mode */
- {
- MYSQL_TIME current_date;
- set_current_date(thd, &current_date);
- calc_time_diff(dt, &current_date, 1, tm, 0);
- }
- int warnings= 0;
- return check_time_range(tm, dec, &warnings);
-}
-
-
longlong pack_time(const MYSQL_TIME *my_time)
{
return ((((((my_time->year * 13ULL +
@@ -1511,3 +1406,10 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time,
break;
}
}
+
+
+bool my_decimal::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const char *field_name)
+{
+ return decimal_to_datetime_with_warn(this, to, fuzzydate, field_name);
+}
diff --git a/sql/sql_time.h b/sql/sql_time.h
index d3607a28a76..8c6e58856e6 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -54,50 +54,6 @@ bool time_to_datetime(THD *thd, const MYSQL_TIME *tm, MYSQL_TIME *dt);
bool time_to_datetime_with_warn(THD *thd,
const MYSQL_TIME *tm, MYSQL_TIME *dt,
ulonglong fuzzydate);
-/*
- Simply truncate the YYYY-MM-DD part to 0000-00-00
- and change time_type to MYSQL_TIMESTAMP_TIME
-*/
-inline void datetime_to_time(MYSQL_TIME *ltime)
-{
- DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_DATE ||
- ltime->time_type == MYSQL_TIMESTAMP_DATETIME);
- DBUG_ASSERT(ltime->neg == 0);
- ltime->year= ltime->month= ltime->day= 0;
- ltime->time_type= MYSQL_TIMESTAMP_TIME;
-}
-
-
-/**
- Convert DATE/DATETIME to TIME(dec)
- using CURRENT_DATE in a non-old mode,
- or using simple truncation in old mode (OLD_MODE_ZERO_DATE_TIME_CAST).
-
- @param thd - the thread to get the variables.old_behaviour value from
- @param dt - the DATE of DATETIME value to convert
- @param[out] tm - store result here
- @param dec - the desired scale. The fractional part of the result
- is checked according to this parameter before returning
- the conversion result. "dec" is important in the corner
- cases near the max/min limits.
- If the result is '838:59:59.999999' and the desired scale
- is less than 6, an error is returned.
- Note, dec is not important in the
- OLD_MODE_ZERO_DATE_TIME_CAST old mode.
-
- - in case of OLD_MODE_ZERO_DATE_TIME_CAST
- the TIME part is simply truncated and "false" is returned.
- - otherwise, the result is calculated effectively similar to:
- TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME))
- If the difference fits into the supported TIME range, "false" is returned,
- otherwise a warning is issued and "true" is returned.
-
- @return false - on success
- @return true - on error
-*/
-bool datetime_to_time_with_warn(THD *, const MYSQL_TIME *dt,
- MYSQL_TIME *tm, uint dec);
-
inline void datetime_to_date(MYSQL_TIME *ltime)
{
@@ -120,14 +76,6 @@ void make_truncated_value_warning(THD *thd,
timestamp_type time_type,
const char *field_name);
-static inline void make_truncated_value_warning(THD *thd,
- Sql_condition::enum_warning_level level, const char *str_val, size_t str_length, timestamp_type time_type,
- const char *field_name)
-{
- const ErrConvString str(str_val, str_length, &my_charset_bin);
- make_truncated_value_warning(thd, level, &str, time_type, field_name);
-}
-
extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
const char *format_str,
uint format_length);
@@ -141,7 +89,7 @@ bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
const INTERVAL &interval);
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int l_sign, longlong *seconds_out, long *microseconds_out);
+ int l_sign, ulonglong *seconds_out, ulong *microseconds_out);
int append_interval(String *str, interval_type int_type,
const INTERVAL &interval);
/**
@@ -171,7 +119,7 @@ bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
-void calc_time_from_sec(MYSQL_TIME *to, long seconds, long microseconds);
+void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds);
uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 755a9a9486d..9f26bff3321 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -2311,12 +2311,10 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
if (trg_field->field_idx != (uint)-1)
{
DBUG_PRINT("info", ("marking field: %d", trg_field->field_idx));
- bitmap_set_bit(trigger_table->read_set, trg_field->field_idx);
if (trg_field->get_settable_routine_parameter())
bitmap_set_bit(trigger_table->write_set, trg_field->field_idx);
- if (trigger_table->field[trg_field->field_idx]->vcol_info)
- trigger_table->mark_virtual_col(trigger_table->
- field[trg_field->field_idx]);
+ trigger_table->mark_column_with_deps(
+ trigger_table->field[trg_field->field_idx]);
}
}
}
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 201825d4593..34177242704 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -493,7 +493,7 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
bool Sql_cmd_truncate_table::execute(THD *thd)
{
bool res= TRUE;
- TABLE_LIST *table= thd->lex->select_lex.table_list.first;
+ TABLE_LIST *table= thd->lex->first_select_lex()->table_list.first;
DBUG_ENTER("Sql_cmd_truncate_table::execute");
if (check_one_table_access(thd, DROP_ACL, table))
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 188ba8c4629..43edd2d506a 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -173,7 +173,7 @@ bool get_type_attributes_for_tvc(THD *thd,
Item *item;
for (uint holder_pos= 0 ; (item= it++); holder_pos++)
{
- DBUG_ASSERT(item->fixed);
+ DBUG_ASSERT(item->is_fixed());
holders[holder_pos].add_argument(item);
}
}
@@ -251,7 +251,6 @@ bool table_value_constr::prepare(THD *thd, SELECT_LEX *sl,
holders[pos].type_handler(),
&holders[pos]/*Type_all_attributes*/,
holders[pos].get_maybe_null());
- new_holder->fix_fields(thd, 0);
sl->item_list.push_back(new_holder);
}
@@ -296,7 +295,7 @@ int table_value_constr::save_explain_data_intern(THD *thd,
explain->select_id= select_lex->select_number;
explain->select_type= select_lex->type;
- explain->linkage= select_lex->linkage;
+ explain->linkage= select_lex->get_linkage();
explain->using_temporary= false;
explain->using_filesort= false;
/* Setting explain->message means that all other members are invalid */
@@ -549,7 +548,7 @@ bool Item_subselect::wrap_tvc_in_derived_table(THD *thd,
Item *item;
SELECT_LEX *sq_select; // select for IN subquery;
sq_select= lex->current_select;
- sq_select->linkage= tvc_sl->linkage;
+ sq_select->set_linkage(tvc_sl->get_linkage());
sq_select->parsing_place= SELECT_LIST;
item= new (thd->mem_root) Item_field(thd, &sq_select->context,
NULL, NULL, &star_clex_str);
@@ -568,7 +567,7 @@ bool Item_subselect::wrap_tvc_in_derived_table(THD *thd,
goto err;
tvc_select= lex->current_select;
derived_unit= tvc_select->master_unit();
- tvc_select->linkage= DERIVED_TABLE_TYPE;
+ tvc_select->set_linkage(DERIVED_TABLE_TYPE);
lex->current_select= sq_select;
@@ -695,7 +694,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
mysql_init_select(lex);
tvc_select= lex->current_select;
derived_unit= tvc_select->master_unit();
- tvc_select->linkage= DERIVED_TABLE_TYPE;
+ tvc_select->set_linkage(DERIVED_TABLE_TYPE);
/* Create TVC used in the transformation */
if (create_value_list_for_tvc(thd, &values))
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 22eebaf6a38..e7fcdf499ec 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -21,11 +21,13 @@
#include "sql_time.h"
#include "item.h"
#include "log.h"
+#include "tztime.h"
Type_handler_row type_handler_row;
Type_handler_null type_handler_null;
+Type_handler_bool type_handler_bool;
Type_handler_tiny type_handler_tiny;
Type_handler_short type_handler_short;
Type_handler_long type_handler_long;
@@ -41,6 +43,7 @@ Type_handler_olddecimal type_handler_olddecimal;
Type_handler_newdecimal type_handler_newdecimal;
Type_handler_year type_handler_year;
+Type_handler_year type_handler_year2;
Type_handler_time type_handler_time;
Type_handler_date type_handler_date;
Type_handler_timestamp type_handler_timestamp;
@@ -56,6 +59,7 @@ Type_handler_set type_handler_set;
Type_handler_string type_handler_string;
Type_handler_var_string type_handler_var_string;
Type_handler_varchar type_handler_varchar;
+Type_handler_hex_hybrid type_handler_hex_hybrid;
static Type_handler_varchar_compressed type_handler_varchar_compressed;
Type_handler_tiny_blob type_handler_tiny_blob;
@@ -91,6 +95,9 @@ bool Type_handler_data::init()
&type_handler_geometry,
&type_handler_geometry) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
+ &type_handler_hex_hybrid,
+ &type_handler_long_blob) ||
+ m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_tiny_blob,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
@@ -125,12 +132,346 @@ bool Type_handler_data::init()
Type_handler_data *type_handler_data= NULL;
-void Time::make_from_item(Item *item, const Options opt)
+
+void VDec::set(Item *item)
+{
+ m_ptr= item->val_decimal(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+VDec::VDec(Item *item)
+{
+ m_ptr= item->val_decimal(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+VDec_op::VDec_op(Item_func_hybrid_field_type *item)
+{
+ m_ptr= item->decimal_op(&m_buffer);
+ DBUG_ASSERT((m_ptr == NULL) == item->null_value);
+}
+
+
+bool Dec_ptr::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ Item *item)
+{
+ if (to_datetime_with_warn(to, fuzzydate, item->field_name_or_null()))
+ return item->null_value|= item->make_zero_date(to, fuzzydate);
+ return item->null_value= false;
+}
+
+
+my_decimal *Temporal::to_decimal(my_decimal *to) const
+{
+ return date2my_decimal(this, to);
+}
+
+
+my_decimal *Temporal::bad_to_decimal(my_decimal *to) const
+{
+ my_decimal_set_zero(to);
+ return NULL;
+}
+
+
+Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item)
+{
+ if (item->get_date(this, sql_mode_for_dates(thd)))
+ time_type= MYSQL_TIMESTAMP_NONE;
+}
+
+
+void Sec6::make_from_decimal(const my_decimal *d)
+{
+ m_neg= my_decimal2seconds(d, &m_sec, &m_usec);
+ m_truncated= (m_sec >= LONGLONG_MAX);
+}
+
+
+void Sec6::make_from_double(double nr)
+{
+ if ((m_neg= nr < 0))
+ nr= -nr;
+ if ((m_truncated= nr > (double) LONGLONG_MAX))
+ {
+ m_sec= LONGLONG_MAX;
+ m_usec= 0;
+ }
+ else
+ {
+ m_sec= (ulonglong) nr;
+ m_usec= (ulong) ((nr - floor(nr)) * 1000000);
+ }
+}
+
+
+void Sec6::make_truncated_warning(THD *thd, const char *type_str) const
+{
+ char buff[1 + MAX_BIGINT_WIDTH + 1 + 6 + 1]; // '-' int '.' frac '\0'
+ to_string(buff, sizeof(buff));
+ current_thd->push_warning_truncated_wrong_value(type_str, buff);
+}
+
+
+bool Sec6::to_time_with_warn(MYSQL_TIME *to, const ErrConv *str,
+ const char *field_name) const
+{
+ int was_cut;
+ bool res= to_time(to, &was_cut);
+ if (res || MYSQL_TIME_WARN_HAVE_WARNINGS(was_cut))
+ current_thd->
+ push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ res, "time", str->ptr(),
+ field_name);
+ return res;
+}
+
+
+bool Sec6::to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const ErrConv *str,
+ const char *field_name) const
+{
+ bool res, have_warnings= false;
+ int was_cut;
+ res= to_datetime(to, fuzzydate, &was_cut);
+ have_warnings= was_cut && (fuzzydate & TIME_NO_ZERO_IN_DATE);
+ if (res || have_warnings)
+ current_thd->
+ push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ res, "datetime", str->ptr(),
+ field_name);
+ return res;
+}
+
+
+bool Sec6::convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate,
+ const ErrConv *str, const char *field_name)
+ const
+{
+ bool is_time= fuzzydate & TIME_TIME_ONLY;
+ if (truncated())
+ {
+ /*
+ The value was already truncated at the constructor call time,
+ and a truncation warning was issued. Here we convert silently
+ to avoid double warnings.
+ */
+ current_thd->
+ push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ !is_time,
+ is_time ? "time" : "datetime",
+ str->ptr(), field_name);
+ int warn;
+ return is_time ? to_time(ltime, &warn) :
+ to_datetime(ltime, fuzzydate, &warn);
+ }
+ return is_time ? to_time_with_warn(ltime, str, field_name) :
+ to_datetime_with_warn(ltime, fuzzydate, str, field_name);
+}
+
+
+VSec6::VSec6(Item *item, const char *type_str, ulonglong limit)
+{
+ if (item->decimals == 0)
+ { // optimize for an important special case
+ longlong nr= item->val_int();
+ make_from_int(nr, item->unsigned_flag);
+ m_is_null= item->null_value;
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ ErrConvInteger err(nr, item->unsigned_flag);
+ current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+ else if (item->cmp_type() == REAL_RESULT)
+ {
+ double nr= item->val_real();
+ make_from_double(nr);
+ m_is_null= item->null_value;
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ }
+ if (m_truncated)
+ {
+ ErrConvDouble err(nr);
+ current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+ else
+ {
+ VDec tmp(item);
+ (m_is_null= tmp.is_null()) ? reset() : make_from_decimal(tmp.ptr());
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ }
+ if (m_truncated)
+ {
+ ErrConvDecimal err(tmp.ptr());
+ current_thd->push_warning_truncated_wrong_value(type_str, err.ptr());
+ }
+ }
+}
+
+
+Year::Year(longlong value, bool unsigned_flag, uint length)
{
+ if ((m_truncated= (value < 0))) // Negative or huge unsigned
+ m_year= unsigned_flag ? 9999 : 0;
+ else if (value > 9999)
+ {
+ m_truncated= true;
+ m_year= 9999;
+ }
+ else if (length == 2)
+ {
+ m_year= value < 70 ? (uint) value + 2000 :
+ value <= 1900 ? (uint) value + 1900 :
+ (uint) value;
+ }
+ else
+ m_year= (uint) value;
+ DBUG_ASSERT(m_year <= 9999);
+}
+
+
+uint Year::year_precision(const Item *item) const
+{
+ return item->type_handler() == &type_handler_year2 ? 2 : 4;
+}
+
+
+VYear::VYear(Item *item)
+ :Year_null(Year(item->val_int(), item->unsigned_flag,
+ year_precision(item)), item->null_value)
+{ }
+
+
+VYear_op::VYear_op(Item_func_hybrid_field_type *item)
+ :Year_null(Year(item->int_op(), item->unsigned_flag,
+ year_precision(item)), item->null_value)
+{ }
+
+
+void Time::make_from_item(int *warn, Item *item, const Options opt)
+{
+ *warn= 0;
if (item->get_date(this, opt.get_date_flags()))
time_type= MYSQL_TIMESTAMP_NONE;
else
- valid_MYSQL_TIME_to_valid_value(opt);
+ valid_MYSQL_TIME_to_valid_value(warn, opt);
+}
+
+
+/**
+ Create from a DATETIME by subtracting a given number of days,
+ implementing an optimized version of calc_time_diff().
+*/
+void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
+ long days)
+{
+ *warn= 0;
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATETIME ||
+ from->time_type == MYSQL_TIMESTAMP_DATE);
+ long daynr= calc_daynr(from->year, from->month, from->day);
+ long daydiff= daynr - days;
+ if (!daynr) // Zero date
+ {
+ set_zero_time(this, MYSQL_TIMESTAMP_TIME);
+ neg= true;
+ hour= TIME_MAX_HOUR + 1; // to report "out of range" in "warn"
+ }
+ else if (daydiff >=0)
+ {
+ neg= false;
+ year= month= day= 0;
+ hhmmssff_copy(from);
+ hour+= daydiff * 24;
+ time_type= MYSQL_TIMESTAMP_TIME;
+ }
+ else
+ {
+ longlong timediff= ((((daydiff * 24LL +
+ from->hour) * 60LL +
+ from->minute) * 60LL +
+ from->second) * 1000000LL +
+ from->second_part);
+ unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME);
+ if (year || month)
+ {
+ *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ year= month= day= 0;
+ hour= TIME_MAX_HOUR + 1;
+ }
+ }
+ // The above code can generate TIME values outside of the valid TIME range.
+ adjust_time_range_or_invalidate(warn);
+}
+
+
+void Time::make_from_datetime_move_day_to_hour(int *warn,
+ const MYSQL_TIME *from)
+{
+ *warn= 0;
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
+ from->time_type == MYSQL_TIMESTAMP_DATETIME);
+ time_type= MYSQL_TIMESTAMP_TIME;
+ neg= false;
+ year= month= day= 0;
+ hhmmssff_copy(from);
+ datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, from->year,
+ from->month, from->day);
+ adjust_time_range_or_invalidate(warn);
+}
+
+
+void Time::make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays)
+{
+ if (!curdays)
+ make_from_datetime_move_day_to_hour(warn, from);
+ else
+ make_from_datetime_with_days_diff(warn, from, curdays);
+}
+
+
+void Time::make_from_time(int *warn, const MYSQL_TIME *from)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
+ if (from->year || from->month)
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ DBUG_ASSERT(from->day == 0);
+ *(static_cast<MYSQL_TIME*>(this))= *from;
+ adjust_time_range_or_invalidate(warn);
+ }
+}
+
+
+Time::Time(int *warn, const MYSQL_TIME *from, long curdays)
+{
+ switch (from->time_type) {
+ case MYSQL_TIMESTAMP_NONE:
+ case MYSQL_TIMESTAMP_ERROR:
+ make_from_out_of_range(warn);
+ break;
+ case MYSQL_TIMESTAMP_DATE:
+ case MYSQL_TIMESTAMP_DATETIME:
+ make_from_datetime(warn, from, curdays);
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ make_from_time(warn, from);
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
}
@@ -160,6 +501,71 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
}
+void Temporal_with_date::make_from_item(THD *thd, Item *item)
+{
+ return make_from_item(thd, item, sql_mode_for_dates(thd));
+}
+
+
+void Temporal_with_date::check_date_or_invalidate(int *warn, sql_mode_t flags)
+{
+ if (check_date(this, pack_time(this) != 0, flags, warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+}
+
+
+void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
+ sql_mode_t flags)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
+ if (time_to_datetime(thd, from, this))
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ check_date_or_invalidate(warn, flags);
+ }
+}
+
+
+void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ sql_mode_t flags)
+{
+ DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
+ from->time_type == MYSQL_TIMESTAMP_DATETIME);
+ if (from->neg || check_datetime_range(from))
+ make_from_out_of_range(warn);
+ else
+ {
+ *warn= 0;
+ *(static_cast<MYSQL_TIME*>(this))= *from;
+ date_to_datetime(this);
+ check_date_or_invalidate(warn, flags);
+ }
+}
+
+
+Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ sql_mode_t flags)
+{
+ DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
+ switch (from->time_type) {
+ case MYSQL_TIMESTAMP_ERROR:
+ case MYSQL_TIMESTAMP_NONE:
+ make_from_out_of_range(warn);
+ break;
+ case MYSQL_TIMESTAMP_TIME:
+ make_from_time(thd, warn, from, flags);
+ break;
+ case MYSQL_TIMESTAMP_DATETIME:
+ case MYSQL_TIMESTAMP_DATE:
+ make_from_datetime(thd, warn, from, flags);
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
{
uint res= 0;
@@ -280,6 +686,32 @@ bool Type_std_attributes::count_string_length(const char *func_name,
}
+/*
+ Find a handler by its ODBC literal data type.
+
+ @param type_str - data type name, not necessarily 0-terminated
+ @retval - a pointer to data type handler if type_str points
+ to a known ODBC literal data type, or NULL otherwise
+*/
+const Type_handler *
+Type_handler::odbc_literal_type_handler(const LEX_CSTRING *type_str)
+{
+ if (type_str->length == 1)
+ {
+ if (type_str->str[0] == 'd') // {d'2001-01-01'}
+ return &type_handler_newdate;
+ else if (type_str->str[0] == 't') // {t'10:20:30'}
+ return &type_handler_time2;
+ }
+ 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 &type_handler_datetime2;
+ }
+ return NULL; // Not a known ODBC literal type
+}
+
+
/**
This method is used by:
- Item_user_var_as_out_param::field_type()
@@ -433,6 +865,7 @@ const Name
Type_handler_string::m_name_char(STRING_WITH_LEN("char")),
Type_handler_var_string::m_name_var_string(STRING_WITH_LEN("varchar")),
Type_handler_varchar::m_name_varchar(STRING_WITH_LEN("varchar")),
+ Type_handler_hex_hybrid::m_name_hex_hybrid(STRING_WITH_LEN("hex_hybrid")),
Type_handler_tiny_blob::m_name_tinyblob(STRING_WITH_LEN("tinyblob")),
Type_handler_medium_blob::m_name_mediumblob(STRING_WITH_LEN("mediumblob")),
Type_handler_long_blob::m_name_longblob(STRING_WITH_LEN("longblob")),
@@ -443,6 +876,7 @@ const Name
Type_handler_set::m_name_set(STRING_WITH_LEN("set"));
const Name
+ Type_handler_bool::m_name_bool(STRING_WITH_LEN("boolean")),
Type_handler_tiny::m_name_tiny(STRING_WITH_LEN("tinyint")),
Type_handler_short::m_name_short(STRING_WITH_LEN("smallint")),
Type_handler_long::m_name_int(STRING_WITH_LEN("int")),
@@ -465,6 +899,11 @@ const Name
Type_handler_datetime_common::m_name_datetime(STRING_WITH_LEN("datetime")),
Type_handler_timestamp_common::m_name_timestamp(STRING_WITH_LEN("timestamp"));
+const Name
+ Type_handler::m_version_default(STRING_WITH_LEN("")),
+ Type_handler::m_version_mariadb53(STRING_WITH_LEN("mariadb-5.3")),
+ Type_handler::m_version_mysql56(STRING_WITH_LEN("mysql-5.6"));
+
const Type_limits_int
Type_handler_tiny::m_limits_sint8= Type_limits_sint8(),
@@ -1604,6 +2043,70 @@ bool Type_handler_bit::
/*************************************************************************/
+void Type_handler_blob_common::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ DBUG_ASSERT(def->key_length == 0);
+}
+
+
+void Type_handler_typelib::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG));
+ def->interval= field->get_typelib();
+}
+
+
+#ifdef HAVE_SPATIAL
+void Type_handler_geometry::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ def->geom_type= ((Field_geom*) field)->geom_type;
+ def->srid= ((Field_geom*) field)->srid;
+}
+#endif
+
+
+void Type_handler_year::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ if (def->length != 4)
+ {
+ char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
+ my_snprintf(buff, sizeof(buff), "YEAR(%llu)", def->length);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
+ buff, "YEAR(4)");
+ }
+}
+
+
+void Type_handler_real_result::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ /*
+ Floating points are stored with FLOATING_POINT_DECIMALS but internally
+ in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS.
+ */
+ if (def->decimals >= FLOATING_POINT_DECIMALS)
+ def->decimals= NOT_FIXED_DEC;
+}
+
+
+/*************************************************************************/
+
bool Type_handler::
Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
@@ -2007,8 +2510,8 @@ Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_tiny(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_tiny(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2020,8 +2523,8 @@ Field *Type_handler_short::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_short(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_short(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2032,8 +2535,8 @@ Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_medium(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_medium(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
0/*zerofill*/, attr.unsigned_flag);
}
@@ -2045,8 +2548,8 @@ Field *Type_handler_long::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_long(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_long(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2057,8 +2560,8 @@ Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_longlong(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_longlong(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
0/*zerofill*/, attr.unsigned_flag);
}
@@ -2070,8 +2573,8 @@ Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_vers_trx_id(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_vers_trx_id(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
0/*zerofill*/, attr.unsigned_flag);
}
@@ -2083,8 +2586,8 @@ Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_float(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_float(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
(uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2096,8 +2599,8 @@ Field *Type_handler_double::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_double(addr.ptr, attr.max_char_length(),
- addr.null_ptr, addr.null_bit,
+ Field_double(addr.ptr(), attr.max_char_length(),
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
(uint8) attr.decimals, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2118,7 +2621,8 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
*/
DBUG_ASSERT(0);
return new (table->in_use->mem_root)
- Field_decimal(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+ Field_decimal(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name, (uint8) attr.decimals,
0/*zerofill*/,attr.unsigned_flag);
}
@@ -2165,7 +2669,7 @@ Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
len= required_length;
}
return new (table->in_use->mem_root)
- Field_new_decimal(addr.ptr, len, addr.null_ptr, addr.null_bit,
+ Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
dec, 0/*zerofill*/, attr.unsigned_flag);
}
@@ -2177,7 +2681,8 @@ Field *Type_handler_year::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_year(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+ Field_year(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
@@ -2189,7 +2694,7 @@ Field *Type_handler_null::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_null(addr.ptr, attr.max_length,
+ Field_null(addr.ptr(), attr.max_length,
Field::NONE, name, attr.collation.collation);
}
@@ -2201,7 +2706,7 @@ Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name,
{
return new_Field_timestamp(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, attr.decimals);
}
@@ -2217,7 +2722,7 @@ Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name,
make_table_field() for make_field() purposes in field.cc.
*/
return new_Field_timestamp(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, attr.decimals);
}
@@ -2229,7 +2734,7 @@ Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_newdate(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
@@ -2246,7 +2751,7 @@ Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
*/
DBUG_ASSERT(0);
return new (table->in_use->mem_root)
- Field_date(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
@@ -2258,7 +2763,7 @@ Field *Type_handler_time::make_table_field(const LEX_CSTRING *name,
{
return new_Field_time(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
@@ -2275,7 +2780,7 @@ Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
make_table_field() for make_field() purposes in field.cc.
*/
return new_Field_time(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
@@ -2287,7 +2792,7 @@ Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name,
{
return new_Field_datetime(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
@@ -2302,7 +2807,7 @@ Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name,
make_table_field() for make_field() purposes in field.cc.
*/
return new_Field_datetime(table->in_use->mem_root,
- addr.ptr, addr.null_ptr, addr.null_bit,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
@@ -2314,8 +2819,8 @@ Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_bit_as_char(addr.ptr, attr.max_length,
- addr.null_ptr, addr.null_bit,
+ Field_bit_as_char(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
@@ -2327,7 +2832,8 @@ Field *Type_handler_string::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_string(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+ Field_string(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.collation);
}
@@ -2339,9 +2845,9 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_varstring(addr.ptr, attr.max_length,
+ Field_varstring(addr.ptr(), attr.max_length,
HA_VARCHAR_PACKLENGTH(attr.max_length),
- addr.null_ptr, addr.null_bit,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
table->s, attr.collation);
}
@@ -2354,7 +2860,7 @@ Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
1, attr.collation);
}
@@ -2367,7 +2873,7 @@ Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
2, attr.collation);
}
@@ -2381,7 +2887,7 @@ Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
3, attr.collation);
}
@@ -2394,7 +2900,7 @@ Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
- Field_blob(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
4, attr.collation);
}
@@ -2408,7 +2914,7 @@ Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name,
TABLE *table) const
{
return new (table->in_use->mem_root)
- Field_geom(addr.ptr, addr.null_ptr, addr.null_bit,
+ Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, 4,
(Field::geometry_type) attr.uint_geometry_type(),
0);
@@ -2424,7 +2930,8 @@ Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
return new (table->in_use->mem_root)
- Field_enum(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+ Field_enum(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
get_enum_pack_length(typelib->count), typelib,
attr.collation);
@@ -2440,7 +2947,8 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
return new (table->in_use->mem_root)
- Field_set(addr.ptr, attr.max_length, addr.null_ptr, addr.null_bit,
+ Field_set(addr.ptr(), attr.max_length,
+ addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
get_enum_pack_length(typelib->count), typelib,
attr.collation);
@@ -2512,6 +3020,61 @@ uint32 Type_handler_general_purpose_int::max_display_length(const Item *item)
/*************************************************************************/
+void Type_handler_row::Item_update_null_value(Item *item) const
+{
+ DBUG_ASSERT(0);
+ item->null_value= true;
+}
+
+
+void Type_handler_time_common::Item_update_null_value(Item *item) const
+{
+ MYSQL_TIME ltime;
+ (void) item->get_date(&ltime, TIME_TIME_ONLY);
+}
+
+
+void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const
+{
+ MYSQL_TIME ltime;
+ (void) item->get_date(&ltime, sql_mode_for_dates(current_thd));
+}
+
+
+void Type_handler_string_result::Item_update_null_value(Item *item) const
+{
+ StringBuffer<MAX_FIELD_WIDTH> tmp;
+ (void) item->val_str(&tmp);
+}
+
+
+void Type_handler_real_result::Item_update_null_value(Item *item) const
+{
+ (void) item->val_real();
+}
+
+
+void Type_handler_decimal_result::Item_update_null_value(Item *item) const
+{
+ my_decimal tmp;
+ (void) item->val_decimal(&tmp);
+}
+
+
+void Type_handler_int_result::Item_update_null_value(Item *item) const
+{
+ (void) item->val_int();
+}
+
+
+void Type_handler_bool::Item_update_null_value(Item *item) const
+{
+ (void) item->val_bool();
+}
+
+
+/*************************************************************************/
+
int Type_handler_time_common::Item_save_in_field(Item *item, Field *field,
bool no_conversions) const
{
@@ -2704,7 +3267,7 @@ Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const
Item_cache *
Type_handler_year::Item_get_cache(THD *thd, const Item *item) const
{
- return new (thd->mem_root) Item_cache_year(thd);
+ return new (thd->mem_root) Item_cache_year(thd, item->type_handler());
}
Item_cache *
@@ -2824,8 +3387,21 @@ bool Type_handler_typelib::
TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++)
{
- if ((typelib= items[i]->get_typelib()))
- break;
+ TYPELIB *typelib2;
+ if ((typelib2= items[i]->get_typelib()))
+ {
+ if (typelib)
+ {
+ /*
+ Two ENUM/SET columns found. We convert such combinations to VARCHAR.
+ This may change in the future to preserve ENUM/SET
+ if typelib definitions are equal.
+ */
+ handler->set_handler(&type_handler_varchar);
+ return func->aggregate_attributes_string(func_name, items, nitems);
+ }
+ typelib= typelib2;
+ }
}
DBUG_ASSERT(typelib); // There must be at least one typelib
func->set_typelib(typelib);
@@ -2983,6 +3559,13 @@ bool Type_handler_int_result::
}
+bool Type_handler_bool::
+ Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+{
+ return Item_sum_hybrid_fix_length_and_dec_numeric(func, &type_handler_bool);
+}
+
+
bool Type_handler_real_result::
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
@@ -3211,15 +3794,6 @@ bool Type_handler_int_result::Item_val_bool(Item *item) const
return item->val_int() != 0;
}
-bool Type_handler_decimal_result::Item_val_bool(Item *item) const
-{
- my_decimal decimal_value;
- my_decimal *val= item->val_decimal(&decimal_value);
- if (val)
- return !my_decimal_is_zero(val);
- return false;
-}
-
bool Type_handler_temporal_result::Item_val_bool(Item *item) const
{
return item->val_real() != 0.0;
@@ -3243,7 +3817,9 @@ bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
- return item->get_date_from_year(ltime, fuzzydate);
+ return item->null_value=
+ VYear(item).to_mysql_time_with_warn(ltime, fuzzydate,
+ item->field_name_or_null());
}
@@ -3254,13 +3830,6 @@ bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
}
-bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
-{
- return item->get_date_from_decimal(ltime, fuzzydate);
-}
-
-
bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
@@ -3324,12 +3893,6 @@ longlong Type_handler_int_result::
return item->val_int_unsigned_typecast_from_int();
}
-longlong Type_handler_decimal_result::
- Item_val_int_unsigned_typecast(Item *item) const
-{
- return item->val_int_unsigned_typecast_from_decimal();
-}
-
longlong Type_handler_temporal_result::
Item_val_int_unsigned_typecast(Item *item) const
{
@@ -3390,7 +3953,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_str(
Item_func_hybrid_field_type *item,
String *str) const
{
- return item->val_str_from_decimal_op(str);
+ return VDec_op(item).to_string_round(str, item->decimals);
}
@@ -3399,7 +3962,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_real(
Item_func_hybrid_field_type *item)
const
{
- return item->val_real_from_decimal_op();
+ return VDec_op(item).to_double();
}
@@ -3408,7 +3971,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_int(
Item_func_hybrid_field_type *item)
const
{
- return item->val_int_from_decimal_op();
+ return VDec_op(item).to_longlong(item->unsigned_flag);
}
@@ -3417,7 +3980,7 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *item,
my_decimal *dec) const
{
- return item->val_decimal_from_decimal_op(dec);
+ return VDec_op(item).to_decimal(dec);
}
@@ -3427,7 +3990,18 @@ Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
MYSQL_TIME *ltime,
ulonglong fuzzydate) const
{
- return item->get_date_from_decimal_op(ltime, fuzzydate);
+ return VDec_op(item).to_datetime_with_warn(ltime, fuzzydate, item);
+}
+
+
+bool
+Type_handler_year::Item_func_hybrid_field_type_get_date(
+ Item_func_hybrid_field_type *item,
+ MYSQL_TIME *ltime,
+ ulonglong fuzzydate) const
+{
+ return item->null_value=
+ VYear_op(item).to_mysql_time_with_warn(ltime, fuzzydate, NULL);
}
@@ -3707,10 +4281,16 @@ longlong Type_handler_string_result::
return func->val_int_cmp_string();
}
-longlong Type_handler_temporal_result::
+longlong Type_handler_temporal_with_date::
+ Item_func_between_val_int(Item_func_between *func) const
+{
+ return func->val_int_cmp_datetime();
+}
+
+longlong Type_handler_time_common::
Item_func_between_val_int(Item_func_between *func) const
{
- return func->val_int_cmp_temporal();
+ return func->val_int_cmp_time();
}
longlong Type_handler_int_result::
@@ -3930,10 +4510,31 @@ String *Type_handler_string_result::
}
-String *Type_handler_temporal_result::
+String *Type_handler_time_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Time(func).to_string(str, func->decimals);
+}
+
+
+String *Type_handler_date_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Date(func).to_string(str);
+}
+
+
+String *Type_handler_datetime_common::
+ Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
+{
+ return Datetime(func).to_string(str, func->decimals);
+}
+
+
+String *Type_handler_timestamp_common::
Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
- return func->val_string_from_date(str);
+ return Datetime(func).to_string(str, func->decimals);
}
@@ -3947,7 +4548,7 @@ String *Type_handler_int_result::
String *Type_handler_decimal_result::
Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
- return func->val_string_from_decimal(str);
+ return VDec(func).to_string_round(str, func->decimals);
}
@@ -4892,7 +5493,7 @@ uint Type_handler_string_result::Item_temporal_precision(Item *item,
StringBuffer<64> buf;
String *tmp;
MYSQL_TIME_STATUS status;
- DBUG_ASSERT(item->fixed);
+ DBUG_ASSERT(item->is_fixed());
if ((tmp= item->val_str(&buf)) &&
!(is_time ?
str_to_time(tmp->charset(), tmp->ptr(), tmp->length(),
@@ -5393,11 +5994,10 @@ Item *Type_handler_real_result::
Item *Type_handler_decimal_result::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
- my_decimal decimal_value;
- my_decimal *result= item->val_decimal(&decimal_value);
- if (item->null_value)
+ VDec result(item);
+ if (result.is_null())
return new (thd->mem_root) Item_null(thd, item->name.str);
- return new (thd->mem_root) Item_decimal(thd, item->name.str, result,
+ return new (thd->mem_root) Item_decimal(thd, item->name.str, result.ptr(),
item->max_length, item->decimals);
}
@@ -5787,6 +6387,490 @@ void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
/***************************************************************************/
+Field *Type_handler_row::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ DBUG_ASSERT(attr->length == 0);
+ DBUG_ASSERT(f_maybe_null(attr->pack_flag));
+ return new (mem_root) Field_row(rec.ptr(), name);
+}
+
+
+Field *Type_handler_olddecimal::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_decimal(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_decimals(attr->pack_flag),
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_newdecimal::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_new_decimal(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_decimals(attr->pack_flag),
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_float::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ int decimals= f_decimals(attr->pack_flag);
+ if (decimals == FLOATING_POINT_DECIMALS)
+ decimals= NOT_FIXED_DEC;
+ return new (mem_root)
+ Field_float(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag)== 0);
+}
+
+
+Field *Type_handler_double::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ int decimals= f_decimals(attr->pack_flag);
+ if (decimals == FLOATING_POINT_DECIMALS)
+ decimals= NOT_FIXED_DEC;
+ return new (mem_root)
+ Field_double(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag)== 0);
+}
+
+
+Field *Type_handler_tiny::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_tiny(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_short::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_short(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_int24::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_medium(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_long::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_long(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_longlong::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
+ return new (mem_root)
+ Field_vers_trx_id(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+ return new (mem_root)
+ Field_longlong(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+}
+
+
+Field *Type_handler_timestamp::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new_Field_timestamp(mem_root,
+ rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_timestamp2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check,
+ name, share, attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_year::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_year(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_date::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_date(rec.ptr(),rec.null_ptr(),rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_newdate::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_newdate(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name);
+}
+
+
+Field *Type_handler_time::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MIN_TIME_WIDTH));
+}
+
+
+Field *Type_handler_time2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MIN_TIME_WIDTH));
+}
+
+
+Field *Type_handler_datetime::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_datetime2::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name,
+ attr->temporal_dec(MAX_DATETIME_WIDTH));
+}
+
+
+Field *Type_handler_null::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_null(rec.ptr(), (uint32) attr->length, attr->unireg_check,
+ name, attr->charset);
+}
+
+
+Field *Type_handler_bit::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return f_bit_as_char(attr->pack_flag) ?
+ new (mem_root) Field_bit_as_char(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name) :
+ new (mem_root) Field_bit(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ bit.ptr(), bit.offs(), attr->unireg_check, name);
+}
+
+
+#ifdef HAVE_SPATIAL
+Field *Type_handler_geometry::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ status_var_increment(current_thd->status_var.feature_gis);
+ return new (mem_root)
+ Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->geom_type, attr->srid);
+}
+#endif
+
+
+Field *Type_handler_string::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_string(rec.ptr(), (uint32) attr->length,
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->charset);
+}
+
+
+Field *Type_handler_varchar::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_varstring_compressed(rec.ptr(), (uint32) attr->length,
+ HA_VARCHAR_PACKLENGTH((uint32) attr->length),
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share, attr->charset,
+ zlib_compression_method);
+ return new (mem_root)
+ Field_varstring(rec.ptr(), (uint32) attr->length,
+ HA_VARCHAR_PACKLENGTH((uint32) attr->length),
+ rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share, attr->charset);
+}
+
+
+Field *Type_handler_blob_common::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
+ return new (mem_root)
+ Field_blob_compressed(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->charset,
+ zlib_compression_method);
+ return new (mem_root)
+ Field_blob(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->charset);
+}
+
+
+Field *Type_handler_enum::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->pack_flag_to_pack_length(),
+ attr->interval, attr->charset);
+}
+
+
+Field *Type_handler_set::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root)
+ Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, attr->pack_flag_to_pack_length(),
+ attr->interval, attr->charset);
+}
+
+
+/***************************************************************************/
+
+void Type_handler::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_basic(buff);
+ def->frm_pack_charset(buff);
+}
+
+
+#ifdef HAVE_SPATIAL
+void Type_handler_geometry::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_basic(buff);
+ buff[11]= 0;
+ buff[14]= (uchar) def->geom_type;
+}
+#endif
+
+
+/***************************************************************************/
+
+bool Type_handler::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ attr->frm_unpack_basic(buffer);
+ return attr->frm_unpack_charset(share, buffer);
+}
+
+
+#ifdef HAVE_SPATIAL
+bool Type_handler_geometry::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ uint gis_opt_read, gis_length, gis_decimals;
+ Field_geom::storage_type st_type;
+ attr->frm_unpack_basic(buffer);
+ // charset and geometry_type share the same byte in frm
+ attr->geom_type= (Field::geometry_type) buffer[14];
+ gis_opt_read= gis_field_options_read(gis_options->str,
+ gis_options->length,
+ &st_type, &gis_length,
+ &gis_decimals, &attr->srid);
+ gis_options->str+= gis_opt_read;
+ gis_options->length-= gis_opt_read;
+ return false;
+}
+#endif
+
+/***************************************************************************/
+
bool Type_handler::Vers_history_point_resolve_unit(THD *thd,
Vers_history_point *point)
const
@@ -5845,3 +6929,360 @@ bool Type_handler_general_purpose_string::
}
/***************************************************************************/
+
+bool Type_handler_null::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ return true;
+}
+
+
+bool Type_handler_real_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const double *va= a->const_ptr_double();
+ const double *vb= b->const_ptr_double();
+ return va[0] == vb[0];
+}
+
+
+bool Type_handler_int_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const longlong *va= a->const_ptr_longlong();
+ const longlong *vb= b->const_ptr_longlong();
+ bool res= va[0] == vb[0] &&
+ (va[0] >= 0 ||
+ (a->get_type_all_attributes_from_const()->unsigned_flag ==
+ b->get_type_all_attributes_from_const()->unsigned_flag));
+ return res;
+}
+
+
+bool Type_handler_string_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const String *sa= a->const_ptr_string();
+ const String *sb= b->const_ptr_string();
+ return binary_cmp ? sa->bin_eq(sb) :
+ a->get_type_all_attributes_from_const()->collation.collation ==
+ b->get_type_all_attributes_from_const()->collation.collation &&
+ sa->eq(sb, a->get_type_all_attributes_from_const()->collation.collation);
+}
+
+
+bool
+Type_handler_decimal_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const my_decimal *da= a->const_ptr_my_decimal();
+ const my_decimal *db= b->const_ptr_my_decimal();
+ return !da->cmp(db) &&
+ (!binary_cmp ||
+ a->get_type_all_attributes_from_const()->decimals ==
+ b->get_type_all_attributes_from_const()->decimals);
+}
+
+
+bool
+Type_handler_temporal_result::Item_const_eq(const Item_const *a,
+ const Item_const *b,
+ bool binary_cmp) const
+{
+ const MYSQL_TIME *ta= a->const_ptr_mysql_time();
+ const MYSQL_TIME *tb= b->const_ptr_mysql_time();
+ return !my_time_compare(ta, tb) &&
+ (!binary_cmp ||
+ a->get_type_all_attributes_from_const()->decimals ==
+ b->get_type_all_attributes_from_const()->decimals);
+}
+
+/***************************************************************************/
+
+const Type_handler *
+Type_handler_hex_hybrid::cast_to_int_type_handler() const
+{
+ return &type_handler_longlong;
+}
+
+
+const Type_handler *
+Type_handler_hex_hybrid::type_handler_for_system_time() const
+{
+ return &type_handler_longlong;
+}
+
+
+/***************************************************************************/
+
+bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Type_handler_int_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_int();
+ longlong value1= b->val_int();
+ return !a->null_value && !b->null_value && value0 == value1 &&
+ (value0 >= 0 || a->unsigned_flag == b->unsigned_flag);
+}
+
+
+bool Type_handler_real_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ double value0= a->val_real();
+ double value1= b->val_real();
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_time_common::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_time_packed();
+ longlong value1= b->val_time_packed();
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_temporal_with_date::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ longlong value0= a->val_datetime_packed();
+ longlong value1= b->val_datetime_packed();
+ return !a->null_value && !b->null_value && value0 == value1;
+}
+
+
+bool Type_handler_string_result::Item_eq_value(THD *thd,
+ const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+{
+ String *va, *vb;
+ StringBuffer<128> cmp_value1, cmp_value2;
+ return (va= a->val_str(&cmp_value1)) &&
+ (vb= b->val_str(&cmp_value2)) &&
+ va->eq(vb, attr->compare_collation());
+}
+
+
+/***************************************************************************/
+
+void Type_handler_var_string::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ // Change old VARCHAR to new VARCHAR
+ c->set_handler(&type_handler_varchar);
+}
+
+
+void Type_handler_time_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_time2);
+ else
+ c->set_handler(&type_handler_time);
+}
+
+
+void Type_handler_datetime_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_datetime2);
+ else
+ c->set_handler(&type_handler_datetime);
+}
+
+
+void Type_handler_timestamp_common::
+ Column_definition_implicit_upgrade(Column_definition *c) const
+{
+ if (opt_mysql56_temporal_format)
+ c->set_handler(&type_handler_timestamp2);
+ else
+ c->set_handler(&type_handler_timestamp);
+}
+
+
+/***************************************************************************/
+
+
+int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
+ field->get_date(&field_time, TIME_INVALID_DATES);
+ item->get_date(&item_time, TIME_INVALID_DATES);
+ if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
+ time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
+ return 1;
+ return my_time_compare(&field_time, item_time_cmp);
+}
+
+
+int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ MYSQL_TIME field_time, item_time;
+ field->get_time(&field_time);
+ item->get_time(&item_time);
+ return my_time_compare(&field_time, &item_time);
+}
+
+
+int Type_handler_string_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ StringBuffer<MAX_FIELD_WIDTH> item_tmp;
+ StringBuffer<MAX_FIELD_WIDTH> field_tmp;
+ String *item_result= item->val_str(&item_tmp);
+ /*
+ Some implementations of Item::val_str(String*) actually modify
+ the field Item::null_value, hence we can't check it earlier.
+ */
+ if (item->null_value)
+ return 0;
+ String *field_result= field->val_str(&field_tmp);
+ return sortcmp(field_result, item_result, field->charset());
+}
+
+
+int Type_handler_int_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ DBUG_ASSERT(0); // Not used yet
+ return 0;
+}
+
+
+int Type_handler_real_result::stored_field_cmp_to_item(THD *thd,
+ Field *field,
+ Item *item) const
+{
+ /*
+ The patch for Bug#13463415 started using this function for comparing
+ BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
+ Prefixing the auto variables with volatile fixes the problem....
+ */
+ volatile double result= item->val_real();
+ if (item->null_value)
+ return 0;
+ volatile double field_result= field->val_real();
+ if (field_result < result)
+ return -1;
+ else if (field_result > result)
+ return 1;
+ return 0;
+}
+
+
+/***************************************************************************/
+
+
+static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
+{
+ return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0;
+}
+
+
+static void literal_warn(THD *thd, const Item *item,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ const MYSQL_TIME *ltime,
+ const MYSQL_TIME_STATUS *st,
+ const char *typestr, bool send_error)
+{
+ if (likely(item))
+ {
+ if (st->warnings) // e.g. a note on nanosecond truncation
+ {
+ ErrConvString err(str, length, cs);
+ make_truncated_value_warning(thd,
+ Sql_condition::time_warn_level(st->warnings),
+ &err, ltime->time_type, 0);
+ }
+ }
+ else if (send_error)
+ {
+ ErrConvString err(str, length, cs);
+ my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr());
+ }
+}
+
+
+Item_literal *
+Type_handler_date_common::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ MYSQL_TIME_STATUS st;
+ MYSQL_TIME ltime;
+ Item_literal *item= NULL;
+ sql_mode_t flags= sql_mode_for_dates(thd);
+ if (!str_to_datetime(cs, str, length, &ltime, flags, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_DATE && !st.warnings)
+ item= new (thd->mem_root) Item_date_literal(thd, &ltime);
+ literal_warn(thd, item, str, length, cs, &ltime, &st, "DATE", send_error);
+ return item;
+}
+
+
+Item_literal *
+Type_handler_temporal_with_date::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ MYSQL_TIME_STATUS st;
+ MYSQL_TIME ltime;
+ Item_literal *item= NULL;
+ sql_mode_t flags= sql_mode_for_dates(thd);
+ if (!str_to_datetime(cs, str, length, &ltime, flags, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_DATETIME &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_datetime_literal(thd, &ltime, st.precision);
+ literal_warn(thd, item, str, length, cs, &ltime, &st, "DATETIME", send_error);
+ return item;
+}
+
+
+Item_literal *
+Type_handler_time_common::create_literal_item(THD *thd,
+ const char *str,
+ size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+{
+ MYSQL_TIME_STATUS st;
+ MYSQL_TIME ltime;
+ Item_literal *item= NULL;
+ if (!str_to_time(cs, str, length, &ltime, 0, &st) &&
+ ltime.time_type == MYSQL_TIMESTAMP_TIME &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_time_literal(thd, &ltime, st.precision);
+ literal_warn(thd, item, str, length, cs, &ltime, &st, "TIME", send_error);
+ return item;
+}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 1ddcef2da61..40433fdaabd 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -28,7 +28,10 @@
class Field;
class Column_definition;
+class Column_definition_attributes;
class Item;
+class Item_const;
+class Item_literal;
class Item_param;
class Item_cache;
class Item_func_or_sum;
@@ -74,6 +77,438 @@ struct TABLE;
struct SORT_FIELD_ATTR;
class Vers_history_point;
+#define my_charset_numeric my_charset_latin1
+
+enum scalar_comparison_op
+{
+ SCALAR_CMP_EQ,
+ SCALAR_CMP_EQUAL,
+ SCALAR_CMP_LT,
+ SCALAR_CMP_LE,
+ SCALAR_CMP_GE,
+ SCALAR_CMP_GT
+};
+
+
+class Dec_ptr
+{
+protected:
+ my_decimal *m_ptr;
+ Dec_ptr() { }
+public:
+ bool is_null() const { return m_ptr == NULL; }
+ const my_decimal *ptr() const { return m_ptr; }
+ const my_decimal *ptr_or(const my_decimal *def) const
+ {
+ return m_ptr ? m_ptr : def;
+ }
+ my_decimal *to_decimal(my_decimal *to) const
+ {
+ if (!m_ptr)
+ return NULL;
+ *to= *m_ptr;
+ return to;
+ }
+ double to_double() const { return m_ptr ? m_ptr->to_double() : 0.0; }
+ longlong to_longlong(bool unsigned_flag)
+ { return m_ptr ? m_ptr->to_longlong(unsigned_flag) : 0; }
+ bool to_bool() const { return m_ptr ? m_ptr->to_bool() : false; }
+ bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const char *field_name)
+ {
+ return m_ptr ? m_ptr->to_datetime_with_warn(to, fuzzydate, field_name) :
+ true;
+ }
+ bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate, Item *item);
+ String *to_string(String *to) const
+ {
+ return m_ptr ? m_ptr->to_string(to) : NULL;
+ }
+ String *to_string(String *to, uint prec, uint dec, char filler)
+ {
+ return m_ptr ? m_ptr->to_string(to, prec, dec, filler) : NULL;
+ }
+ int to_binary(uchar *bin, int prec, int scale) const
+ {
+ return (m_ptr ? m_ptr : &decimal_zero)->to_binary(bin, prec, scale);
+ }
+ int cmp(const my_decimal *dec) const
+ {
+ DBUG_ASSERT(m_ptr);
+ DBUG_ASSERT(dec);
+ return m_ptr->cmp(dec);
+ }
+ int cmp(const Dec_ptr &other) const
+ {
+ return cmp(other.m_ptr);
+ }
+};
+
+
+// A helper class to handle results of val_decimal(), date_op(), etc.
+class Dec_ptr_and_buffer: public Dec_ptr
+{
+protected:
+ my_decimal m_buffer;
+public:
+ int round_to(my_decimal *to, uint scale, decimal_round_mode mode)
+ {
+ DBUG_ASSERT(m_ptr);
+ return m_ptr->round_to(to, scale, mode);
+ }
+ int round_self(uint scale, decimal_round_mode mode)
+ {
+ return round_to(&m_buffer, scale, mode);
+ }
+ String *to_string_round(String *to, uint dec)
+ {
+ /*
+ decimal_round() allows from==to
+ So it's save even if m_ptr points to m_buffer before this call:
+ */
+ return m_ptr ? m_ptr->to_string_round(to, dec, &m_buffer) : NULL;
+ }
+};
+
+
+// A helper class to handle val_decimal() results.
+class VDec: public Dec_ptr_and_buffer
+{
+public:
+ VDec(): Dec_ptr_and_buffer() { }
+ VDec(Item *item);
+ void set(Item *a);
+};
+
+
+// A helper class to handler decimal_op() results.
+class VDec_op: public Dec_ptr_and_buffer
+{
+public:
+ VDec_op(Item_func_hybrid_field_type *item);
+};
+
+
+/*
+ Get and cache val_decimal() values for two items.
+ If the first value appears to be NULL, the second value is not evaluated.
+*/
+class VDec2_lazy
+{
+public:
+ VDec m_a;
+ VDec m_b;
+ VDec2_lazy(Item *a, Item *b) :m_a(a)
+ {
+ if (!m_a.is_null())
+ m_b.set(b);
+ }
+ bool has_null() const
+ {
+ return m_a.is_null() || m_b.is_null();
+ }
+};
+
+
+/**
+ Class Sec6 represents a fixed point value with 6 fractional digits.
+ Used e.g. to convert double and my_decimal values to TIME/DATETIME.
+*/
+
+class Sec6
+{
+protected:
+ ulonglong m_sec; // The integer part, between 0 and LONGLONG_MAX
+ ulong m_usec; // The fractional part, between 0 and 999999
+ bool m_neg; // false if positive, true of negative
+ bool m_truncated; // Indicates if the constructor truncated the value
+ void make_from_decimal(const my_decimal *d);
+ void make_from_double(double d);
+ void make_from_int(longlong nr, bool unsigned_val)
+ {
+ m_neg= nr < 0 && !unsigned_val;
+ m_sec= m_neg ? (ulonglong) -nr : (ulonglong) nr;
+ m_usec= 0;
+ m_truncated= false;
+ }
+ void reset()
+ {
+ m_sec= m_usec= m_neg= m_truncated= 0;
+ }
+ Sec6() { }
+public:
+ Sec6(bool neg, ulonglong nr, ulong frac)
+ :m_sec(nr), m_usec(frac), m_neg(neg), m_truncated(false)
+ { }
+ Sec6(double nr)
+ {
+ make_from_double(nr);
+ }
+ Sec6(const my_decimal *d)
+ {
+ make_from_decimal(d);
+ }
+ Sec6(longlong nr, bool unsigned_val)
+ {
+ make_from_int(nr, unsigned_val);
+ }
+ bool neg() const { return m_neg; }
+ bool truncated() const { return m_truncated; }
+ ulonglong sec() const { return m_sec; }
+ long usec() const { return m_usec; }
+ /**
+ Converts Sec6 to MYSQL_TIME
+
+ @param ltime converted value will be written here
+ @param fuzzydate conversion flags (TIME_INVALID_DATE, etc)
+ @param str original number, as an ErrConv. For the warning
+ @param field_name field name or NULL if not a field. For the warning
+ @returns false for success, true for a failure
+ */
+ bool convert_to_mysql_time(MYSQL_TIME *ltime, ulonglong fuzzydate,
+ const ErrConv *str, const char *field_name) const;
+
+ // Convert a number in format hhhmmss.ff to TIME'hhh:mm:ss.ff'
+ bool to_time(MYSQL_TIME *to, int *warn) const
+ {
+ return number_to_time(m_neg, m_sec, m_usec, to, warn);
+ }
+ bool to_time_with_warn(MYSQL_TIME *to, const ErrConv *str,
+ const char *field_name) const;
+ /*
+ Convert a number in format YYYYMMDDhhmmss.ff to
+ TIMESTAMP'YYYY-MM-DD hh:mm:ss.ff'
+ */
+ bool to_datetime(MYSQL_TIME *to, ulonglong flags, int *warn) const
+ {
+ if (m_neg)
+ {
+ *warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ return true;
+ }
+ return number_to_datetime(m_sec, m_usec, to, flags, warn) == -1;
+ }
+ bool to_datetime_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const ErrConv *str, const char *field_name) const;
+ // Convert elapsed seconds to TIME
+ bool sec_to_time(MYSQL_TIME *ltime, uint dec) const
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ ltime->neg= m_neg;
+ if (m_sec > TIME_MAX_VALUE_SECONDS)
+ {
+ // use check_time_range() to set ltime to the max value depending on dec
+ int unused;
+ ltime->hour= TIME_MAX_HOUR + 1;
+ check_time_range(ltime, dec, &unused);
+ return true;
+ }
+ DBUG_ASSERT(usec() <= TIME_MAX_SECOND_PART);
+ ltime->hour= (uint) (m_sec / 3600);
+ ltime->minute= (uint) (m_sec % 3600) / 60;
+ ltime->second= (uint) m_sec % 60;
+ ltime->second_part= m_usec;
+ return false;
+ }
+ size_t to_string(char *to, size_t nbytes) const
+ {
+ return m_usec ?
+ my_snprintf(to, nbytes, "%s%llu.%06lu",
+ m_neg ? "-" : "", m_sec, (uint) m_usec) :
+ my_snprintf(to, nbytes, "%s%llu", m_neg ? "-" : "", m_sec);
+ }
+ void make_truncated_warning(THD *thd, const char *type_str) const;
+};
+
+
+class VSec6: public Sec6
+{
+ bool m_is_null;
+public:
+ VSec6(Item *item, const char *type_str, ulonglong limit);
+ bool is_null() const { return m_is_null; }
+};
+
+
+/*
+ A heler class to perform additive operations between
+ two MYSQL_TIME structures and return the result as a
+ combination of seconds, microseconds and sign.
+*/
+class Sec6_add
+{
+ ulonglong m_sec; // number of seconds
+ ulong m_usec; // number of microseconds
+ bool m_neg; // false if positive, true if negative
+ bool m_error; // false if the value is OK, true otherwise
+ void to_hh24mmssff(MYSQL_TIME *ltime, timestamp_type tstype) const
+ {
+ bzero(ltime, sizeof(*ltime));
+ ltime->neg= m_neg;
+ calc_time_from_sec(ltime, (ulong) (m_sec % SECONDS_IN_24H), m_usec);
+ ltime->time_type= tstype;
+ }
+public:
+ /*
+ @param ltime1 - the first value to add (must be a valid DATE,TIME,DATETIME)
+ @param ltime2 - the second value to add (must be a valid TIME)
+ @param sign - the sign of the operation
+ (+1 for addition, -1 for subtraction)
+ */
+ Sec6_add(const MYSQL_TIME *ltime1, const MYSQL_TIME *ltime2, int sign)
+ {
+ DBUG_ASSERT(sign == -1 || sign == 1);
+ DBUG_ASSERT(!ltime1->neg || ltime1->time_type == MYSQL_TIMESTAMP_TIME);
+ if (!(m_error= (ltime2->time_type != MYSQL_TIMESTAMP_TIME)))
+ {
+ if (ltime1->neg != ltime2->neg)
+ sign= -sign;
+ m_neg= calc_time_diff(ltime1, ltime2, -sign, &m_sec, &m_usec);
+ if (ltime1->neg && (m_sec || m_usec))
+ m_neg= !m_neg; // Swap sign
+ }
+ }
+ bool to_time(MYSQL_TIME *ltime, uint decimals) const
+ {
+ if (m_error)
+ return true;
+ to_hh24mmssff(ltime, MYSQL_TIMESTAMP_TIME);
+ ltime->hour+= to_days_abs() * 24;
+ return adjust_time_range_with_warn(ltime, decimals);
+ }
+ bool to_datetime(MYSQL_TIME *ltime) const
+ {
+ if (m_error || m_neg)
+ return true;
+ to_hh24mmssff(ltime, MYSQL_TIMESTAMP_DATETIME);
+ return get_date_from_daynr(to_days_abs(),
+ &ltime->year, &ltime->month, &ltime->day) ||
+ !ltime->day;
+ }
+ long to_days_abs() const { return (long) (m_sec / SECONDS_IN_24H); }
+};
+
+
+class Year
+{
+protected:
+ uint m_year;
+ bool m_truncated;
+ bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const char *field_name) const
+ {
+ longlong value= m_year * 10000; // Make it YYYYMMDD
+ const ErrConvInteger str(value, true);
+ Sec6 sec(false, value, 0);
+ return sec.convert_to_mysql_time(to, fuzzydate, &str, field_name);
+ }
+ uint year_precision(const Item *item) const;
+public:
+ Year(): m_year(0), m_truncated(false) { }
+ Year(longlong value, bool unsigned_flag, uint length);
+ uint year() const { return m_year; }
+ bool truncated() const { return m_truncated; }
+};
+
+
+class Year_null: public Year
+{
+protected:
+ bool m_is_null;
+public:
+ Year_null(const Year &other, bool is_null)
+ :Year(is_null ? Year() : other),
+ m_is_null(is_null)
+ { }
+ bool is_null() const { return m_is_null; }
+ bool to_mysql_time_with_warn(MYSQL_TIME *to, ulonglong fuzzydate,
+ const char *field_name) const
+ {
+ return m_is_null ? true :
+ Year::to_mysql_time_with_warn(to, fuzzydate, field_name);
+ }
+};
+
+
+class VYear: public Year_null
+{
+public:
+ VYear(Item *item);
+};
+
+
+class VYear_op: public Year_null
+{
+public:
+ VYear_op(Item_func_hybrid_field_type *item);
+};
+
+
+class Temporal: protected MYSQL_TIME
+{
+protected:
+ bool is_valid_temporal() const
+ {
+ DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
+ return time_type != MYSQL_TIMESTAMP_NONE;
+ }
+ my_decimal *bad_to_decimal(my_decimal *to) const;
+ my_decimal *to_decimal(my_decimal *to) const;
+ static double to_double(bool negate, ulonglong num, ulong frac)
+ {
+ double d= (double) num + frac / (double) TIME_SECOND_PART_FACTOR;
+ return negate ? -d : d;
+ }
+ longlong to_packed() const { return ::pack_time(this); }
+ void make_from_out_of_range(int *warn)
+ {
+ *warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+public:
+ long fraction_remainder(uint dec) const
+ {
+ return my_time_fraction_remainder(second_part, dec);
+ }
+};
+
+
+/*
+ Use this class when you need to get a MYSQL_TIME from an Item
+ using Item's native timestamp type, without automatic timestamp
+ type conversion.
+*/
+class Temporal_hybrid: public Temporal
+{
+public:
+ Temporal_hybrid(THD *thd, Item *item);
+ Temporal_hybrid(Item *item) { *this= Temporal_hybrid(current_thd, item); }
+ longlong to_longlong() const
+ {
+ if (!is_valid_temporal())
+ return 0;
+ ulonglong v= TIME_to_ulonglong(this);
+ return neg ? -(longlong) v : (longlong) v;
+ }
+ double to_double() const
+ {
+ return is_valid_temporal() ? TIME_to_double(this) : 0;
+ }
+ my_decimal *to_decimal(my_decimal *to)
+ {
+ return is_valid_temporal() ? Temporal::to_decimal(to) : bad_to_decimal(to);
+ }
+ String *to_string(String *str, uint dec) const
+ {
+ if (!is_valid_temporal())
+ return NULL;
+ str->set_charset(&my_charset_numeric);
+ if (!str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ str->length(my_TIME_to_str(this, const_cast<char*>(str->ptr()), dec));
+ return str;
+ }
+};
+
/**
Class Time is designed to store valid TIME values.
@@ -93,13 +528,15 @@ class Vers_history_point;
Time derives from MYSQL_TIME privately to make sure it is accessed
externally only in the valid state.
*/
-class Time: private MYSQL_TIME
+class Time: public Temporal
{
public:
enum datetime_to_time_mode_t
{
DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS,
- DATETIME_TO_TIME_YYYYMMDD_TRUNCATE
+ DATETIME_TO_TIME_YYYYMMDD_TRUNCATE,
+ DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY,
+ DATETIME_TO_TIME_MINUS_CURRENT_DATE
};
class Options
{
@@ -148,41 +585,77 @@ private:
second <= TIME_MAX_SECOND &&
second_part <= TIME_MAX_SECOND_PART;
}
-
+ void hhmmssff_copy(const MYSQL_TIME *from)
+ {
+ hour= from->hour;
+ minute= from->minute;
+ second= from->second;
+ second_part= from->second_part;
+ }
+ void datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(int *warn,
+ uint from_year,
+ uint from_month,
+ uint from_day)
+ {
+ if (from_year != 0 || from_month != 0)
+ *warn|= MYSQL_TIME_NOTE_TRUNCATED;
+ else
+ hour+= from_day * 24;
+ }
+ /*
+ The result is calculated effectively similar to:
+ TIMEDIFF(dt, CAST(CURRENT_DATE AS DATETIME))
+ If the difference does not fit to the supported TIME range, it's truncated.
+ */
+ void datetime_to_time_minus_current_date(THD *thd)
+ {
+ MYSQL_TIME current_date, tmp;
+ set_current_date(thd, &current_date);
+ calc_time_diff(this, &current_date, 1, &tmp, 0);
+ static_cast<MYSQL_TIME*>(this)[0]= tmp;
+ int warnings= 0;
+ (void) check_time_range(this, TIME_SECOND_PART_DIGITS, &warnings);
+ DBUG_ASSERT(is_valid_time());
+ }
/*
Convert a valid DATE or DATETIME to TIME.
Before this call, "this" must be a valid DATE or DATETIME value,
- e.g. returned from Item::get_date().
+ e.g. returned from Item::get_date(), str_to_time(), number_to_time().
After this call, "this" is a valid TIME value.
*/
- void valid_datetime_to_valid_time(const Options opt)
+ void valid_datetime_to_valid_time(int *warn, const Options opt)
{
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATE ||
time_type == MYSQL_TIMESTAMP_DATETIME);
/*
- Make sure that day and hour are valid, so the result hour value
+ We're dealing with a DATE or DATETIME returned from
+ str_to_time(), number_to_time() or unpack_time().
+ Do some asserts to make sure the result hour value
after mixing days to hours does not go out of the valid TIME range.
+ The maximum hour value after mixing days will be 31*24+23=767,
+ which is within the supported TIME range.
+ Thus no adjust_time_range_or_invalidate() is needed here.
*/
DBUG_ASSERT(day < 32);
DBUG_ASSERT(hour < 24);
- if (year == 0 && month == 0 &&
- opt.datetime_to_time_mode() ==
- DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
+ if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_MINUS_CURRENT_DATE)
{
- /*
- The maximum hour value after mixing days will be 31*24+23=767,
- which is within the supported TIME range.
- Thus no adjust_time_range_or_invalidate() is needed here.
- */
- hour+= day * 24;
+ datetime_to_time_minus_current_date(current_thd);
+ }
+ else
+ {
+ if (opt.datetime_to_time_mode() ==
+ DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
+ datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, year, month, day);
+ year= month= day= 0;
+ time_type= MYSQL_TIMESTAMP_TIME;
}
- year= month= day= 0;
- time_type= MYSQL_TIMESTAMP_TIME;
DBUG_ASSERT(is_valid_time_slow());
}
/**
Convert valid DATE/DATETIME to valid TIME if needed.
This method is called after Item::get_date(),
+ str_to_time(), number_to_time().
which can return only valid TIME/DATE/DATETIME values.
Before this call, "this" is:
- either a valid TIME/DATE/DATETIME value
@@ -192,12 +665,17 @@ private:
- either a valid TIME (within the supported TIME range),
- or MYSQL_TIMESTAMP_NONE
*/
- void valid_MYSQL_TIME_to_valid_value(const Options opt)
+ void valid_MYSQL_TIME_to_valid_value(int *warn, const Options opt)
{
switch (time_type) {
case MYSQL_TIMESTAMP_DATE:
case MYSQL_TIMESTAMP_DATETIME:
- valid_datetime_to_valid_time(opt);
+ if (opt.datetime_to_time_mode() ==
+ DATETIME_TO_TIME_YYYYMMDD_00000000_ONLY &&
+ (year || month || day))
+ make_from_out_of_range(warn);
+ else
+ valid_datetime_to_valid_time(warn, opt);
break;
case MYSQL_TIMESTAMP_NONE:
break;
@@ -209,11 +687,73 @@ private:
break;
}
}
- void make_from_item(class Item *item, const Options opt);
+
+ /*
+ This method is called after number_to_time() and str_to_time(),
+ which can return DATE or DATETIME values. Convert to TIME if needed.
+ We trust that xxx_to_time() returns a valid TIME/DATE/DATETIME value,
+ so here we need to do only simple validation.
+ */
+ void xxx_to_time_result_to_valid_value(int *warn, const Options opt)
+ {
+ // str_to_time(), number_to_time() never return MYSQL_TIMESTAMP_ERROR
+ DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
+ valid_MYSQL_TIME_to_valid_value(warn, opt);
+ }
+ void adjust_time_range_or_invalidate(int *warn)
+ {
+ if (check_time_range(this, TIME_SECOND_PART_DIGITS, warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ void make_from_datetime_move_day_to_hour(int *warn, const MYSQL_TIME *from);
+ void make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
+ long curdays);
+ void make_from_time(int *warn, const MYSQL_TIME *from);
+ void make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays);
+ void make_from_item(int *warn, Item *item, const Options opt);
public:
+ /*
+ All constructors that accept an "int *warn" parameter initialize *warn.
+ The old value gets lost.
+ */
Time() { time_type= MYSQL_TIMESTAMP_NONE; }
- Time(Item *item) { make_from_item(item, Options()); }
- Time(Item *item, const Options opt) { make_from_item(item, opt); }
+ Time(Item *item)
+ {
+ int warn;
+ make_from_item(&warn, item, Options());
+ }
+ Time(Item *item, const Options opt)
+ {
+ int warn;
+ make_from_item(&warn, item, opt);
+ }
+ Time(int *warn, const MYSQL_TIME *from, long curdays);
+ Time(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
+ const Options opt)
+ {
+ MYSQL_TIME_STATUS status;
+ if (str_to_time(cs, str, len, this, opt.get_date_flags(), &status))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ // The below call will optionally add notes to already collected warnings:
+ xxx_to_time_result_to_valid_value(&status.warnings, opt);
+ *warn= status.warnings;
+ }
+ Time(int *warn, const Sec6 &nr, const Options opt)
+ {
+ if (nr.to_time(this, warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ xxx_to_time_result_to_valid_value(warn, opt);
+ }
+ Time(int *warn, double nr)
+ :Temporal(Time(warn, Sec6(nr), Options()))
+ { }
+ Time(int *warn, longlong nr, bool unsigned_val)
+ :Temporal(Time(warn, Sec6(nr, unsigned_val), Options()))
+ { }
+ Time(int *warn, const my_decimal *d)
+ :Temporal(Time(warn, Sec6(d), Options()))
+ { }
static sql_mode_t flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES; }
static sql_mode_t comparison_flags_for_get_date()
@@ -243,8 +783,8 @@ public:
{
DBUG_ASSERT(is_valid_time_slow());
DBUG_ASSERT(other->is_valid_time_slow());
- longlong p0= pack_time(this);
- longlong p1= pack_time(other);
+ longlong p0= to_packed();
+ longlong p1= other->to_packed();
if (p0 < p1)
return -1;
if (p0 > p1)
@@ -260,6 +800,41 @@ public:
{
return neg ? -to_seconds_abs() : to_seconds_abs();
}
+ longlong to_longlong() const
+ {
+ if (!is_valid_time())
+ return 0;
+ ulonglong v= TIME_to_ulonglong_time(this);
+ return neg ? -(longlong) v : (longlong) v;
+ }
+ double to_double() const
+ {
+ return !is_valid_time() ? 0 :
+ Temporal::to_double(neg, TIME_to_ulonglong_time(this), second_part);
+ }
+ String *to_string(String *str, uint dec) const
+ {
+ if (!is_valid_time())
+ return NULL;
+ str->set_charset(&my_charset_numeric);
+ if (!str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ str->length(my_time_to_str(this, const_cast<char*>(str->ptr()), dec));
+ return str;
+ }
+ my_decimal *to_decimal(my_decimal *to)
+ {
+ return is_valid_time() ? Temporal::to_decimal(to) : bad_to_decimal(to);
+ }
+ longlong to_packed() const
+ {
+ return is_valid_time() ? Temporal::to_packed() : 0;
+ }
+ Time trunc(uint dec) const
+ {
+ Time tm(*this);
+ my_time_trunc(&tm, dec);
+ return tm;
+ }
};
@@ -286,14 +861,46 @@ public:
it is accessed externally only in the valid state.
*/
-class Temporal_with_date: protected MYSQL_TIME
+class Temporal_with_date: public Temporal
{
protected:
+ void check_date_or_invalidate(int *warn, sql_mode_t flags);
void make_from_item(THD *thd, Item *item, sql_mode_t flags);
+ void make_from_item(THD *thd, Item *item);
+ Temporal_with_date()
+ {
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
Temporal_with_date(THD *thd, Item *item, sql_mode_t flags)
{
make_from_item(thd, item, flags);
}
+ Temporal_with_date(THD *thd, Item *item)
+ {
+ make_from_item(thd, item);
+ }
+ Temporal_with_date(int *warn, const Sec6 &nr, sql_mode_t flags)
+ {
+ DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
+ if (nr.to_datetime(this, flags, warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ Temporal_with_date(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
+ sql_mode_t flags)
+ {
+ DBUG_ASSERT((flags & TIME_TIME_ONLY) == 0);
+ MYSQL_TIME_STATUS status;
+ if (str_to_datetime(cs, str, len, this, flags, &status))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ *warn= status.warnings;
+ }
+public:
+ bool check_date_with_warn(ulonglong flags)
+ {
+ return ::check_date_with_warn(this, flags, MYSQL_TIMESTAMP_ERROR);
+ }
+ static sql_mode_t comparison_flags_for_get_date()
+ { return TIME_INVALID_DATES | TIME_FUZZY_DATES; }
};
@@ -325,6 +932,20 @@ public:
datetime_to_date(this);
DBUG_ASSERT(is_valid_value_slow());
}
+ Date(THD *thd, Item *item)
+ :Temporal_with_date(thd, item)
+ {
+ if (time_type == MYSQL_TIMESTAMP_DATETIME)
+ datetime_to_date(this);
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Date(Item *item)
+ :Temporal_with_date(current_thd, item)
+ {
+ if (time_type == MYSQL_TIMESTAMP_DATETIME)
+ datetime_to_date(this);
+ DBUG_ASSERT(is_valid_value_slow());
+ }
Date(const Temporal_with_date *d)
:Temporal_with_date(*d)
{
@@ -341,6 +962,38 @@ public:
DBUG_ASSERT(is_valid_date_slow());
return this;
}
+ bool copy_to_mysql_time(MYSQL_TIME *ltime) const
+ {
+ if (time_type == MYSQL_TIMESTAMP_NONE)
+ {
+ ltime->time_type= MYSQL_TIMESTAMP_NONE;
+ return true;
+ }
+ DBUG_ASSERT(is_valid_date_slow());
+ *ltime= *this;
+ return false;
+ }
+ longlong to_longlong() const
+ {
+ return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL;
+ }
+ double to_double() const
+ {
+ return (double) to_longlong();
+ }
+ String *to_string(String *str) const
+ {
+ if (!is_valid_date())
+ return NULL;
+ str->set_charset(&my_charset_numeric);
+ if (!str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ str->length(my_date_to_str(this, const_cast<char*>(str->ptr())));
+ return str;
+ }
+ my_decimal *to_decimal(my_decimal *to)
+ {
+ return is_valid_date() ? Temporal::to_decimal(to) : bad_to_decimal(to);
+ }
};
@@ -365,14 +1018,72 @@ class Datetime: public Temporal_with_date
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME);
return !check_datetime_range(this);
}
+ void date_to_datetime_if_needed()
+ {
+ if (time_type == MYSQL_TIMESTAMP_DATE)
+ date_to_datetime(this);
+ }
+ void make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
+ sql_mode_t flags);
+ void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ sql_mode_t flags);
public:
Datetime(THD *thd, Item *item, sql_mode_t flags)
:Temporal_with_date(thd, item, flags)
{
- if (time_type == MYSQL_TIMESTAMP_DATE)
- date_to_datetime(this);
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(THD *thd, Item *item)
+ :Temporal_with_date(thd, item)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(Item *item)
+ :Temporal_with_date(current_thd, item)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(THD *thd, int *warn, const MYSQL_TIME *from, sql_mode_t flags);
+ Datetime()
+ {
+ set_zero_time(this, MYSQL_TIMESTAMP_DATETIME);
+ }
+ Datetime(int *warn, const char *str, size_t len, CHARSET_INFO *cs,
+ sql_mode_t flags)
+ :Temporal_with_date(warn, str, len, cs, flags)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(int *warn, double nr, sql_mode_t flags)
+ :Temporal_with_date(warn, Sec6(nr), flags)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(int *warn, const my_decimal *d, sql_mode_t flags)
+ :Temporal_with_date(warn, Sec6(d), flags)
+ {
+ date_to_datetime_if_needed();
DBUG_ASSERT(is_valid_value_slow());
}
+ /*
+ Create a Datime object from a longlong number.
+ Note, unlike in Time(), we don't need an "unsigned_val" here,
+ as it's not important if overflow happened because
+ of a negative number, or because of a huge positive number.
+ */
+ Datetime(int *warn, longlong sec, ulong usec, sql_mode_t flags)
+ :Temporal_with_date(warn, Sec6(false, (ulonglong) sec, usec), flags)
+ {
+ Sec6 nr(false, (ulonglong) sec, usec);
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+
bool is_valid_datetime() const
{
/*
@@ -418,8 +1129,42 @@ public:
ltime->time_type= type;
return false;
}
+ longlong to_longlong() const
+ {
+ return is_valid_datetime() ?
+ (longlong) TIME_to_ulonglong_datetime(this) : 0LL;
+ }
+ double to_double() const
+ {
+ return !is_valid_datetime() ? 0 :
+ Temporal::to_double(neg, TIME_to_ulonglong_datetime(this), second_part);
+ }
+ String *to_string(String *str, uint dec) const
+ {
+ if (!is_valid_datetime())
+ return NULL;
+ str->set_charset(&my_charset_numeric);
+ if (!str->alloc(MAX_DATE_STRING_REP_LENGTH))
+ str->length(my_datetime_to_str(this, const_cast<char*>(str->ptr()), dec));
+ return str;
+ }
+ my_decimal *to_decimal(my_decimal *to)
+ {
+ return is_valid_datetime() ? Temporal::to_decimal(to) : bad_to_decimal(to);
+ }
+ longlong to_packed() const
+ {
+ return is_valid_datetime() ? Temporal::to_packed() : 0;
+ }
+ Datetime trunc(uint dec) const
+ {
+ Datetime tm(*this);
+ my_time_trunc(&tm, dec);
+ return tm;
+ }
};
+
/*
Flags for collation aggregation modes, used in TDCollation::agg():
@@ -445,7 +1190,6 @@ public:
#define MY_COLL_CMP_CONV (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE)
-#define my_charset_numeric my_charset_latin1
#define MY_REPERTOIRE_NUMERIC MY_REPERTOIRE_ASCII
@@ -834,6 +1578,14 @@ public:
};
+class Type_cmp_attributes
+{
+public:
+ virtual ~Type_cmp_attributes() { }
+ virtual CHARSET_INFO *compare_collation() const= 0;
+};
+
+
class Type_cast_attributes
{
CHARSET_INFO *m_charset;
@@ -886,28 +1638,67 @@ public:
};
-class Record_addr
+class Bit_addr
{
-public:
- uchar *ptr; // Position to field in record
/**
- Byte where the @c NULL bit is stored inside a record. If this Field is a
- @c NOT @c NULL field, this member is @c NULL.
+ Byte where the bit is stored inside a record.
+ If the corresponding Field is a NOT NULL field, this member is NULL.
+ */
+ uchar *m_ptr;
+ /**
+ Offset of the bit inside m_ptr[0], in the range 0..7.
*/
- uchar *null_ptr;
- uchar null_bit; // Bit used to test null bit
+ uchar m_offs;
+public:
+ Bit_addr()
+ :m_ptr(NULL),
+ m_offs(0)
+ { }
+ Bit_addr(uchar *ptr, uchar offs)
+ :m_ptr(ptr), m_offs(offs)
+ {
+ DBUG_ASSERT(ptr || offs == 0);
+ DBUG_ASSERT(offs < 8);
+ }
+ Bit_addr(bool maybe_null)
+ :m_ptr(maybe_null ? (uchar *) "" : NULL),
+ m_offs(0)
+ { }
+ uchar *ptr() const { return m_ptr; }
+ uchar offs() const { return m_offs; }
+ uchar bit() const { return m_ptr ? ((uchar) 1) << m_offs : 0; }
+ void inc()
+ {
+ DBUG_ASSERT(m_ptr);
+ m_ptr+= (m_offs == 7);
+ m_offs= (m_offs + 1) & 7;
+ }
+};
+
+
+class Record_addr
+{
+ uchar *m_ptr; // Position of the field in the record
+ Bit_addr m_null; // Position and offset of the null bit
+public:
Record_addr(uchar *ptr_arg,
uchar *null_ptr_arg,
uchar null_bit_arg)
- :ptr(ptr_arg),
- null_ptr(null_ptr_arg),
- null_bit(null_bit_arg)
+ :m_ptr(ptr_arg),
+ m_null(null_ptr_arg, null_bit_arg)
+ { }
+ Record_addr(uchar *ptr, const Bit_addr &null)
+ :m_ptr(ptr),
+ m_null(null)
{ }
Record_addr(bool maybe_null)
- :ptr(NULL),
- null_ptr(maybe_null ? (uchar*) "" : 0),
- null_bit(0)
+ :m_ptr(NULL),
+ m_null(maybe_null)
{ }
+ uchar *ptr() const { return m_ptr; }
+ const Bit_addr &null() const { return m_null; }
+ uchar *null_ptr() const { return m_null.ptr(); }
+ uchar null_bit() const { return m_null.bit(); }
};
@@ -982,6 +1773,9 @@ public:
class Type_handler
{
protected:
+ static const Name m_version_default;
+ static const Name m_version_mysql56;
+ static const Name m_version_mariadb53;
String *print_item_value_csstr(THD *thd, Item *item, String *str) const;
String *print_item_value_temporal(THD *thd, Item *item, String *str,
const Name &type_name, String *buf) const;
@@ -1014,6 +1808,7 @@ protected:
enum_field_types type)
const;
public:
+ static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str);
static const Type_handler *blob_type_handler(uint max_octet_length);
static const Type_handler *string_type_handler(uint max_octet_length);
static const Type_handler *bit_and_int_mixture_handler(uint max_char_len);
@@ -1047,8 +1842,31 @@ public:
const Type_handler *h2);
virtual const Name name() const= 0;
+ virtual const Name version() const { return m_version_default; }
virtual enum_field_types field_type() const= 0;
virtual enum_field_types real_field_type() const { return field_type(); }
+ /**
+ Type code which is used for merging of traditional data types for result
+ (for UNION and for hybrid functions such as COALESCE).
+ Mapping can be done both ways: old->new, new->old, depending
+ on the particular data type implementation:
+ - type_handler_var_string (MySQL-4.1 old VARCHAR) is converted to
+ new VARCHAR before merging.
+ field_type_merge_rules[][] returns new VARCHAR.
+ - type_handler_newdate is converted to old DATE before merging.
+ field_type_merge_rules[][] returns NEWDATE.
+ - Temporal type_handler_xxx2 (new MySQL-5.6 types) are converted to
+ corresponding old type codes before merging (e.g. TIME2->TIME).
+ field_type_merge_rules[][] returns old type codes (e.g. TIME).
+ Then old types codes are supposed to convert to new type codes somehow,
+ but they do not. So UNION and COALESCE create old columns.
+ This is a bug and should be fixed eventually.
+ */
+ virtual enum_field_types traditional_merge_field_type() const
+ {
+ DBUG_ASSERT(is_traditional_type());
+ return field_type();
+ }
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
virtual enum_mysql_timestamp_type mysql_timestamp_type() const
@@ -1059,6 +1877,25 @@ public:
{
return false;
}
+ virtual bool is_order_clause_position_type() const
+ {
+ return false;
+ }
+ virtual bool is_limit_clause_valid_type() const
+ {
+ return false;
+ }
+ /*
+ Returns true if this data type supports a hack that
+ WHERE notnull_column IS NULL
+ finds zero values, e.g.:
+ WHERE date_notnull_column IS NULL ->
+ WHERE date_notnull_column = '0000-00-00'
+ */
+ virtual bool cond_notnull_field_isnull_to_field_eq_zero() const
+ {
+ return false;
+ }
/**
Check whether a field type can be partially indexed by a key.
@param type field type
@@ -1097,6 +1934,12 @@ public:
{
return this;
}
+ virtual const Type_handler *type_handler_for_system_time() const
+ {
+ return this;
+ }
+ virtual int
+ stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0;
virtual CHARSET_INFO *charset_for_protocol(const Item *item) const;
virtual const Type_handler*
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
@@ -1123,6 +1966,7 @@ public:
virtual bool can_return_text() const { return true; }
virtual bool can_return_date() const { return true; }
virtual bool can_return_time() const { return true; }
+ virtual bool is_bool_type() const { return false; }
virtual bool is_general_purpose_string_type() const { return false; }
virtual uint Item_time_precision(Item *item) const;
virtual uint Item_datetime_precision(Item *item) const;
@@ -1169,7 +2013,20 @@ public:
virtual Field *make_conversion_table_field(TABLE *TABLE,
uint metadata,
const Field *target) const= 0;
+ // Automatic upgrade, e.g. for ALTER TABLE t1 FORCE
+ virtual void Column_definition_implicit_upgrade(Column_definition *c) const
+ { }
+ // Fix attributes after the parser
virtual bool Column_definition_fix_attributes(Column_definition *c) const= 0;
+ /*
+ Fix attributes from an existing field. Used for:
+ - ALTER TABLE (for columns that do not change)
+ - DECLARE var TYPE OF t1.col1; (anchored SP variables)
+ */
+ virtual void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const
+ { }
virtual bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
@@ -1208,6 +2065,23 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ virtual Field *
+ make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const= 0;
+ virtual void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const;
+ virtual bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options) const;
+
virtual void make_sort_key(uchar *to, Item *item,
const SORT_FIELD_ATTR *sort_field,
Sort_param *param) const= 0;
@@ -1217,6 +2091,7 @@ public:
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 calc_pack_length(uint32 length) const= 0;
+ virtual void Item_update_null_value(Item *item) const= 0;
virtual bool Item_save_in_value(Item *item, st_value *value) const= 0;
virtual void Item_param_setup_conversion(THD *thd, Item_param *) const {}
virtual void Item_param_set_param_func(Item_param *param,
@@ -1295,6 +2170,32 @@ public:
Item *src,
const Item *cmp) const= 0;
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
+ /**
+ A builder for literals with data type name prefix, e.g.:
+ TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'.
+ @param thd The current thread
+ @param str Character literal
+ @param length Length of str
+ @param cs Character set of the string
+ @param send_error Whether to generate an error on failure
+
+ @retval A pointer to a new Item on success
+ NULL on error (wrong literal value, EOM)
+ */
+ virtual Item_literal *create_literal_item(THD *thd,
+ const char *str, size_t length,
+ CHARSET_INFO *cs,
+ bool send_error) const
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
+ Item_literal *create_literal_item(THD *thd, const String *str,
+ bool send_error) const
+ {
+ return create_literal_item(thd, str->ptr(), str->length(), str->charset(),
+ send_error);
+ }
virtual Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const
{
@@ -1302,6 +2203,13 @@ public:
return NULL;
}
virtual bool set_comparator_func(Arg_comparator *cmp) const= 0;
+ virtual bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const
+ {
+ return false;
+ }
+ virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const= 0;
virtual bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -1447,6 +2355,11 @@ public:
return ROW_RESULT;
}
const Type_handler *type_handler_for_comparison() const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const
{
@@ -1469,6 +2382,12 @@ public:
{
return false;
}
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const
+ {
+ DBUG_ASSERT(0);
+ }
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
@@ -1497,6 +2416,13 @@ public:
DBUG_ASSERT(0);
return NULL;
}
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void make_sort_key(uchar *to, Item *item,
const SORT_FIELD_ATTR *sort_field,
Sort_param *param) const
@@ -1518,6 +2444,8 @@ public:
DBUG_ASSERT(0);
return 0;
}
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const
{
DBUG_ASSERT(0);
@@ -1533,6 +2461,7 @@ public:
DBUG_ASSERT(0);
return true;
}
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
{
DBUG_ASSERT(0);
@@ -1764,6 +2693,10 @@ public:
Item_result cmp_type() const { return REAL_RESULT; }
virtual ~Type_handler_real_result() {}
const Type_handler *type_handler_for_comparison() const;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
@@ -1771,12 +2704,17 @@ public:
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
const st_value *value) const;
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
@@ -1837,6 +2775,11 @@ public:
Item_result cmp_type() const { return DECIMAL_RESULT; }
virtual ~Type_handler_decimal_result() {};
const Type_handler *type_handler_for_comparison() const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ {
+ VDec item_val(item);
+ return item_val.is_null() ? 0 : my_decimal(field).cmp(item_val.ptr());
+ }
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
@@ -1848,6 +2791,14 @@ public:
uint32 max_display_length(const Item *item) const;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const
+ {
+ VDec va(a), vb(b);
+ return va.ptr() && vb.ptr() && !va.cmp(vb);
+ }
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
void Item_param_set_param_func(Item_param *param,
@@ -1860,6 +2811,7 @@ public:
{
return Item_send_str(item, protocol, buf);
}
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
@@ -1873,10 +2825,19 @@ public:
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
- bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ bool Item_val_bool(Item *item) const
+ {
+ return VDec(item).to_bool();
+ }
+ bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ {
+ return VDec(item).to_datetime_with_warn(ltime, fuzzydate, item);
+ }
longlong Item_val_int_signed_typecast(Item *item) const;
- longlong Item_val_int_unsigned_typecast(Item *item) const;
+ longlong Item_val_int_unsigned_typecast(Item *item) const
+ {
+ return VDec(item).to_longlong(true);
+ }
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
String *) const;
@@ -2038,8 +2999,11 @@ class Type_handler_int_result: public Type_handler_numeric
public:
Item_result result_type() const { return INT_RESULT; }
Item_result cmp_type() const { return INT_RESULT; }
+ bool is_order_clause_position_type() const { return true; }
+ bool is_limit_clause_valid_type() const { return true; }
virtual ~Type_handler_int_result() {}
const Type_handler *type_handler_for_comparison() const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
@@ -2048,12 +3012,17 @@ public:
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
uint Item_decimal_precision(const Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
const st_value *value) const;
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
@@ -2099,6 +3068,7 @@ public:
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+
};
@@ -2127,6 +3097,8 @@ public:
void sortlength(THD *thd,
const Type_std_attributes *item,
SORT_FIELD_ATTR *attr) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -2159,7 +3131,6 @@ public:
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
MYSQL_TIME *,
ulonglong fuzzydate) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
double Item_func_min_max_val_real(Item_func_min_max *) const;
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
@@ -2167,7 +3138,6 @@ public:
bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const;
bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
Item_func_in *) const;
bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
@@ -2192,6 +3162,7 @@ public:
CHARSET_INFO *charset_for_protocol(const Item *item) const;
virtual ~Type_handler_string_result() {}
const Type_handler *type_handler_for_comparison() const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
CHARSET_INFO *cs) const;
@@ -2211,6 +3182,10 @@ public:
const Schema_specification_st *schema)
const;
uint32 max_display_length(const Item *item) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
uint Item_time_precision(Item *item) const
{
return Item_temporal_precision(item, true);
@@ -2220,6 +3195,7 @@ public:
return Item_temporal_precision(item, false);
}
uint Item_decimal_precision(const Item *item) const;
+ void Item_update_null_value(Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
void Item_param_setup_conversion(THD *thd, Item_param *) const;
void Item_param_set_param_func(Item_param *param,
@@ -2357,6 +3333,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
@@ -2391,6 +3374,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
@@ -2425,11 +3415,29 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
+class Type_handler_bool: public Type_handler_long
+{
+ static const Name m_name_bool;
+public:
+ const Name name() const { return m_name_bool; }
+ bool is_bool_type() const { return true; }
+ void Item_update_null_value(Item *item) const;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const;
+};
+
+
class Type_handler_longlong: public Type_handler_general_purpose_int
{
static const Name m_name_longlong;
@@ -2463,6 +3471,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
@@ -2508,6 +3523,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2527,6 +3549,9 @@ public:
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
ulonglong table_flags) const
@@ -2535,8 +3560,18 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *item,
+ MYSQL_TIME *to,
+ ulonglong fuzzydate) const;
};
@@ -2577,6 +3612,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@@ -2607,6 +3649,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
@@ -2639,6 +3688,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
};
@@ -2655,8 +3711,12 @@ public:
{
return MYSQL_TIMESTAMP_TIME;
}
+ Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
+ CHARSET_INFO *cs, bool send_error) const;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
uint Item_decimal_scale(const Item *item) const
{
return Item_decimal_scale_with_seconds(item);
@@ -2667,12 +3727,15 @@ public:
return Item_divisor_precision_increment_with_seconds(item);
}
const Type_handler *type_handler_for_comparison() const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
return Item_send_time(item, protocol, buf);
}
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
@@ -2693,8 +3756,10 @@ public:
bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
MYSQL_TIME *,
ulonglong fuzzydate) const;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
bool Item_func_min_max_get_date(Item_func_min_max*,
MYSQL_TIME *, ulonglong fuzzydate) const;
+ longlong Item_func_between_val_int(Item_func_between *func) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
bool set_comparator_func(Arg_comparator *cmp) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -2711,6 +3776,7 @@ class Type_handler_time: public Type_handler_time_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_time() {}
+ const Name version() const { return m_version_mariadb53; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -2722,6 +3788,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2729,6 +3802,7 @@ class Type_handler_time2: public Type_handler_time_common
{
public:
virtual ~Type_handler_time2() {}
+ const Name version() const { return m_version_mysql56; }
enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
@@ -2741,6 +3815,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2748,16 +3829,23 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
{
public:
virtual ~Type_handler_temporal_with_date() {}
+ Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
+ CHARSET_INFO *cs, bool send_error) const;
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
return Item_send_date(item, protocol, buf);
}
+ void Item_update_null_value(Item *item) const;
int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
bool set_comparator_func(Arg_comparator *cmp) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
+ longlong Item_func_between_val_int(Item_func_between *func) const;
};
@@ -2773,12 +3861,19 @@ public:
{
return MYSQL_TIMESTAMP_DATE;
}
+ bool cond_notnull_field_isnull_to_field_eq_zero() const
+ {
+ return true;
+ }
+ Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
+ CHARSET_INFO *cs, bool send_error) const;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
uint Item_decimal_precision(const Item *item) const;
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2803,6 +3898,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2822,6 +3924,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2837,8 +3946,13 @@ public:
{
return MYSQL_TIMESTAMP_DATETIME;
}
+ bool cond_notnull_field_isnull_to_field_eq_zero() const
+ {
+ return true;
+ }
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
+ void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
uint Item_decimal_scale(const Item *item) const
{
@@ -2855,6 +3969,7 @@ public:
}
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2872,6 +3987,7 @@ class Type_handler_datetime: public Type_handler_datetime_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_datetime() {}
+ const Name version() const { return m_version_mariadb53; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -2883,6 +3999,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2890,6 +4013,7 @@ class Type_handler_datetime2: public Type_handler_datetime_common
{
public:
virtual ~Type_handler_datetime2() {}
+ const Name version() const { return m_version_mysql56; }
enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
@@ -2902,6 +4026,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2921,6 +4052,7 @@ public:
{
return true;
}
+ void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
uint Item_decimal_scale(const Item *item) const
{
@@ -2937,6 +4069,7 @@ public:
}
String *print_item_value(THD *thd, Item *item, String *str) const;
Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2954,6 +4087,7 @@ class Type_handler_timestamp: public Type_handler_timestamp_common
public:
static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; }
virtual ~Type_handler_timestamp() {}
+ const Name version() const { return m_version_mariadb53; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -2965,6 +4099,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -2972,6 +4113,7 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common
{
public:
virtual ~Type_handler_timestamp2() {}
+ const Name version() const { return m_version_mysql56; }
enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
@@ -2986,6 +4128,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3010,6 +4159,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3041,6 +4197,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3056,6 +4219,8 @@ public:
const Type_handler *type_handler_for_union(const Item *) const;
uint32 max_display_length(const Item *item) const { return 0; }
uint32 calc_pack_length(uint32 length) const { return 0; }
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
bool Item_save_in_value(Item *item, st_value *value) const;
bool Item_send(Item *item, Protocol *protocol, st_value *buf) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
@@ -3079,6 +4244,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3115,6 +4287,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3127,10 +4306,15 @@ public:
const Name name() const { return m_name_var_string; }
enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; }
enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_VARCHAR;
+ }
const Type_handler *type_handler_for_tmp_table(const Item *item) const
{
return varstring_type_handler(item);
}
+ void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
@@ -3173,10 +4357,28 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
bool adjust_spparam_type(Spvar_definition *def, Item *from) const;
};
+class Type_handler_hex_hybrid: public Type_handler_varchar
+{
+ static const Name m_name_hex_hybrid;
+public:
+ virtual ~Type_handler_hex_hybrid() {}
+ const Name name() const { return m_name_hex_hybrid; }
+ const Type_handler *cast_to_int_type_handler() const;
+ const Type_handler *type_handler_for_system_time() const;
+};
+
+
class Type_handler_varchar_compressed: public Type_handler_varchar
{
public:
@@ -3206,6 +4408,9 @@ public:
}
bool is_param_long_data_type() const { return true; }
bool Column_definition_fix_attributes(Column_definition *c) const;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
ulonglong table_flags) const;
@@ -3216,6 +4421,13 @@ public:
Item **items, uint nitems) const;
void Item_param_setup_conversion(THD *thd, Item_param *) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3317,7 +4529,18 @@ public:
const st_value *value) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
@@ -3331,6 +4554,14 @@ public:
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
+
bool can_return_int() const { return false; }
bool can_return_decimal() const { return false; }
bool can_return_real() const { return false; }
@@ -3380,6 +4611,9 @@ public:
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
Item **items, uint nitems) const;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
@@ -3402,7 +4636,11 @@ class Type_handler_enum: public Type_handler_typelib
public:
virtual ~Type_handler_enum() {}
const Name name() const { return m_name_enum; }
- virtual enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
+ enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_ENUM;
+ }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -3414,6 +4652,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3423,7 +4668,11 @@ class Type_handler_set: public Type_handler_typelib
public:
virtual ~Type_handler_set() {}
const Name name() const { return m_name_set; }
- virtual enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
+ enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
+ enum_field_types traditional_merge_field_type() const
+ {
+ return MYSQL_TYPE_SET;
+ }
uint32 calc_pack_length(uint32 length) const;
Field *make_conversion_table_field(TABLE *, uint metadata,
const Field *target) const;
@@ -3435,6 +4684,13 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const;
};
@@ -3535,12 +4791,14 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_set type_handler_set;
extern MYSQL_PLUGIN_IMPORT Type_handler_string type_handler_string;
extern MYSQL_PLUGIN_IMPORT Type_handler_var_string type_handler_var_string;
extern MYSQL_PLUGIN_IMPORT Type_handler_varchar type_handler_varchar;
+extern MYSQL_PLUGIN_IMPORT Type_handler_hex_hybrid type_handler_hex_hybrid;
extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob;
+extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool;
extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_tiny;
extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short;
extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24;
@@ -3553,6 +4811,7 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal;
extern MYSQL_PLUGIN_IMPORT Type_handler_olddecimal type_handler_olddecimal;
extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year;
+extern MYSQL_PLUGIN_IMPORT Type_handler_year type_handler_year2;
extern MYSQL_PLUGIN_IMPORT Type_handler_newdate type_handler_newdate;
extern MYSQL_PLUGIN_IMPORT Type_handler_date type_handler_date;
extern MYSQL_PLUGIN_IMPORT Type_handler_time type_handler_time;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index c8bf9bda57b..29ea427842f 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -68,7 +68,7 @@ void select_unit::change_select()
curr_sel= current_select_number;
/* New SELECT processing starts */
DBUG_ASSERT(table->file->inited == 0);
- step= thd->lex->current_select->linkage;
+ step= thd->lex->current_select->get_linkage();
switch (step)
{
case INTERSECT_TYPE:
@@ -248,7 +248,7 @@ bool select_unit::send_eof()
{
if (step != INTERSECT_TYPE ||
(thd->lex->current_select->next_select() &&
- thd->lex->current_select->next_select()->linkage == INTERSECT_TYPE))
+ thd->lex->current_select->next_select()->get_linkage() == INTERSECT_TYPE))
{
/*
it is not INTESECT or next SELECT in the sequence is INTERSECT so no
@@ -752,11 +752,11 @@ bool st_select_lex_unit::join_union_type_attributes(THD *thd_arg,
been fixed yet. An Item_type_holder must be created based on a fixed
Item, so use the inner Item instead.
*/
- DBUG_ASSERT(item_tmp->fixed ||
+ DBUG_ASSERT(item_tmp->is_fixed() ||
(item_tmp->type() == Item::REF_ITEM &&
((Item_ref *)(item_tmp))->ref_type() ==
Item_ref::OUTER_REF));
- if (!item_tmp->fixed)
+ if (!item_tmp->is_fixed())
item_tmp= item_tmp->real_item();
holders[holder_pos].add_argument(item_tmp);
}
@@ -1419,7 +1419,7 @@ bool st_select_lex_unit::exec()
union_result->change_select();
if (fake_select_lex)
{
- if (sl != &thd->lex->select_lex)
+ if (sl != thd->lex->first_select_lex())
fake_select_lex->uncacheable|= sl->uncacheable;
else
fake_select_lex->uncacheable= 0;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index cb7bcdc33a1..6994ffa04a9 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -318,7 +318,7 @@ int mysql_update(THD *thd,
SQL_SELECT *select= NULL;
SORT_INFO *file_sort= 0;
READ_RECORD info;
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
ulonglong id;
List<Item> all_fields;
killed_state killed_status= NOT_KILLED;
@@ -375,7 +375,7 @@ int mysql_update(THD *thd,
table->covering_keys= table->s->keys_in_use;
table->quick_keys.clear_all();
- query_plan.select_lex= &thd->lex->select_lex;
+ query_plan.select_lex= thd->lex->first_select_lex();
query_plan.table= table;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Force privilege re-checking for views after they have been opened. */
@@ -977,7 +977,7 @@ update_begin:
myf flags= 0;
if (table->file->is_fatal_error(error, HA_CHECK_ALL))
- flags|= ME_FATALERROR; /* Other handler errors are fatal */
+ flags|= ME_FATAL; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
table->file->print_error(error,MYF(flags));
@@ -1088,7 +1088,7 @@ update_begin:
{
/* purecov: begin inspected */
prepare_record_for_error_message(loc_error, table);
- table->file->print_error(loc_error,MYF(ME_FATALERROR));
+ table->file->print_error(loc_error,MYF(ME_FATAL));
error= 1;
/* purecov: end */
}
@@ -1246,7 +1246,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
TABLE *table= table_list->table;
#endif
List<Item> all_fields;
- SELECT_LEX *select_lex= &thd->lex->select_lex;
+ SELECT_LEX *select_lex= thd->lex->first_select_lex();
DBUG_ENTER("mysql_prepare_update");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1523,7 +1523,7 @@ int mysql_multi_update_prepare(THD *thd)
LEX *lex= thd->lex;
TABLE_LIST *table_list= lex->query_tables;
TABLE_LIST *tl;
- List<Item> *fields= &lex->select_lex.item_list;
+ List<Item> *fields= &lex->first_select_lex()->item_list;
table_map tables_for_update;
bool update_view= 0;
/*
@@ -1565,14 +1565,15 @@ int mysql_multi_update_prepare(THD *thd)
if (mysql_handle_derived(lex, DT_PREPARE))
DBUG_RETURN(TRUE);
- if (setup_tables_and_check_access(thd, &lex->select_lex.context,
- &lex->select_lex.top_join_list,
+ if (setup_tables_and_check_access(thd,
+ &lex->first_select_lex()->context,
+ &lex->first_select_lex()->top_join_list,
table_list,
- lex->select_lex.leaf_tables, FALSE,
- UPDATE_ACL, SELECT_ACL, FALSE))
+ lex->first_select_lex()->leaf_tables,
+ FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(TRUE);
- if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
+ if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
@@ -1595,13 +1596,14 @@ int mysql_multi_update_prepare(THD *thd)
thd->table_map_for_update= tables_for_update= get_table_map(fields);
- if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update))
+ if (unsafe_key_update(lex->first_select_lex()->leaf_tables,
+ tables_for_update))
DBUG_RETURN(true);
/*
Setup timestamp handling and locking mode
*/
- List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
+ List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables);
while ((tl= ti++))
{
TABLE *table= tl->table;
@@ -1694,7 +1696,7 @@ int mysql_multi_update_prepare(THD *thd)
Check that we are not using table that we are updating, but we should
skip all tables of UPDATE SELECT itself
*/
- lex->select_lex.exclude_from_table_unique_test= TRUE;
+ lex->first_select_lex()->exclude_from_table_unique_test= TRUE;
/* We only need SELECT privilege for columns in the values list */
ti.rewind();
while ((tl= ti++))
@@ -1716,7 +1718,7 @@ int mysql_multi_update_prepare(THD *thd)
Set exclude_from_table_unique_test value back to FALSE. It is needed for
further check in multi_update::prepare whether to use record cache.
*/
- lex->select_lex.exclude_from_table_unique_test= FALSE;
+ lex->first_select_lex()->exclude_from_table_unique_test= FALSE;
if (lex->save_prep_leaf_tables())
DBUG_RETURN(TRUE);
@@ -1745,7 +1747,7 @@ bool mysql_multi_update(THD *thd,
DBUG_ENTER("mysql_multi_update");
if (!(*result= new (thd->mem_root) multi_update(thd, table_list,
- &thd->lex->select_lex.leaf_tables,
+ &thd->lex->first_select_lex()->leaf_tables,
fields, values,
handle_duplicates, ignore)))
{
@@ -2248,11 +2250,11 @@ int multi_update::prepare2(JOIN *join)
{
if (item_rowid_table(*it2) != tbl)
continue;
- Item *fld= new (thd->mem_root)
- Item_field(thd, (*it)->get_tmp_table_field());
+ Item_field *fld= new (thd->mem_root)
+ Item_field(thd, (*it)->get_tmp_table_field());
if (!fld)
return 1;
- fld->set_result_field((*it2)->get_tmp_table_field());
+ fld->result_field= (*it2)->get_tmp_table_field();
*it2= fld;
}
}
@@ -2384,7 +2386,7 @@ int multi_update::send_data(List<Item> &not_used_values)
myf flags= 0;
if (table->file->is_fatal_error(error, HA_CHECK_ALL))
- flags|= ME_FATALERROR; /* Other handler errors are fatal */
+ flags|= ME_FATAL; /* Other handler errors are fatal */
prepare_record_for_error_message(error, table);
table->file->print_error(error,MYF(flags));
@@ -2539,17 +2541,10 @@ int multi_update::do_updates()
not its dependencies
*/
while(TABLE *tbl= check_opt_it++)
- {
- if (tbl->vcol_set)
- {
- bitmap_clear_all(tbl->vcol_set);
- for (Field **vf= tbl->vfield; *vf; vf++)
- {
+ if (Field **vf= tbl->vfield)
+ for (; *vf; vf++)
if (bitmap_is_set(tbl->read_set, (*vf)->field_index))
- tbl->mark_virtual_col(*vf);
- }
- }
- }
+ (*vf)->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0);
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
{
@@ -2639,10 +2634,10 @@ int multi_update::do_updates()
uint field_num= 0;
do
{
- if (unlikely((local_error=
- tbl->file->ha_rnd_pos(tbl->record[0],
- (uchar *) tmp_table->
- field[field_num]->ptr))))
+ String rowid;
+ tmp_table->field[field_num]->val_str(&rowid);
+ if (unlikely((local_error= tbl->file->ha_rnd_pos(tbl->record[0],
+ (uchar*)rowid.ptr()))))
{
err_table= tbl;
goto err;
@@ -2759,7 +2754,7 @@ int multi_update::do_updates()
err:
{
prepare_record_for_error_message(local_error, err_table);
- err_table->file->print_error(local_error,MYF(ME_FATALERROR));
+ err_table->file->print_error(local_error,MYF(ME_FATAL));
}
err2:
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index f262daad89d..f2fc4b6bf75 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -254,7 +254,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
LEX *lex= thd->lex;
/* first table in list is target VIEW name => cut off it */
TABLE_LIST *tbl;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
SELECT_LEX *sl;
bool res= TRUE;
DBUG_ENTER("create_view_precheck");
@@ -323,7 +323,6 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
}
}
- if (&lex->select_lex != lex->all_selects_list)
{
/* check tables of subqueries */
for (tbl= tables; tbl; tbl= tbl->next_global)
@@ -399,7 +398,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
SELECT_LEX *sl;
SELECT_LEX_UNIT *unit= &lex->unit;
bool res= FALSE;
@@ -995,7 +994,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
{
/* TODO: change here when we will support UNIONs */
- for (TABLE_LIST *tbl= lex->select_lex.table_list.first;
+ for (TABLE_LIST *tbl= lex->first_select_lex()->table_list.first;
tbl;
tbl= tbl->next_local)
{
@@ -1114,8 +1113,8 @@ loop_out:
UNION
*/
if (view->updatable_view &&
- !lex->select_lex.master_unit()->is_unit_op() &&
- !(lex->select_lex.table_list.first)->next_local &&
+ !lex->first_select_lex()->master_unit()->is_unit_op() &&
+ !(lex->first_select_lex()->table_list.first)->next_local &&
find_table_in_global_list(lex->query_tables->next_global,
&lex->query_tables->db,
&lex->query_tables->table_name))
@@ -1162,7 +1161,8 @@ err:
bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
bool open_view_no_parse)
{
- SELECT_LEX *end, *UNINIT_VAR(view_select);
+ SELECT_LEX_NODE *end;
+ SELECT_LEX *UNINIT_VAR(view_select);
LEX *old_lex, *lex;
Query_arena *arena, backup;
TABLE_LIST *top_view= table->top_table();
@@ -1361,8 +1361,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
lex_start(thd);
lex->stmt_lex= old_lex;
- view_select= &lex->select_lex;
- view_select->select_number= ++thd->lex->stmt_lex->current_select_number;
sql_mode_t saved_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
@@ -1397,6 +1395,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx);
+ view_select= lex->first_select_lex();
+
/* Restore environment. */
if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||
@@ -1546,7 +1546,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
This may change in future, for example if we enable merging of
views with subqueries in select list.
*/
- view_main_select_tables= lex->select_lex.table_list.first;
+ view_main_select_tables= lex->first_select_lex()->table_list.first;
/*
Let us set proper lock type for tables of the view's main
@@ -1574,7 +1574,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
/* Fields in this view can be used in upper select in case of merge. */
if (table->select_lex)
- table->select_lex->add_where_field(&lex->select_lex);
+ table->select_lex->add_where_field(lex->first_select_lex());
}
/*
This method has a dependency on the proper lock type being set,
@@ -1596,8 +1596,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
lex->safe_to_cache_query);
/* move SQL_CACHE to whole query */
- if (view_select->options & OPTION_TO_QUERY_CACHE)
- old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+ if (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE)
+ old_lex->first_select_lex()->options|= OPTION_TO_QUERY_CACHE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (table->view_suid)
@@ -1679,9 +1679,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
/* prepare view context */
- lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables);
- lex->select_lex.context.outer_context= 0;
- lex->select_lex.select_n_having_items+=
+ lex->first_select_lex()->
+ context.resolve_in_table_list_only(view_main_select_tables);
+ lex->first_select_lex()->context.outer_context= 0;
+ lex->first_select_lex()->select_n_having_items+=
table->select_lex->select_n_having_items;
table->where= view_select->where;
@@ -1692,12 +1693,13 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
*/
if (!table->select_lex->master_unit()->is_unit_op() &&
table->select_lex->order_list.elements == 0)
- table->select_lex->order_list.push_back(&lex->select_lex.order_list);
+ table->select_lex->order_list.
+ push_back(&lex->first_select_lex()->order_list);
else
{
if (old_lex->sql_command == SQLCOM_SELECT &&
(old_lex->describe & DESCRIBE_EXTENDED) &&
- lex->select_lex.order_list.elements &&
+ lex->first_select_lex()->order_list.elements &&
!table->select_lex->master_unit()->is_unit_op())
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
@@ -1732,7 +1734,11 @@ ok:
lex->unit.include_down(table->select_lex);
lex->unit.slave= view_select; // fix include_down initialisation
/* global SELECT list linking */
- end= view_select; // primary SELECT_LEX is always last
+ /*
+ The primary SELECT_LEX is always last (because parsed first) if WITH not
+ used, otherwise it is good start point for last element finding
+ */
+ for (end= view_select; end->link_next; end= end->link_next);
end->link_next= old_lex->all_selects_list;
old_lex->all_selects_list->link_prev= &end->link_next;
old_lex->all_selects_list= lex->all_selects_list;
@@ -1917,7 +1923,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
*/
if ((!view->view && !view->belong_to_view) ||
thd->lex->sql_command == SQLCOM_INSERT ||
- thd->lex->select_lex.select_limit == 0)
+ thd->lex->first_select_lex()->select_limit == 0)
DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
table= view->table;
view= view->top_table();
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 7ed44982dd6..cc22908ec4b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -491,96 +491,6 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
}
/**
- @brief Creates a new SELECT_LEX for a UNION branch.
-
- Sets up and initializes a SELECT_LEX structure for a query once the parser
- discovers a UNION token. The current SELECT_LEX is pushed on the stack and
- the new SELECT_LEX becomes the current one.
-
- @param lex The parser state.
-
- @param is_union_distinct True if the union preceding the new select
- statement uses UNION DISTINCT.
-
- @param is_top_level This should be @c TRUE if the newly created SELECT_LEX
- is a non-nested statement.
-
- @return <code>false</code> if successful, <code>true</code> if an error was
- reported. In the latter case parsing should stop.
- */
-bool LEX::add_select_to_union_list(bool is_union_distinct,
- enum sub_select_type type,
- bool is_top_level)
-{
- const char *type_name= (type == INTERSECT_TYPE ? "INTERSECT" :
- (type == EXCEPT_TYPE ? "EXCEPT" : "UNION"));
- /*
- Only the last SELECT can have INTO. Since the grammar won't allow INTO in
- a nested SELECT, we make this check only when creating a top-level SELECT.
- */
- if (is_top_level && result)
- {
- my_error(ER_WRONG_USAGE, MYF(0), type_name, "INTO");
- return TRUE;
- }
- if (current_select->order_list.first && !current_select->braces)
- {
- my_error(ER_WRONG_USAGE, MYF(0), type_name, "ORDER BY");
- return TRUE;
- }
-
- if (current_select->explicit_limit && !current_select->braces)
- {
- my_error(ER_WRONG_USAGE, MYF(0), type_name, "LIMIT");
- return TRUE;
- }
- if (current_select->linkage == GLOBAL_OPTIONS_TYPE)
- {
- thd->parse_error();
- return TRUE;
- }
- if (!is_union_distinct && (type == INTERSECT_TYPE || type == EXCEPT_TYPE))
- {
- my_error(ER_WRONG_USAGE, MYF(0), type_name, "ALL");
- return TRUE;
- }
- /*
- Priority implementation, but also trying to keep things as flat
- as possible */
- if (type == INTERSECT_TYPE &&
- (current_select->linkage != INTERSECT_TYPE &&
- current_select != current_select->master_unit()->first_select())
- && !(thd->variables.sql_mode & MODE_ORACLE))
- {
- /*
- This and previous SELECTs should go one level down because of
- priority
- */
- SELECT_LEX *prev= exclude_last_select();
- if (add_unit_in_brackets(prev))
- return TRUE;
- return add_select_to_union_list(is_union_distinct, type, 0);
- }
- else
- {
- check_automatic_up(type);
- }
- /* This counter shouldn't be incremented for UNION parts */
- nest_level--;
- if (mysql_new_select(this, 0, NULL))
- return TRUE;
- mysql_init_select(this);
- current_select->linkage= type;
- current_select->with_all_modifier= !is_union_distinct;
- if (is_union_distinct) /* UNION DISTINCT - remember position */
- current_select->master_unit()->union_distinct= current_select;
- else
- DBUG_ASSERT(type == UNION_TYPE);
- return FALSE;
-}
-
-
-/**
Create a separate LEX for each assignment if in SP.
If we are in SP we want have own LEX for each assignment.
@@ -621,6 +531,7 @@ void sp_create_assignment_lex(THD *thd, bool no_lookahead)
lex->sphead->m_tmp_query= lip->get_tok_end();
/* Inherit from outer lex. */
lex->option_type= old_lex->option_type;
+ lex->main_select_push();
}
}
@@ -680,6 +591,9 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
if (sp->add_instr(i))
return true;
}
+ lex->pop_select();
+ if (Lex->check_main_unit_semantics())
+ return true;
enum_var_type inner_option_type= lex->option_type;
if (lex->sphead->restore_lex(thd))
return true;
@@ -767,6 +681,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
return v;
}
+
%}
%union {
int num;
@@ -796,6 +711,20 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
uint offset;
} sp_cursor_name_and_offset;
vers_history_point_t vers_history_point;
+ struct
+ {
+ enum sub_select_type unit_type;
+ bool distinct;
+ } unit_operation;
+ struct
+ {
+ SELECT_LEX *first;
+ SELECT_LEX *prev_last;
+ } select_list;
+ SQL_I_List<ORDER> *select_order;
+ Lex_select_lock select_lock;
+ Lex_select_limit select_limit;
+ Lex_order_limit_lock *order_limit_lock;
/* pointers */
Create_field *create_field;
@@ -841,6 +770,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
handlerton *db_type;
st_select_lex *select_lex;
+ st_select_lex_unit *select_lex_unit;
struct p_elem_val *p_elem_value;
class Window_frame *window_frame;
class Window_frame_bound *window_frame_bound;
@@ -849,7 +779,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
/* enums */
enum enum_view_suid view_suid;
- enum sub_select_type unit_type;
enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name;
enum Diagnostics_information::Which_area diag_area;
@@ -888,10 +817,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 62 shift/reduce conflicts.
+ Currently there are 58 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 62
+%expect 58
/*
Comments for TOKENS.
@@ -1042,6 +971,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token LEADING /* SQL-2003-R */
%token LEAVE_SYM
%token LEFT /* SQL-2003-R */
+%token LEFT_PAREN_ALT /* INTERNAL */
+%token LEFT_PAREN_WITH /* INTERNAL */
+%token LEFT_PAREN_LIKE /* INTERNAL */
%token LEX_HOSTNAME
%token LIKE /* SQL-2003-R */
%token LIMIT
@@ -1784,7 +1716,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
NCHAR_STRING
%type <lex_str_ptr>
- opt_table_alias
+ opt_table_alias_clause
+ table_alias_clause
%type <ident_cli>
IDENT
@@ -1846,7 +1779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_temporary all_or_any opt_distinct opt_glimit_clause
opt_ignore_leaves fulltext_options union_option
opt_not
- select_derived_init transaction_access_mode_types
+ transaction_access_mode_types
opt_natural_language_mode opt_query_expansion
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
@@ -1966,11 +1899,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
join_table_list join_table
table_factor table_ref esc_table_ref
table_primary_ident table_primary_derived
- select_derived derived_table_list
- select_derived_union
- derived_simple_table
- derived_query_specification
- derived_table_value_constructor
+ derived_table_list table_reference_list_parens
+ nested_table_reference_list join_table_parens
%type <date_time_type> date_time_type;
%type <interval> interval
@@ -2004,14 +1934,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
UNDERSCORE_CHARSET
%type <select_lex> subselect
- get_select_lex get_select_lex_derived
- simple_table
query_specification
- query_term_union_not_ready
- query_term_union_ready
- query_expression_body
- select_paren_derived
table_value_constructor
+ simple_table
+ query_primary
+ query_primary_parens
+ select_into_query_specification
+
+
+%type <select_lex_unit>
+ query_specification_start
+ query_expression_body
+ query_expression
+ query_expression_unit
%type <boolfunc2creator> comp_op
@@ -2023,11 +1958,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <virtual_column> opt_check_constraint check_constraint virtual_column_func
column_default_expr
-%type <unit_type> unit_type_decl
+
+%type <unit_operation> unit_type_decl
+
+%type <select_lock>
+ opt_procedure_or_into
+ opt_select_lock_type
+ select_lock_type
+ opt_lock_wait_timeout_new
+
+%type <select_limit> opt_limit_clause limit_clause limit_options
+
+%type <order_limit_lock>
+ query_expression_tail
+ order_or_limit
+ opt_order_limit_lock
+
+%type <select_order> opt_order_clause order_clause order_list
%type <NONE>
analyze_stmt_command
- query verb_clause create change select do drop insert replace insert2
+ query verb_clause create change select select_into
+ do drop insert replace insert2
insert_values update delete truncate rename compound_statement
show describe load alter optimize keycache preload flush
reset purge begin commit rollback savepoint release
@@ -2043,7 +1995,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
assign_to_keycache_parts
preload_list preload_list_or_parts preload_keys preload_keys_parts
select_item_list select_item values_list no_braces
- opt_limit_clause delete_limit_clause fields opt_values values
+ delete_limit_clause fields opt_values values
no_braces_with_names opt_values_with_names values_with_names
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
@@ -2064,9 +2016,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
- union_clause union_list
- subselect_start opt_and charset
- subselect_end select_var_list select_var_list_init help
+ opt_and charset
+ select_var_list select_var_list_init help
opt_extended_describe shutdown
opt_format_json
prepare prepare_src execute deallocate
@@ -2194,8 +2145,8 @@ rule: <-- starts at col 1
query:
END_OF_INPUT
{
- if (likely(!thd->bootstrap) &&
- unlikely(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
+ if (!thd->bootstrap &&
+ (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT)))
my_yyabort_error((ER_EMPTY_QUERY, MYF(0)));
thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
@@ -2290,6 +2241,7 @@ statement:
| rollback
| savepoint
| select
+ | select_into
| set
| signal_stmt
| show
@@ -2325,6 +2277,8 @@ prepare:
if (unlikely(lex->table_or_sp_used()))
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
"PREPARE..FROM"));
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_PREPARE;
lex->prepared_stmt_name= $2;
}
@@ -2347,7 +2301,10 @@ execute:
lex->prepared_stmt_name= $2;
}
execute_using
- {}
+ {
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| EXECUTE_SYM IMMEDIATE_SYM prepare_src
{
if (unlikely(Lex->table_or_sp_used()))
@@ -2356,7 +2313,10 @@ execute:
Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
}
execute_using
- {}
+ {
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
execute_using:
@@ -2643,17 +2603,22 @@ connection_name:
/* create a table */
create:
- create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
+ create_or_replace opt_temporary TABLE_SYM opt_if_not_exists
{
LEX *lex= thd->lex;
lex->create_info.init();
- if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2,
- $1 | $4)))
+ if (lex->main_select_push())
+ MYSQL_YYABORT;
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
+ if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
MYSQL_YYABORT;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ }
+ table_ident
+ {
+ LEX *lex= thd->lex;
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
lex->alter_info.reset();
/*
@@ -2668,7 +2633,6 @@ create:
create_body
{
LEX *lex= thd->lex;
- lex->current_select= &lex->select_lex;
if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
!lex->create_info.db_type)
{
@@ -2677,22 +2641,24 @@ create:
ER_WARN_USING_OTHER_HANDLER,
ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
hton_name(lex->create_info.db_type)->str,
- $5->table.str);
+ $6->table.str);
}
create_table_set_open_action_and_adjust_tables(lex);
+ Lex->pop_select(); //main select
}
| create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2,
$1 | $4)))
MYSQL_YYABORT;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
/*
@@ -2715,8 +2681,9 @@ create:
if (unlikely(lex->create_info.seq_create_info->check_and_adjust(1)))
{
my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
- lex->select_lex.table_list.first->db.str,
- lex->select_lex.table_list.first->table_name.str);
+ lex->first_select_lex()->table_list.first->db.str,
+ lex->first_select_lex()->table_list.first->
+ table_name.str);
MYSQL_YYABORT;
}
@@ -2729,10 +2696,8 @@ create:
Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
Lex->create_info.sequence= 1;
- lex->current_select= &lex->select_lex;
- if (unlikely((lex->create_info.used_fields &
- HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type))
+ if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
+ !lex->create_info.db_type)
{
lex->create_info.use_default_db_type(thd);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -2742,44 +2707,69 @@ create:
$5->table.str);
}
create_table_set_open_action_and_adjust_tables(lex);
+ Lex->pop_select(); //main select
}
- | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
+ | create_or_replace opt_unique INDEX_SYM opt_if_not_exists
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ ident
opt_key_algorithm_clause
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($8)))
+ if (Lex->add_create_index_prepare($9))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, $6, $1 | $4)))
+ if (Lex->add_create_index($2, &$6, $7, $1 | $4))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout normal_key_options
- opt_index_lock_algorithm { }
- | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace fulltext INDEX_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ opt_if_not_exists ident
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($7)))
+ if (Lex->add_create_index_prepare($8))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF,
- $1 | $4)))
+ if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout fulltext_key_options
- opt_index_lock_algorithm { }
- | create_or_replace spatial INDEX_SYM opt_if_not_exists ident
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace spatial INDEX_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ opt_if_not_exists ident
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($7)))
+ if (Lex->add_create_index_prepare($8))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF,
- $1 | $4)))
+ if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout spatial_key_options
- opt_index_lock_algorithm { }
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
opt_create_database_options
{
@@ -2788,59 +2778,103 @@ create:
$1 | $3)))
MYSQL_YYABORT;
lex->name= $4;
+ Lex->pop_select(); //main select
}
| create_or_replace definer_opt opt_view_suid VIEW_SYM
opt_if_not_exists table_ident
{
- if (unlikely(Lex->add_create_view(thd, $1 | $5,
- DTYPE_ALGORITHM_UNDEFINED, $3,
- $6)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_create_view(thd, $1 | $5,
+ DTYPE_ALGORITHM_UNDEFINED, $3, $6))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM
opt_if_not_exists table_ident
{
if (unlikely(Lex->add_create_view(thd, $1 | $6, $2, $4, $7)))
MYSQL_YYABORT;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
view_list_opt AS view_select
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt TRIGGER_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
trigger_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt PROCEDURE_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
sp_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt EVENT_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
event_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer FUNCTION_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->create_info.set($1);
}
- sf_tail_not_aggregate
- { }
+ sf_tail
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer AGGREGATE_SYM FUNCTION_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->create_info.set($1);
}
sf_tail_aggregate
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace no_definer FUNCTION_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
create_function_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->create_info.set($1);
}
create_aggregate_function_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
opt_require_clause opt_resource_options
{
@@ -3243,7 +3277,7 @@ clear_privileges:
lex->columns.empty();
lex->grant= lex->grant_tot_col= 0;
lex->all_privileges= 0;
- lex->select_lex.db= null_clex_str;
+ lex->first_select_lex()->db= null_clex_str;
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char *)&(lex->mqh),sizeof(lex->mqh));
@@ -3742,7 +3776,7 @@ sp_hcond:
signal_stmt:
SIGNAL_SYM signal_value opt_set_signal_information
{
- if (unlikely(Lex->add_signal_statement(thd, $2)))
+ if (Lex->add_signal_statement(thd, $2))
MYSQL_YYABORT;
}
;
@@ -4202,7 +4236,7 @@ assignment_source_expr:
$$->sp_lex_in_use= true;
$$->set_item_and_free_list($3, thd->free_list);
thd->free_list= NULL;
- if (unlikely($$->sphead->restore_lex(thd)))
+ if ($$->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
;
@@ -4211,6 +4245,7 @@ for_loop_bound_expr:
assignment_source_lex
{
Lex->sphead->reset_lex(thd, $1);
+ Lex->current_select->parsing_place= FOR_LOOP_BOUND;
}
expr
{
@@ -4220,6 +4255,7 @@ for_loop_bound_expr:
$$->set_item_and_free_list($3, NULL);
if (unlikely($$->sphead->restore_lex(thd)))
MYSQL_YYABORT;
+ Lex->current_select->parsing_place= NO_MATTER;
}
;
@@ -4453,7 +4489,8 @@ case_stmt_body:
{
if (unlikely(Lex->case_stmt_action_expr($2)))
MYSQL_YYABORT;
- if (unlikely(Lex->sphead->restore_lex(thd)))
+
+ if (Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
simple_when_clause_list
@@ -4655,7 +4692,7 @@ while_body:
LEX *lex= Lex;
if (unlikely(lex->sp_while_loop_expression(thd, $1)))
MYSQL_YYABORT;
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
sp_proc_stmts1 END WHILE_SYM
@@ -4678,7 +4715,7 @@ repeat_body:
if (unlikely(i == NULL) ||
unlikely(lex->sphead->add_instr(i)))
MYSQL_YYABORT;
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
/* We can shortcut the cont_backpatch here */
i->m_cont_dest= ip+1;
@@ -5158,26 +5195,16 @@ size_number:
*/
create_body:
- '(' create_field_list ')'
+ create_field_list_parens
{ Lex->create_info.option_list= NULL; }
opt_create_table_options opt_create_partitioning opt_create_select {}
| opt_create_table_options opt_create_partitioning opt_create_select {}
- /*
- the following rule is redundant, but there's a shift/reduce
- conflict that prevents the rule above from parsing a syntax like
- CREATE TABLE t1 (SELECT 1);
- */
- | '(' create_select_query_specification ')'
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_list {}
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_order_or_limit {}
| create_like
{
Lex->create_info.add(DDL_options_st::OPT_LIKE);
- TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd,
- $1, NULL, 0, TL_READ, MDL_SHARED_READ);
+ TABLE_LIST *src_table= Lex->first_select_lex()->
+ add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ);
if (unlikely(! src_table))
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -5187,7 +5214,7 @@ create_body:
create_like:
LIKE table_ident { $$= $2; }
- | '(' LIKE table_ident ')' { $$= $3; }
+ | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; }
;
opt_create_select:
@@ -5196,23 +5223,19 @@ opt_create_select:
;
create_select_query_expression:
- opt_with_clause SELECT_SYM create_select_part2 opt_table_expression
- create_select_part4
- {
- Select->set_braces(0);
- Select->set_with_clause($1);
+ query_expression
+ {
+ if (Lex->parsed_insert_select($1->first_select()))
+ MYSQL_YYABORT;
}
- union_clause
- | opt_with_clause SELECT_SYM create_select_part2
- create_select_part3_union_not_ready create_select_part4
+ | LEFT_PAREN_WITH with_clause query_expression_body ')'
{
- Select->set_with_clause($1);
+ SELECT_LEX *first_select= $3->first_select();
+ $3->set_with_clause($2);
+ $2->attach_to(first_select);
+ if (Lex->parsed_insert_select(first_select))
+ MYSQL_YYABORT;
}
- | '(' create_select_query_specification ')'
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_list {}
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_order_or_limit {}
;
opt_create_partitioning:
@@ -5295,13 +5318,17 @@ partition_entry:
thd->parse_error(ER_PARTITION_ENTRY_ERROR);
MYSQL_YYABORT;
}
- DBUG_ASSERT(Lex->part_info->table);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
/*
We enter here when opening the frm file to translate
partition info string into part_info data structure.
*/
}
- partition {}
+ partition
+ {
+ Lex->pop_select(); //main select
+ }
;
partition:
@@ -5955,56 +5982,6 @@ opt_versioning_interval_start:
End of partition parser part
*/
-create_select_query_specification:
- opt_with_clause SELECT_SYM create_select_part2 create_select_part3
- create_select_part4
- {
- Select->set_with_clause($1);
- }
- ;
-
-create_select_part2:
- {
- LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_INSERT)
- lex->sql_command= SQLCOM_INSERT_SELECT;
- else if (lex->sql_command == SQLCOM_REPLACE)
- lex->sql_command= SQLCOM_REPLACE_SELECT;
- /*
- The following work only with the local list, the global list
- is created correctly in this case
- */
- lex->current_select->table_list.save_and_clear(&lex->save_list);
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- }
- select_options select_item_list
- {
- Select->parsing_place= NO_MATTER;
- }
- ;
-
-create_select_part3:
- opt_table_expression
- | create_select_part3_union_not_ready
- ;
-
-create_select_part3_union_not_ready:
- table_expression order_or_limit
- | order_or_limit
- ;
-
-create_select_part4:
- opt_select_lock_type
- {
- /*
- The following work only with the local list, the global list
- is created correctly in this case
- */
- Lex->current_select->table_list.push_front(&Lex->save_list);
- }
- ;
-
opt_as:
/* empty */ {}
| AS {}
@@ -6222,7 +6199,7 @@ create_table_option:
}
| UNION_SYM opt_equal
{
- Lex->select_lex.table_list.save_and_clear(&Lex->save_list);
+ Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list);
}
'(' opt_table_list ')'
{
@@ -6231,8 +6208,8 @@ create_table_option:
from the global list.
*/
LEX *lex=Lex;
- lex->create_info.merge_list= lex->select_lex.table_list;
- lex->select_lex.table_list= lex->save_list;
+ lex->create_info.merge_list= lex->first_select_lex()->table_list;
+ lex->first_select_lex()->table_list= lex->save_list;
/*
When excluding union list from the global list we assume that
elements of the former immediately follow elements which represent
@@ -6433,6 +6410,13 @@ create_field_list:
}
;
+create_field_list_parens:
+ LEFT_PAREN_ALT field_list ')'
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
+ ;
+
field_list:
field_list_item
| field_list ',' field_list_item
@@ -6727,6 +6711,8 @@ parse_vcol_expr:
Prevent the end user from invoking this command.
*/
MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
expr
{
@@ -6734,14 +6720,15 @@ parse_vcol_expr:
if (unlikely(!v))
MYSQL_YYABORT;
Lex->last_field->vcol_info= v;
+ Lex->pop_select(); //main select
}
;
parenthesized_expr:
- subselect
+ remember_tok_start
+ query_expression
{
- $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1);
- if (unlikely($$ == NULL))
+ if (!($$= Lex->create_item_query_expression(thd, $1, $2)))
MYSQL_YYABORT;
}
| expr
@@ -7658,23 +7645,25 @@ alter:
Lex->name= null_clex_str;
Lex->table_type= TABLE_TYPE_UNKNOWN;
Lex->sql_command= SQLCOM_ALTER_TABLE;
- Lex->duplicates= DUP_ERROR;
- Lex->select_lex.init_order();
+ Lex->duplicates= DUP_ERROR;
+ Lex->first_select_lex()->order_list.empty();
Lex->create_info.init();
Lex->create_info.row_type= ROW_TYPE_NOT_USED;
Lex->alter_info.reset();
Lex->no_write_to_binlog= 0;
Lex->create_info.storage_media= HA_SM_DEFAULT;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
DBUG_ASSERT(!Lex->m_sql_cmd);
}
alter_options TABLE_SYM table_ident opt_lock_wait_timeout
{
- if (unlikely(!Lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_UPGRADABLE)))
+ if (!Lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE))
MYSQL_YYABORT;
- Lex->select_lex.db= (Lex->select_lex.table_list.first)->db;
+ Lex->first_select_lex()->db=
+ (Lex->first_select_lex()->table_list.first)->db;
Lex->create_last_non_select_table= Lex->last_table();
}
alter_commands
@@ -7686,11 +7675,14 @@ alter:
if (unlikely(Lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
}
+ Lex->pop_select(); //main select
}
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
create_database_options
{
@@ -7700,6 +7692,7 @@ alter:
if (lex->name.str == NULL &&
unlikely(lex->copy_db_to(&lex->name)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
}
| ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
{
@@ -7715,6 +7708,8 @@ alter:
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->sp_chistics.init();
}
sp_a_chistics
@@ -7723,6 +7718,9 @@ alter:
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
lex->spname= $3;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| ALTER FUNCTION_SYM sp_name
{
@@ -7730,6 +7728,8 @@ alter:
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->sp_chistics.init();
}
sp_a_chistics
@@ -7738,14 +7738,23 @@ alter:
lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->spname= $3;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident
{
- if (unlikely(Lex->add_alter_view(thd, $2, $4, $6)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_alter_view(thd, $2, $4, $6))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| ALTER definer_opt opt_view_suid VIEW_SYM table_ident
/*
We have two separate rules for ALTER VIEW rather that
@@ -7753,14 +7762,22 @@ alter:
with the ALTER EVENT below.
*/
{
- if (unlikely(Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| ALTER definer_opt remember_name EVENT_SYM sp_name
{
- /*
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ /*
It is safe to use Lex->spname because
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
is not allowed. Lex->spname is used in the case of RENAME TO
@@ -7792,6 +7809,8 @@ alter:
*/
Lex->sql_command= SQLCOM_ALTER_EVENT;
Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr();
+
+ Lex->pop_select(); //main select
}
| ALTER TABLESPACE alter_tablespace_info
{
@@ -7835,16 +7854,17 @@ alter:
lex->create_info.init();
lex->no_write_to_binlog= 0;
DBUG_ASSERT(!lex->m_sql_cmd);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
table_ident
{
LEX *lex= Lex;
- if (unlikely(!(lex->create_info.seq_create_info=
- new (thd->mem_root) sequence_definition())) ||
- unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_SEQUENCE,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ if (!(lex->create_info.seq_create_info= new (thd->mem_root)
+ sequence_definition()) ||
+ !lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
}
sequence_defs
@@ -7853,6 +7873,9 @@ alter:
Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
if (unlikely(Lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
;
@@ -8002,16 +8025,17 @@ alter_commands:
WITH TABLE_SYM table_ident have_partitioning
{
LEX *lex= thd->lex;
- lex->select_lex.db= $6->db;
- if (lex->select_lex.db.str == NULL &&
- unlikely(lex->copy_db_to(&lex->select_lex.db)))
+ lex->first_select_lex()->db=$6->db;
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
+ {
MYSQL_YYABORT;
+ }
lex->name= $6->table;
lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $6, NULL,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_NO_WRITE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT, MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
DBUG_ASSERT(!lex->m_sql_cmd);
lex->m_sql_cmd= new (thd->mem_root)
@@ -8250,9 +8274,9 @@ alter_list_item:
| RENAME opt_to table_ident
{
LEX *lex=Lex;
- lex->select_lex.db= $3->db;
- if (lex->select_lex.db.str == NULL &&
- unlikely(lex->copy_db_to(&lex->select_lex.db)))
+ lex->first_select_lex()->db= $3->db;
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
MYSQL_YYABORT;
if (unlikely(check_table_name($3->table.str,$3->table.length,
FALSE)) ||
@@ -8947,8 +8971,8 @@ adm_partition:
cache_keys_spec:
{
- Lex->select_lex.alloc_index_hints(thd);
- Select->set_index_hint_type(INDEX_HINT_USE,
+ Lex->first_select_lex()->alloc_index_hints(thd);
+ Select->set_index_hint_type(INDEX_HINT_USE,
INDEX_HINT_MASK_ALL);
}
cache_key_list_or_empty
@@ -8969,217 +8993,218 @@ opt_ignore_leaves:
Select : retrieve data from table
*/
-
select:
- opt_with_clause select_init
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SELECT;
- lex->current_select->set_with_clause($1);
- }
- ;
-
-select_init:
- SELECT_SYM select_options_and_item_list select_init3
- | table_value_constructor
- | table_value_constructor union_list
- | table_value_constructor union_order_or_limit
- | '(' select_paren ')'
- | '(' select_paren ')' union_list
- | '(' select_paren ')' union_order_or_limit
- ;
-
-union_list_part2:
- SELECT_SYM select_options_and_item_list select_init3_union_query_term
- | table_value_constructor
- | table_value_constructor union_list
- | table_value_constructor union_order_or_limit
- | '(' select_paren_union_query_term ')'
- | '(' select_paren_union_query_term ')' union_list
- | '(' select_paren_union_query_term ')' union_order_or_limit
- ;
-
-select_paren:
+ query_expression_body
{
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($1->fake_select_lex ?
+ $1->fake_select_lex :
+ $1->first_select()))
+ MYSQL_YYABORT;
}
- table_value_constructor
+ opt_procedure_or_into
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Lex->pop_select();
+ if ($1->set_lock_to_the_last_select($3))
+ MYSQL_YYABORT;
+ if (Lex->select_finalize($1))
+ MYSQL_YYABORT;
}
- |
+ | with_clause query_expression_body
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($2->fake_select_lex ?
+ $2->fake_select_lex :
+ $2->first_select()))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_options_and_item_list select_part3
- opt_select_lock_type
+ opt_procedure_or_into
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Lex->pop_select();
+ $2->set_with_clause($1);
+ $1->attach_to($2->first_select());
+ if ($2->set_lock_to_the_last_select($4))
+ MYSQL_YYABORT;
+ if (Lex->select_finalize($2))
+ MYSQL_YYABORT;
}
- | '(' select_paren ')'
;
-select_paren_union_query_term:
+
+select_into:
+ select_into_query_specification
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($1))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_options_and_item_list select_part3_union_query_term
- opt_select_lock_type
+ opt_order_limit_lock
{
- DBUG_ASSERT(Lex->current_select->braces);
- }
- | '(' select_paren_union_query_term ')'
+ st_select_lex_unit *unit;
+ if (!(unit= Lex->parsed_body_select($1, $3)))
+ MYSQL_YYABORT;
+ if (Lex->select_finalize(unit))
+ MYSQL_YYABORT;
+ }
+ ;
+
+
+simple_table:
+ query_specification { $$= $1; }
+ | table_value_constructor { $$= $1; }
;
-select_paren_view:
+table_value_constructor:
+ VALUES
+ {
+ if (Lex->parsed_TVC_start())
+ MYSQL_YYABORT;
+ }
+ values_list
+ {
+ if (!($$= Lex->parsed_TVC_end()))
+ MYSQL_YYABORT;
+ }
+ ;
+
+query_specification_start:
+ SELECT_SYM
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ SELECT_LEX *sel;
+ LEX *lex= Lex;
+ if (!(sel= lex->alloc_select(TRUE)) ||
+ lex->push_select(sel))
+ MYSQL_YYABORT;
+ sel->init_select();
+ sel->braces= FALSE;
}
- SELECT_SYM select_options_and_item_list select_part3_view
- opt_select_lock_type
+ select_options
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Select->parsing_place= SELECT_LIST;
}
- | '(' select_paren_view ')'
- ;
+ select_item_list
+ {
+ Select->parsing_place= NO_MATTER;
+ }
+ ;
-/* The equivalent of select_paren for nested queries. */
-select_paren_derived:
+query_specification:
+ query_specification_start
+ opt_from_clause
+ opt_where_clause
+ opt_group_clause
+ opt_having_clause
+ opt_window_clause
{
- Lex->current_select->set_braces(true);
+ $$= Lex->pop_select();
}
- table_value_constructor
+ ;
+
+select_into_query_specification:
+ query_specification_start
+ into
+ opt_from_clause
+ opt_where_clause
+ opt_group_clause
+ opt_having_clause
+ opt_window_clause
{
- DBUG_ASSERT(Lex->current_select->braces);
- $$= Lex->current_select->master_unit()->first_select();
+ $$= Lex->pop_select();
}
- |
+ ;
+
+opt_from_clause:
+ /* Empty */
+ | from_clause
+ ;
+
+
+query_primary:
+ simple_table
+ { $$= $1; }
+ | query_primary_parens
+ { $$= $1; }
+ ;
+
+query_primary_parens:
+ '(' query_expression_unit
{
- Lex->current_select->set_braces(true);
+ if (Lex->parsed_unit_in_brackets($2))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_part2_derived
- opt_table_expression
- opt_order_clause
- opt_limit_clause
- opt_select_lock_type
+ query_expression_tail ')'
{
- DBUG_ASSERT(Lex->current_select->braces);
- $$= Lex->current_select->master_unit()->first_select();
+ $$= Lex->parsed_unit_in_brackets_tail($2, $4);
}
- | '(' select_paren_derived ')' { $$= $2; }
- ;
-
-select_init3:
- opt_table_expression
- opt_select_lock_type
+ | '(' query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ Lex->push_select($2);
}
- union_clause
- | select_part3_union_not_ready
- opt_select_lock_type
+ query_expression_tail ')'
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_in_brackets($2, $4)))
+ YYABORT;
}
;
-
-select_init3_union_query_term:
- opt_table_expression
- opt_select_lock_type
+query_expression_unit:
+ query_primary
+ unit_type_decl
+ query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type,
+ $2.distinct)))
+ YYABORT;
}
- union_clause
- | select_part3_union_not_ready_noproc
- opt_select_lock_type
+ | query_expression_unit
+ unit_type_decl
+ query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type,
+ $2.distinct, FALSE)))
+ YYABORT;
}
;
-
-select_init3_view:
- opt_table_expression opt_select_lock_type
+query_expression_body:
+ query_primary
{
- Lex->current_select->set_braces(false);
+ Lex->push_select($1);
}
- | opt_table_expression opt_select_lock_type
+ query_expression_tail
{
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_body_select($1, $3)))
+ MYSQL_YYABORT;
}
- union_list_view
- | order_or_limit opt_select_lock_type
+ | query_expression_unit
{
- Lex->current_select->set_braces(false);
+ if (Lex->parsed_body_unit($1))
+ MYSQL_YYABORT;
}
- | table_expression order_or_limit opt_select_lock_type
+ query_expression_tail
{
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_body_unit_tail($1, $3)))
+ MYSQL_YYABORT;
}
;
-/*
- The SELECT parts after select_item_list that cannot be followed by UNION.
-*/
-
-select_part3:
- opt_table_expression
- | select_part3_union_not_ready
- ;
-
-select_part3_union_query_term:
- opt_table_expression
- | select_part3_union_not_ready_noproc
- ;
-
-select_part3_view:
- opt_table_expression
- | order_or_limit
- | table_expression order_or_limit
- ;
-
-select_part3_union_not_ready:
- select_part3_union_not_ready_noproc
- | table_expression procedure_clause
- | table_expression order_or_limit procedure_clause
+query_expression:
+ opt_with_clause
+ query_expression_body
+ {
+ if ($1)
+ {
+ $2->set_with_clause($1);
+ $1->attach_to($2->first_select());
+ }
+ $$= $2;
+ }
;
-select_part3_union_not_ready_noproc:
- order_or_limit
- | into opt_table_expression opt_order_clause opt_limit_clause
- | table_expression into
- | table_expression order_or_limit
- | table_expression order_or_limit into
- ;
-select_options_and_item_list:
- {
- LEX *lex= Lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->linkage != UNION_TYPE)
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- }
- select_options select_item_list
+subselect:
+ remember_tok_start
+ query_expression
{
- Select->parsing_place= NO_MATTER;
+ if (!($$= Lex->parsed_subselect($2, $1)))
+ YYABORT;
}
;
@@ -9187,18 +9212,6 @@ select_options_and_item_list:
/**
<table expression>, as in the SQL standard.
*/
-table_expression:
- from_clause
- opt_where_clause
- opt_group_clause
- opt_having_clause
- opt_window_clause
- ;
-
-opt_table_expression:
- /* Empty */
- | table_expression
- ;
from_clause:
FROM table_reference_list
@@ -9247,8 +9260,9 @@ history_point:
TIMESTAMP TEXT_STRING
{
Item *item;
- if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL,
- MYSQL_TYPE_DATETIME, true)))
+ if (!(item= type_handler_datetime.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true)))
MYSQL_YYABORT;
$$= Vers_history_point(VERS_TIMESTAMP, item);
}
@@ -9301,59 +9315,68 @@ select_option:
query_expression_option
| SQL_NO_CACHE_SYM
{
- /*
- Allow this flag only on the first top-level SELECT statement, if
- SQL_CACHE wasn't specified, and only once per query.
- */
- if (unlikely(Lex->current_select != &Lex->select_lex))
- my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE))
+ /*
+ Allow this flag once per query.
+ */
+ if (Select->options & OPTION_NO_QUERY_CACHE)
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
-
- Lex->safe_to_cache_query=0;
- Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
- Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+ Select->options|= OPTION_NO_QUERY_CACHE;
}
| SQL_CACHE_SYM
{
- /*
- Allow this flag only on the first top-level SELECT statement, if
- SQL_NO_CACHE wasn't specified, and only once per query.
- */
- if (unlikely(Lex->current_select != &Lex->select_lex))
- my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE))
+ /*
+ Allow this flag once per query.
+ */
+ if (Select->options & OPTION_TO_QUERY_CACHE)
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
-
- Lex->safe_to_cache_query=1;
- Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
- Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
+ Select->options|= OPTION_TO_QUERY_CACHE;
}
;
-opt_select_lock_type:
- /* empty */
- | FOR_SYM UPDATE_SYM opt_lock_wait_timeout
+
+select_lock_type:
+ FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new
{
- LEX *lex=Lex;
- lex->current_select->lock_type= TL_WRITE;
- lex->current_select->set_lock_for_tables(TL_WRITE);
- lex->safe_to_cache_query=0;
+ $$= $3;
+ $$.defined_lock= TRUE;
+ $$.update_lock= TRUE;
}
- | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout
+ | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new
{
- LEX *lex=Lex;
- lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS;
- lex->current_select->
- set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
- lex->safe_to_cache_query=0;
+ $$= $5;
+ $$.defined_lock= TRUE;
+ $$.update_lock= FALSE;
}
;
+opt_select_lock_type:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | select_lock_type
+ {
+ $$= $1;
+ }
+ ;
+
+opt_lock_wait_timeout_new:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | WAIT_SYM ulong_num
+ {
+ $$.defined_timeout= TRUE;
+ $$.timeout= $2;
+ }
+ | NOWAIT_SYM
+ {
+ $$.defined_timeout= TRUE;
+ $$.timeout= 0;
+ }
+ ;
+
select_item_list:
select_item_list ',' select_item
| select_item
@@ -10002,7 +10025,21 @@ column_default_non_parenthesized_expr:
| param_marker { $$= $1; }
| variable
| sum_expr
+ {
+ if (!Lex->select_stack_top)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+ MYSQL_YYABORT;
+ }
+ }
| window_func_expr
+ {
+ if (!Lex->select_stack_top)
+ {
+ my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
+ MYSQL_YYABORT;
+ }
+ }
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')'
{
@@ -10180,7 +10217,7 @@ function_call_keyword_timestamp:
}
| TIMESTAMP '(' expr ',' expr ')'
{
- $$= new (thd->mem_root) Item_func_add_time(thd, $3, $5, 1, 0);
+ $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
@@ -11595,10 +11632,15 @@ esc_table_ref:
/* Equivalent to <table reference list> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
derived_table_list:
- esc_table_ref { $$=$1; }
+ esc_table_ref
+ {
+ $$=$1;
+ Select->add_joined_table($1);
+ }
| derived_table_list ',' esc_table_ref
{
MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ Select->add_joined_table($3);
}
;
@@ -11617,11 +11659,18 @@ join_table:
left-associative joins.
*/
table_ref normal_join table_ref %prec TABLE_REF_PRIORITY
- { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; }
+ {
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
+ $3->straight=$2;
+ }
| table_ref normal_join table_ref
ON
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $3)))
MYSQL_YYABORT;
@@ -11638,6 +11687,8 @@ join_table:
USING
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
}
'(' using_list ')'
{
@@ -11648,6 +11699,8 @@ join_table:
| table_ref NATURAL inner_join table_factor
{
MYSQL_YYABORT_UNLESS($1 && ($$=$4));
+ Select->add_joined_table($1);
+ Select->add_joined_table($4);
$4->straight=$3;
add_join_natural($1,$4,NULL,Select);
}
@@ -11657,6 +11710,8 @@ join_table:
ON
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
MYSQL_YYABORT;
@@ -11673,6 +11728,8 @@ join_table:
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
}
USING '(' using_list ')'
{
@@ -11683,6 +11740,8 @@ join_table:
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $6);
+ Select->add_joined_table($1);
+ Select->add_joined_table($6);
add_join_natural($1,$6,NULL,Select);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
@@ -11693,6 +11752,8 @@ join_table:
ON
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
MYSQL_YYABORT;
@@ -11710,6 +11771,8 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
}
USING '(' using_list ')'
{
@@ -11721,6 +11784,8 @@ join_table:
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $6);
+ Select->add_joined_table($1);
+ Select->add_joined_table($6);
add_join_natural($6,$1,NULL,Select);
LEX *lex= Lex;
if (unlikely(!($$= lex->current_select->convert_right_join())))
@@ -11756,238 +11821,44 @@ use_partition:
}
;
-/*
- This is a flattening of the rules <table factor> and <table primary>
- in the SQL:2003 standard, since we don't have <sample clause>
-
- I.e.
- <table factor> ::= <table primary> [ <sample clause> ]
-*/
-/* Warning - may return NULL in case of incomplete SELECT */
table_factor:
- table_primary_ident
- | table_primary_derived
+ table_primary_ident { $$= $1; }
+ | table_primary_derived { $$= $1; }
+ | join_table_parens { $$= $1; }
+ | table_reference_list_parens { $$= $1; }
;
-table_primary_ident:
- {
- DBUG_ASSERT(Select);
- SELECT_LEX *sel= Select;
- sel->table_join_options= 0;
- }
- table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition
- {
- if (unlikely(!($$= Select->add_table_to_list(thd, $2, $5,
- Select->get_table_join_options(),
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- Select->
- pop_index_hints(),
- $3))))
- MYSQL_YYABORT;
- TABLE_LIST *tl= $$;
- Select->add_joined_table(tl);
- if ($4)
- tl->vers_conditions= Lex->vers_conditions;
- }
- ;
-
-
-
-/*
- Represents a flattening of the following rules from the SQL:2003
- standard. This sub-rule corresponds to the sub-rule
- <table primary> ::= ... | <derived table> [ AS ] <correlation name>
-
- <derived table> ::= <table subquery>
- <table subquery> ::= <subquery>
- <subquery> ::= <left paren> <query expression> <right paren>
- <query expression> ::= [ <with clause> ] <query expression body>
-
- For the time being we use the non-standard rule
- select_derived_union which is a compromise between the standard
- and our parser. Possibly this rule could be replaced by our
- query_expression_body.
-*/
-
-table_primary_derived:
- '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias
+table_reference_list_parens:
+ '(' table_reference_list_parens ')' { $$= $2; }
+ | '(' nested_table_reference_list ')'
{
- /* Use $2 instead of Lex->current_select as derived table will
- alter value of Lex->current_select. */
- if (!($3 || $6) && $2->embedding &&
- !$2->embedding->nested_join->join_list.elements)
- {
- /* we have a derived table ($3 == NULL) but no alias,
- Since we are nested in further parentheses so we
- can pass NULL to the outer level parentheses
- Permits parsing of "((((select ...))) as xyz)" */
- $$= 0;
- }
- else if (!$3)
- {
- /* Handle case of derived table, alias may be NULL if there
- are no outer parentheses, add_table_to_list() will throw
- error in this case */
- LEX *lex=Lex;
- lex->check_automatic_up(UNSPECIFIED_TYPE);
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel->master_unit();
- lex->current_select= sel= unit->outer_select();
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- if (unlikely(!($$= sel->add_table_to_list(thd,
- ti, $6, 0,
- TL_READ,
- MDL_SHARED_READ))))
- MYSQL_YYABORT;
- sel->add_joined_table($$);
- lex->pop_context();
- lex->nest_level--;
- }
- else if (unlikely($6 != NULL))
- {
- /*
- Tables with or without joins within parentheses cannot
- have aliases, and we ruled out derived tables above.
- */
- thd->parse_error();
+ if (!($$= Select->end_nested_join(thd)))
MYSQL_YYABORT;
- }
- else
- {
- /* nested join: FROM (t1 JOIN t2 ...),
- nest_level is the same as in the outer query */
- $$= $3;
- }
- /*
- Fields in derived table can be used in upper select in
- case of merge. We do not add HAVING fields because we do
- not merge such derived. We do not add union because
- also do not merge them
- */
- if ($$ && $$->derived &&
- !$$->derived->first_select()->next_select())
- $$->select_lex->add_where_field($$->derived->first_select());
- if ($5)
- {
- MYSQL_YYABORT_UNLESS(!$3);
- $$->vers_conditions= Lex->vers_conditions;
- }
}
- /* Represents derived table with WITH clause */
- | '(' get_select_lex subselect_start
- with_clause query_expression_body
- subselect_end ')' opt_for_system_time_clause opt_table_alias
- {
- LEX *lex=Lex;
- SELECT_LEX *sel= $2;
- SELECT_LEX_UNIT *unit= $5->master_unit();
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- $5->set_with_clause($4);
- lex->current_select= sel;
- if (unlikely(!($$= sel->add_table_to_list(lex->thd,
- ti, $9, 0,
- TL_READ,
- MDL_SHARED_READ))))
- MYSQL_YYABORT;
- sel->add_joined_table($$);
- if ($8)
- $$->vers_conditions= Lex->vers_conditions;
- }
;
-/*
- This rule accepts just about anything. The reason is that we have
- empty-producing rules in the beginning of rules, in this case
- subselect_start. This forces bison to take a decision which rules to
- reduce by long before it has seen any tokens. This approach ties us
- to a very limited class of parseable languages, and unfortunately
- SQL is not one of them. The chosen 'solution' was this rule, which
- produces just about anything, even complete bogus statements, for
- instance ( table UNION SELECT 1 ).
- Fortunately, we know that the semantic value returned by
- select_derived is NULL if it contained a derived table, and a pointer to
- the base table's TABLE_LIST if it was a base table. So in the rule
- regarding union's, we throw a parse error manually and pretend it
- was bison that did it.
-
- Also worth noting is that this rule concerns query expressions in
- the from clause only. Top level select statements and other types of
- subqueries have their own union rules.
-*/
-select_derived_union:
- select_derived
- | select_derived union_order_or_limit
+nested_table_reference_list:
+ table_ref ',' table_ref
{
- if (unlikely($1))
- {
- thd->parse_error();
+ if (Select->init_nested_join(thd))
MYSQL_YYABORT;
- }
- }
- | select_derived union_head_non_top
- {
- if (unlikely($1))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- union_list_derived_part2
- | derived_simple_table opt_select_lock_type
- | derived_simple_table order_or_limit opt_select_lock_type
- | derived_simple_table opt_select_lock_type union_list_derived
- ;
-
-union_list_derived_part2:
- query_term_union_not_ready { Lex->pop_context(); }
- | query_term_union_ready { Lex->pop_context(); }
- | query_term_union_ready { Lex->pop_context(); } union_list_derived
- ;
-
-union_list_derived:
- union_head_non_top union_list_derived_part2
- ;
-
-
-/* The equivalent of select_init2 for nested queries. */
-select_init2_derived:
- select_part2_derived
- {
- Select->set_braces(0);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
+ $$= $1->embedding;
}
- ;
-
-/* The equivalent of select_part2 for nested queries. */
-select_part2_derived:
+ | nested_table_reference_list ',' table_ref
{
- LEX *lex= Lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->linkage != UNION_TYPE)
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- }
- opt_query_expression_options select_item_list
- {
- Select->parsing_place= NO_MATTER;
+ Select->add_joined_table($3);
+ $$= $1;
}
;
-/* handle contents of parentheses in join expression */
-select_derived:
- get_select_lex_derived derived_table_list
+join_table_parens:
+ '(' join_table_parens ')' { $$= $2; }
+ | '(' join_table ')'
{
LEX *lex= Lex;
- /* for normal joins, $2 != NULL and end_nested_join() != NULL,
- for derived tables, both must equal NULL */
-
- if (unlikely(!($$= $1->end_nested_join(lex->thd)) && $2))
- MYSQL_YYABORT;
- if (unlikely(!$2 && $$))
+ if (!($$= lex->current_select->nest_last_join(thd)))
{
thd->parse_error();
MYSQL_YYABORT;
@@ -11995,86 +11866,59 @@ select_derived:
}
;
-derived_simple_table:
- derived_query_specification { $$= $1; }
- | derived_table_value_constructor { $$= $1; }
- ;
-/*
- Similar to query_specification, but for derived tables.
- Example: the inner parenthesized SELECT in this query:
- SELECT * FROM (SELECT * FROM t1);
-*/
-derived_query_specification:
- SELECT_SYM select_derived_init select_derived2
- {
- if ($2)
- Select->set_braces(1);
- $$= NULL;
- }
- ;
-derived_table_value_constructor:
- VALUES
- {
- Lex->tvc_start();
- }
- values_list
+table_primary_ident:
+ table_ident opt_use_partition opt_for_system_time_clause
+ opt_table_alias_clause opt_key_definition
{
- if (Lex->tvc_finalize_derived())
+ SELECT_LEX *sel= Select;
+ sel->table_join_options= 0;
+ if (!($$= Select->add_table_to_list(thd, $1, $4,
+ Select->get_table_join_options(),
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type,
+ Select->pop_index_hints(),
+ $2)))
MYSQL_YYABORT;
- $$= NULL;
+ TABLE_LIST *tl= $$;
+ if ($3)
+ tl->vers_conditions= Lex->vers_conditions;
}
;
-select_derived2:
- {
- LEX *lex= Lex;
- lex->derived_tables|= DERIVED_SUBQUERY;
- if (unlikely(!lex->expr_allows_subselect ||
- lex->sql_command == (int)SQLCOM_PURGE))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
- unlikely(mysql_new_select(lex, 1, NULL)))
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->linkage= DERIVED_TABLE_TYPE;
- lex->current_select->parsing_place= SELECT_LIST;
- }
- select_options select_item_list
- {
- Select->parsing_place= NO_MATTER;
- }
- opt_table_expression
- ;
+/*
+ Represents a flattening of the following rules from the SQL:2003
+ standard. This sub-rule corresponds to the sub-rule
+ <table primary> ::= ... | <derived table> [ AS ] <correlation name>
-get_select_lex:
- /* Empty */ { $$= Select; }
- ;
+ <derived table> ::= <table subquery>
+ <table subquery> ::= <subquery>
+ <subquery> ::= <left paren> <query expression> <right paren>
+ <query expression> ::= [ <with clause> ] <query expression body>
-get_select_lex_derived:
- get_select_lex
+ For the time being we use the non-standard rule
+ select_derived_union which is a compromise between the standard
+ and our parser. Possibly this rule could be replaced by our
+ query_expression_body.
+*/
+
+table_primary_derived:
+ query_primary_parens opt_for_system_time_clause table_alias_clause
{
- LEX *lex= Lex;
- if (unlikely($1->init_nested_join(lex->thd)))
- MYSQL_YYABORT;
+ if (!($$= Lex->parsed_derived_select($1, $2, $3)))
+ YYABORT;
}
- ;
-
-select_derived_init:
+ | '('
+ query_expression
+ ')' opt_for_system_time_clause table_alias_clause
{
- LEX *lex= Lex;
-
- TABLE_LIST *embedding= lex->current_select->embedding;
- $$= embedding &&
- !embedding->nested_join->join_list.elements;
- /* return true if we are deeply nested */
+ if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
+ YYABORT;
}
;
+
opt_outer:
/* empty */ {}
| OUTER {}
@@ -12205,9 +12049,14 @@ table_alias:
| '='
;
-opt_table_alias:
+opt_table_alias_clause:
/* empty */ { $$=0; }
- | table_alias ident_table_alias
+
+ | table_alias_clause { $$= $1; }
+ ;
+
+table_alias_clause:
+ table_alias ident_table_alias
{
$$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING));
if (unlikely($$ == NULL))
@@ -12303,7 +12152,7 @@ olap_opt:
SQL-2003: GROUP BY ... CUBE(col1, col2, col3)
*/
LEX *lex=Lex;
- if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE))
+ if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE",
"global union parameters"));
lex->current_select->olap= CUBE_TYPE;
@@ -12320,7 +12169,7 @@ olap_opt:
SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3)
*/
LEX *lex= Lex;
- if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE))
+ if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
"global union parameters"));
lex->current_select->olap= ROLLUP_TYPE;
@@ -12380,7 +12229,7 @@ opt_window_partition_clause:
opt_window_order_clause:
/* empty */ { }
- | ORDER_SYM BY order_list
+ | ORDER_SYM BY order_list { Select->order_list= *($3); }
;
opt_window_frame_clause:
@@ -12504,70 +12353,35 @@ alter_order_item:
opt_order_clause:
/* empty */
+ { $$= NULL; }
| order_clause
+ { $$= $1; }
;
order_clause:
ORDER_SYM BY
{
- LEX *lex=Lex;
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel-> master_unit();
- if (unlikely(sel->linkage != GLOBAL_OPTIONS_TYPE &&
- sel->olap != UNSPECIFIED_OLAP_TYPE &&
- (sel->linkage != UNION_TYPE || sel->braces)))
- {
- my_error(ER_WRONG_USAGE, MYF(0),
- "CUBE/ROLLUP", "ORDER BY");
- MYSQL_YYABORT;
- }
- if (lex->sql_command != SQLCOM_ALTER_TABLE &&
- !unit->fake_select_lex)
- {
- /*
- A query of the of the form (SELECT ...) ORDER BY order_list is
- executed in the same way as the query
- SELECT ... ORDER BY order_list
- unless the SELECT construct contains ORDER BY or LIMIT clauses.
- Otherwise we create a fake SELECT_LEX if it has not been
- created yet.
- */
- SELECT_LEX *first_sl= unit->first_select();
- if (unlikely(!unit->is_unit_op() &&
- (first_sl->order_list.elements ||
- first_sl->select_limit) &&
- unit->add_fake_select_lex(thd)))
- MYSQL_YYABORT;
- }
- if (sel->master_unit()->is_unit_op() && !sel->braces)
- {
- /*
- At this point we don't know yet whether this is the last
- select in union or not, but we move ORDER BY to
- fake_select_lex anyway. If there would be one more select
- in union mysql_new_select will correctly throw error.
- */
- DBUG_ASSERT(sel->master_unit()->fake_select_lex);
- lex->current_select= sel->master_unit()->fake_select_lex;
- }
+ thd->where= "ORDER clause";
}
order_list
{
-
+ $$= $4;
}
;
order_list:
order_list ',' order_ident order_dir
{
- if (unlikely(add_order_to_list(thd, $3,(bool) $4)))
- MYSQL_YYABORT;
- }
+ $$= $1;
+ if (add_to_list(thd, *$$, $3,(bool) $4))
+ MYSQL_YYABORT;
+ }
| order_ident order_dir
{
- if (unlikely(add_order_to_list(thd, $1,(bool) $2)))
+ $$= new (thd->mem_root) SQL_I_List<ORDER>();
+ if (add_to_list(thd, *$$, $1, (bool) $2))
MYSQL_YYABORT;
- }
+ }
;
order_dir:
@@ -12577,63 +12391,61 @@ order_dir:
;
opt_limit_clause:
- /* empty */ {}
- | limit_clause {}
+ /* empty */
+ { $$.empty(); }
+ | limit_clause
+ { $$= $1; }
;
-limit_clause_init:
- LIMIT
- {
- SELECT_LEX *sel= Select;
- if (sel->master_unit()->is_unit_op() && !sel->braces)
- {
- /* Move LIMIT that belongs to UNION to fake_select_lex */
- Lex->current_select= sel->master_unit()->fake_select_lex;
- DBUG_ASSERT(Select);
- }
- }
- ;
-
limit_clause:
- limit_clause_init limit_options
+ LIMIT limit_options
{
- SELECT_LEX *sel= Select;
- if (!sel->select_limit->basic_const_item() ||
- sel->select_limit->val_int() > 0)
+ $$= $2;
+ if (!$$.select_limit->basic_const_item() ||
+ $$.select_limit->val_int() > 0)
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
- | limit_clause_init limit_options
+ | LIMIT limit_options
ROWS_SYM EXAMINED_SYM limit_rows_option
{
+ $$= $2;
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
- | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option
+ | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option
{
+ $$.select_limit= 0;
+ $$.offset_limit= 0;
+ $$.explicit_limit= 1;
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
;
+opt_global_limit_clause:
+ opt_limit_clause
+ {
+ Select->explicit_limit= $1.explicit_limit;
+ Select->select_limit= $1.select_limit;
+ Select->offset_limit= $1.offset_limit;
+ }
+
limit_options:
limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= 0;
- sel->explicit_limit= 1;
+ $$.select_limit= $1;
+ $$.offset_limit= 0;
+ $$.explicit_limit= 1;
}
| limit_option ',' limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $3;
- sel->offset_limit= $1;
- sel->explicit_limit= 1;
+ $$.select_limit= $3;
+ $$.offset_limit= $1;
+ $$.explicit_limit= 1;
}
| limit_option OFFSET_SYM limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= $3;
- sel->explicit_limit= 1;
+ $$.select_limit= $1;
+ $$.offset_limit= $3;
+ $$.explicit_limit= 1;
}
;
@@ -12696,6 +12508,77 @@ delete_limit_clause:
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
;
+opt_order_limit_lock:
+ /* empty */
+ { $$= NULL; }
+ | order_or_limit
+ {
+ $$= $1;
+ $$->lock.empty();
+ }
+ | order_or_limit select_lock_type
+ {
+ $$= $1;
+ $$->lock= $2;
+ }
+ | select_lock_type
+ {
+ $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ $$->order_list= NULL;
+ $$->limit.empty();
+ $$->lock= $1;
+ }
+ ;
+query_expression_tail:
+ opt_order_limit_lock
+ ;
+
+opt_procedure_or_into:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | procedure_clause opt_select_lock_type
+ {
+ $$= $2;
+ }
+ | into opt_select_lock_type
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
+ "<select expression> INTO <destination>;",
+ "'SELECT <select list> INTO <destination>"
+ " FROM...'");
+ $$= $2;
+ }
+ ;
+
+
+order_or_limit:
+ order_clause opt_limit_clause
+ {
+ $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ $$->order_list= $1;
+ $$->limit= $2;
+ }
+ | limit_clause
+ {
+ Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ op->order_list= NULL;
+ op->limit= $1;
+ $$->order_list= NULL;
+ $$->limit= $1;
+ }
+ ;
+
+
opt_plus:
/* empty */
| '+'
@@ -12765,14 +12648,11 @@ bool:
| TRUE_SYM { $$= 1; }
| FALSE_SYM { $$= 0; }
-
procedure_clause:
PROCEDURE_SYM ident /* Procedure name */
{
LEX *lex=Lex;
- DBUG_ASSERT(&lex->select_lex == lex->current_select);
-
lex->proc_list.elements=0;
lex->proc_list.first=0;
lex->proc_list.next= &lex->proc_list.first;
@@ -12792,6 +12672,7 @@ procedure_clause:
parameters are reduced.
*/
Lex->expr_allows_subselect= false;
+ Select->options|= OPTION_PROCEDURE_CLAUSE;
}
'(' procedure_list ')'
{
@@ -12875,6 +12756,7 @@ select_outvar:
into:
INTO into_destination
+ {}
;
into_destination:
@@ -13068,10 +12950,11 @@ table_list:
table_name:
table_ident
{
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL,
- TL_OPTION_UPDATING,
- YYPS->m_lock_type,
- YYPS->m_mdl_type)))
+ if (!thd->lex->current_select_or_default()->
+ add_table_to_list(thd, $1, NULL,
+ TL_OPTION_UPDATING,
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -13145,16 +13028,23 @@ insert:
LEX *lex= Lex;
lex->sql_command= SQLCOM_INSERT;
lex->duplicates= DUP_ERROR;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
}
insert_lock_option
opt_ignore insert2
{
Select->set_lock_for_tables($3);
- Lex->current_select= &Lex->select_lex;
+ Lex->current_select= Lex->first_select_lex();
}
insert_field_spec opt_insert_update
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
replace:
@@ -13163,15 +13053,22 @@ replace:
LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
}
replace_lock_option insert2
{
Select->set_lock_for_tables($3);
- Lex->current_select= &Lex->select_lex;
+ Lex->current_select= Lex->first_select_lex();
}
insert_field_spec
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
insert_lock_option:
@@ -13214,15 +13111,14 @@ insert_table:
table_name_with_opt_use_partition
{
LEX *lex=Lex;
- lex->field_list.empty();
+ //lex->field_list.empty();
lex->many_values.empty();
lex->insert_list=0;
};
insert_field_spec:
insert_values {}
- | '(' ')' insert_values {}
- | '(' fields ')' insert_values {}
+ | insert_field_list insert_values {}
| SET
{
LEX *lex=Lex;
@@ -13230,20 +13126,33 @@ insert_field_spec:
unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
+ lex->current_select->parsing_place= NO_MATTER;
}
ident_eq_list
;
+insert_field_list:
+ LEFT_PAREN_ALT opt_fields ')'
+ {
+ Lex->current_select->parsing_place= AFTER_LIST;
+ }
+ ;
+
+opt_fields:
+ /* empty */
+ | fields
+ ;
+
fields:
fields ',' insert_ident
{ Lex->field_list.push_back($3, thd->mem_root); }
| insert_ident { Lex->field_list.push_back($1, thd->mem_root); }
;
+
+
insert_values:
- VALUES values_list {}
- | VALUE_SYM values_list {}
- | create_select_query_expression {}
+ create_select_query_expression {}
;
values_list:
@@ -13393,6 +13302,8 @@ update:
UPDATE_SYM
{
LEX *lex= Lex;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->sql_command= SQLCOM_UPDATE;
lex->duplicates= DUP_ERROR;
@@ -13401,13 +13312,14 @@ update:
SET update_list
{
LEX *lex= Lex;
- if (lex->select_lex.table_list.elements > 1)
+ if (lex->first_select_lex()->table_list.elements > 1)
lex->sql_command= SQLCOM_UPDATE_MULTI;
- else if (unlikely(lex->select_lex.get_table_list()->derived))
+ else if (lex->first_select_lex()->get_table_list()->derived)
{
/* it is single table update and it is update of derived table */
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
- lex->select_lex.get_table_list()->alias.str, "UPDATE");
+ lex->first_select_lex()->get_table_list()->alias.str,
+ "UPDATE");
MYSQL_YYABORT;
}
/*
@@ -13417,7 +13329,14 @@ update:
*/
Select->set_lock_for_tables($3);
}
- opt_where_clause opt_order_clause delete_limit_clause {}
+ opt_where_clause opt_order_clause delete_limit_clause
+ {
+ if ($10)
+ Select->order_list= *($10);
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
update_list:
@@ -13464,9 +13383,11 @@ delete:
mysql_init_select(lex);
YYPS->m_lock_type= TL_WRITE_DEFAULT;
YYPS->m_mdl_type= MDL_SHARED_WRITE;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->ignore= 0;
- lex->select_lex.init_order();
+ lex->first_select_lex()->order_list.empty();
}
delete_part2
;
@@ -13487,6 +13408,7 @@ delete_part2:
| HISTORY_SYM delete_single_table opt_delete_system_time
{
Lex->last_table()->vers_conditions= Lex->vers_conditions;
+ Lex->pop_select(); //main select
}
;
@@ -13510,7 +13432,12 @@ single_multi:
opt_where_clause
opt_order_clause
delete_limit_clause
- opt_select_expressions {}
+ opt_select_expressions
+ {
+ if ($3)
+ Select->order_list= *($3);
+ Lex->pop_select(); //main select
+ }
| table_wild_list
{
mysql_init_multi_delete(Lex);
@@ -13521,6 +13448,9 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| FROM table_alias_ref_list
{
@@ -13532,6 +13462,9 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
;
@@ -13600,9 +13533,9 @@ truncate:
LEX* lex= Lex;
lex->sql_command= SQLCOM_TRUNCATE;
lex->alter_info.reset();
- lex->select_lex.options= 0;
- lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
- lex->select_lex.init_order();
+ lex->first_select_lex()->options= 0;
+ lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED;
+ lex->first_select_lex()->order_list.empty();
YYPS->m_lock_type= TL_WRITE;
YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
@@ -13687,6 +13620,8 @@ show:
LEX *lex=Lex;
lex->wild=0;
lex->ident= null_clex_str;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
lex->create_info.init();
@@ -13694,6 +13629,7 @@ show:
show_param
{
Select->parsing_place= NO_MATTER;
+ Lex->pop_select(); //main select
}
;
@@ -13709,40 +13645,40 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
MYSQL_YYABORT;
}
| opt_full TRIGGERS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TRIGGERS;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
MYSQL_YYABORT;
}
| EVENTS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_EVENTS;
- lex->select_lex.db= $2;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_EVENTS)))
+ lex->first_select_lex()->db= $2;
+ if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
MYSQL_YYABORT;
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
MYSQL_YYABORT;
}
| OPEN_SYM TABLES opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
MYSQL_YYABORT;
}
| PLUGINS_SYM
@@ -13791,12 +13727,13 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
}
- opt_limit_clause
+ opt_global_limit_clause
| RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
- } opt_limit_clause
+ }
+ opt_global_limit_clause
| keys_or_index from_or_in table_ident opt_db opt_where_clause
{
LEX *lex= Lex;
@@ -13838,13 +13775,13 @@ show_param:
LEX_CSTRING var= {STRING_WITH_LEN("error_count")};
(void) create_select_for_variable(thd, &var);
}
- | WARNINGS opt_limit_clause
+ | WARNINGS opt_global_limit_clause
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
- | ERRORS opt_limit_clause
+ | ERRORS opt_global_limit_clause
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
| PROFILES_SYM
{ Lex->sql_command = SQLCOM_SHOW_PROFILES; }
- | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause
+ | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_PROFILE;
@@ -13906,7 +13843,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL,0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0))
MYSQL_YYABORT;
lex->create_info.storage_media= HA_SM_DEFAULT;
}
@@ -13914,7 +13851,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
MYSQL_YYABORT;
lex->table_type= TABLE_TYPE_VIEW;
}
@@ -13922,7 +13859,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
MYSQL_YYABORT;
lex->table_type= TABLE_TYPE_SEQUENCE;
}
@@ -14139,7 +14076,7 @@ describe:
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
lex->sql_command= SQLCOM_SHOW_FIELDS;
- lex->select_lex.db= null_clex_str;
+ lex->first_select_lex()->db= null_clex_str;
lex->verbose= 0;
if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS)))
MYSQL_YYABORT;
@@ -14153,12 +14090,13 @@ describe:
explainable_command
{
LEX *lex=Lex;
- lex->select_lex.options|= SELECT_DESCRIBE;
+ lex->first_select_lex()->options|= SELECT_DESCRIBE;
}
;
explainable_command:
select
+ | select_into
| insert
| replace
| update
@@ -14179,6 +14117,8 @@ analyze_stmt_command:
opt_extended_describe:
EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
+ | EXTENDED_SYM ALL
+ { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; }
| PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
| opt_format_json {}
;
@@ -14221,8 +14161,7 @@ flush:
lex->type= 0;
lex->no_write_to_binlog= $2;
}
- flush_options
- {}
+ flush_options {}
;
flush_options:
@@ -14239,6 +14178,7 @@ flush_options:
opt_table_list opt_flush_lock
{}
| flush_options_list
+ {}
;
opt_flush_lock:
@@ -14434,6 +14374,8 @@ purge_option:
lex->value_list.empty();
lex->value_list.push_front($2, thd->mem_root);
lex->sql_command= SQLCOM_PURGE_BEFORE;
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
;
@@ -14494,7 +14436,7 @@ use:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CHANGE_DB;
- lex->select_lex.db= $2;
+ lex->first_select_lex()->db= $2;
}
;
@@ -14511,6 +14453,9 @@ load:
$2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML");
MYSQL_YYABORT;
}
+ if (lex->main_select_push())
+ MYSQL_YYABORT;
+ mysql_init_select(lex);
}
load_data_lock opt_local INFILE TEXT_STRING_filesystem
{
@@ -14540,7 +14485,11 @@ load:
opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
data_or_xml:
@@ -14738,11 +14687,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- /*
- it is OK only emulate fix_fields, because we need only
- value of constant
- */
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| HEX_STRING
@@ -14751,7 +14695,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| BIN_NUM
@@ -14764,7 +14707,6 @@ hex_or_bin_String:
it is OK only emulate fix_fields, because we need only
value of constant
*/
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
;
@@ -14900,26 +14842,23 @@ NUM_literal:
temporal_literal:
DATE_SYM TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_DATE,
- true))))
+ if (unlikely(!($$= type_handler_newdate.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
| TIME_SYM TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_TIME,
- true))))
+ if (unlikely(!($$= type_handler_time2.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
| TIMESTAMP TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_DATETIME,
- true))))
+ if (unlikely(!($$= type_handler_datetime.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
;
@@ -14935,17 +14874,21 @@ opt_with_clause:
with_clause:
- WITH opt_recursive
+ WITH opt_recursive
{
+ LEX *lex= Lex;
With_clause *with_clause=
new With_clause($2, Lex->curr_with_clause);
if (unlikely(with_clause == NULL))
MYSQL_YYABORT;
- Lex->derived_tables|= DERIVED_WITH;
- Lex->curr_with_clause= with_clause;
+ lex->derived_tables|= DERIVED_WITH;
+ lex->curr_with_clause= with_clause;
with_clause->add_to_list(Lex->with_clauses_list_last_next);
+ if (lex->current_select &&
+ lex->current_select->parsing_place == BEFORE_OPT_LIST)
+ lex->current_select->parsing_place= NO_MATTER;
}
- with_list
+ with_list
{
$$= Lex->curr_with_clause;
Lex->curr_with_clause= Lex->curr_with_clause->pop();
@@ -14974,11 +14917,10 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_name subselect remember_end ')'
+ AS '(' remember_name query_expression remember_end ')'
{
- With_element *elem= new With_element($1, *$2, $7->master_unit());
- if (unlikely(elem == NULL) ||
- unlikely(Lex->curr_with_clause->add_with_element(elem)))
+ With_element *elem= new With_element($1, *$2, $7);
+ if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8)))
MYSQL_YYABORT;
@@ -15917,14 +15859,22 @@ set:
SET
{
LEX *lex=Lex;
+ if (lex->main_select_push())
+ MYSQL_YYABORT;
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
start_option_value_list
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| SET STATEMENT_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
@@ -15934,6 +15884,9 @@ set:
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
lex->stmt_var_list= lex->var_list;
lex->var_list.empty();
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
FOR_SYM verb_clause
{}
@@ -16352,7 +16305,7 @@ table_lock_list:
;
table_lock:
- table_ident opt_table_alias lock_option
+ table_ident opt_table_alias_clause lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
@@ -16397,27 +16350,36 @@ unlock:
*/
handler:
- HANDLER_SYM table_ident OPEN_SYM opt_table_alias
+ HANDLER_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ handler_tail
+ {
+ Lex->pop_select(); //main select
+ }
+
+handler_tail:
+ table_ident OPEN_SYM opt_table_alias_clause
{
LEX *lex= Lex;
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
lex->sql_command = SQLCOM_HA_OPEN;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, $4,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, $3, 0))
MYSQL_YYABORT;
}
- | HANDLER_SYM table_ident_nodb CLOSE_SYM
+ | table_ident_nodb CLOSE_SYM
{
LEX *lex= Lex;
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
lex->sql_command = SQLCOM_HA_CLOSE;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
MYSQL_YYABORT;
}
- | HANDLER_SYM table_ident_nodb READ_SYM
+ | table_ident_nodb READ_SYM
{
LEX *lex=Lex;
if (unlikely(lex->sphead))
@@ -16431,15 +16393,24 @@ handler:
lex->current_select->select_limit= one;
lex->current_select->offset_limit= 0;
lex->limit_rows_examined= 0;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
MYSQL_YYABORT;
}
- handler_read_or_scan opt_where_clause opt_limit_clause
+ handler_read_or_scan opt_where_clause opt_global_limit_clause
{
- Lex->expr_allows_subselect= TRUE;
+ LEX *lex=Lex;
+ lex->expr_allows_subselect= TRUE;
+ if (!lex->current_select->explicit_limit)
+ {
+ Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
+ if (one == NULL)
+ MYSQL_YYABORT;
+ lex->current_select->select_limit= one;
+ lex->current_select->offset_limit= 0;
+ lex->limit_rows_examined= 0;
+ }
/* Stored functions are not supported for HANDLER READ. */
- if (unlikely(Lex->uses_stored_routines()))
+ if (lex->uses_stored_routines())
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"stored functions in HANDLER ... READ");
@@ -17075,212 +17046,27 @@ release:
*/
unit_type_decl:
- UNION_SYM
- { $$= UNION_TYPE; }
+ UNION_SYM union_option
+ { $$.unit_type= UNION_TYPE; $$.distinct= $2; }
| INTERSECT_SYM
- { $$= INTERSECT_TYPE; }
+ { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
| EXCEPT_SYM
- { $$= EXCEPT_TYPE; }
-
-
-union_clause:
- /* empty */ {}
- | union_list
- ;
-
-union_list:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE)))
- MYSQL_YYABORT;
- }
- union_list_part2
- {
- /*
- Remove from the name resolution context stack the context of the
- last select in the union.
- */
- Lex->pop_context();
- }
- ;
-
-union_list_view:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE)))
- MYSQL_YYABORT;
- }
- query_expression_body_view
- {
- Lex->pop_context();
- }
- ;
+ { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
-union_order_or_limit:
- {
- LEX *lex= thd->lex;
- DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel->master_unit();
- SELECT_LEX *fake= unit->fake_select_lex;
- if (fake)
- {
- fake->no_table_names_allowed= 1;
- lex->current_select= fake;
- }
- thd->where= "global ORDER clause";
- }
- order_or_limit
- {
- thd->lex->current_select->no_table_names_allowed= 0;
- thd->where= "";
- }
- ;
-
-order_or_limit:
- order_clause opt_limit_clause
- | limit_clause
- ;
/*
Start a UNION, for non-top level query expressions.
*/
-union_head_non_top:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, FALSE)))
- MYSQL_YYABORT;
- }
- ;
-
union_option:
/* empty */ { $$=1; }
| DISTINCT { $$=1; }
| ALL { $$=0; }
;
-simple_table:
- query_specification { $$= $1; }
- | table_value_constructor { $$= $1; }
- ;
-
-table_value_constructor:
- VALUES
- {
- Lex->tvc_start();
- }
- values_list
- {
- $$= Lex->current_select;
- if (Lex->tvc_finalize())
- MYSQL_YYABORT;
- }
- ;
-
-/*
- Corresponds to the SQL Standard
- <query specification> ::=
- SELECT [ <set quantifier> ] <select list> <table expression>
-
- Notes:
- - We allow more options in addition to <set quantifier>
- - <table expression> is optional in MariaDB
-*/
-query_specification:
- SELECT_SYM select_init2_derived opt_table_expression
- {
- $$= Lex->current_select->master_unit()->first_select();
- }
- ;
-
-query_term_union_not_ready:
- simple_table order_or_limit opt_select_lock_type { $$= $1; }
- | '(' select_paren_derived ')' union_order_or_limit { $$= $2; }
- ;
-
-query_term_union_ready:
- simple_table opt_select_lock_type { $$= $1; }
- | '(' select_paren_derived ')' { $$= $2; }
- ;
-
-query_expression_body:
- query_term_union_not_ready { $$= $1; }
- | query_term_union_ready { $$= $1; }
- | query_term_union_ready union_list_derived { $$= $1; }
- ;
-
-/* Corresponds to <query expression> in the SQL:2003 standard. */
-subselect:
- subselect_start opt_with_clause query_expression_body subselect_end
- {
- $3->set_with_clause($2);
- $$= $3;
- }
- ;
-
-subselect_start:
- {
- LEX *lex=Lex;
- if (unlikely(!lex->expr_allows_subselect ||
- lex->sql_command == (int)SQLCOM_PURGE))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- /*
- we are making a "derived table" for the parenthesis
- as we need to have a lex level to fit the union
- after the parenthesis, e.g.
- (SELECT .. ) UNION ... becomes
- SELECT * FROM ((SELECT ...) UNION ...)
- */
- if (unlikely(mysql_new_select(Lex, 1, NULL)))
- MYSQL_YYABORT;
- }
- ;
-
-subselect_end:
- {
- LEX *lex=Lex;
-
- lex->check_automatic_up(UNSPECIFIED_TYPE);
- lex->pop_context();
- SELECT_LEX *child= lex->current_select;
- lex->current_select = lex->current_select->return_after_parsing();
- lex->nest_level--;
- lex->current_select->n_child_sum_items += child->n_sum_items;
- /*
- A subselect can add fields to an outer select. Reserve space for
- them.
- */
- lex->current_select->select_n_where_fields+=
- child->select_n_where_fields;
-
- /*
- Aggregate functions in having clause may add fields to an outer
- select. Count them also.
- */
- lex->current_select->select_n_having_items+=
- child->select_n_having_items;
- }
- ;
-
-opt_query_expression_options:
- /* empty */
- | query_expression_option_list
- ;
-
-query_expression_option_list:
- query_expression_option_list query_expression_option
- | query_expression_option
- ;
-
query_expression_option:
STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
| HIGH_PRIORITY
{
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
YYPS->m_mdl_type= MDL_SHARED_READ;
Select->options|= SELECT_HIGH_PRIORITY;
@@ -17288,18 +17074,8 @@ query_expression_option:
| DISTINCT { Select->options|= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT
- {
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
- Select->options|= OPTION_BUFFER_RESULT;
- }
- | SQL_CALC_FOUND_ROWS
- {
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
- Select->options|= OPTION_FOUND_ROWS;
- }
+ | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
+ | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
| ALL { Select->options|= SELECT_ALL; }
;
@@ -17387,35 +17163,14 @@ view_select:
lex->parsing_options.allows_variable= FALSE;
lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr();
}
- opt_with_clause query_expression_body_view view_check_option
+ query_expression
+ view_check_option
{
- LEX *lex= Lex;
- size_t len= YYLIP->get_cpp_ptr() - lex->create_view->select.str;
- void *create_view_select= thd->memdup(lex->create_view->select.str, len);
- lex->create_view->select.length= len;
- lex->create_view->select.str= (char *) create_view_select;
- trim_whitespace(thd->charset(),
- &lex->create_view->select);
- lex->create_view->check= $4;
- lex->parsing_options.allows_variable= TRUE;
- lex->current_select->set_with_clause($2);
+ if (Lex->parsed_create_view($2, $3))
+ MYSQL_YYABORT;
}
;
-/*
- SQL Standard <query expression body> for VIEWs.
- Does not include INTO and PROCEDURE clauses.
-*/
-query_expression_body_view:
- SELECT_SYM select_options_and_item_list select_init3_view
- | table_value_constructor
- | table_value_constructor union_order_or_limit
- | table_value_constructor union_list_view
- | '(' select_paren_view ')'
- | '(' select_paren_view ')' union_order_or_limit
- | '(' select_paren_view ')' union_list_view
- ;
-
view_check_option:
/* empty */ { $$= VIEW_CHECK_NONE; }
| WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; }
@@ -17514,11 +17269,10 @@ trigger_tail:
sp_proc_stmt alternatives are not saving/restoring LEX, so
lex->query_tables can be wiped out.
*/
- if (unlikely(!lex->select_lex.
- add_table_to_list(thd, $10, (LEX_CSTRING*) 0,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_NO_WRITE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $10, (LEX_CSTRING*) 0,
+ TL_OPTION_UPDATING, TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index 8f98cfa3694..d4838590075 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -189,6 +189,20 @@ void ORAerror(THD *thd, const char *s)
uint offset;
} sp_cursor_name_and_offset;
vers_history_point_t vers_history_point;
+ struct
+ {
+ enum sub_select_type unit_type;
+ bool distinct;
+ } unit_operation;
+ struct
+ {
+ SELECT_LEX *first;
+ SELECT_LEX *prev_last;
+ } select_list;
+ SQL_I_List<ORDER> *select_order;
+ Lex_select_lock select_lock;
+ Lex_select_limit select_limit;
+ Lex_order_limit_lock *order_limit_lock;
/* pointers */
Create_field *create_field;
@@ -234,6 +248,7 @@ void ORAerror(THD *thd, const char *s)
handlerton *db_type;
st_select_lex *select_lex;
+ st_select_lex_unit *select_lex_unit;
struct p_elem_val *p_elem_value;
class Window_frame *window_frame;
class Window_frame_bound *window_frame_bound;
@@ -243,7 +258,6 @@ void ORAerror(THD *thd, const char *s)
/* enums */
enum enum_sp_suid_behaviour sp_suid;
enum enum_view_suid view_suid;
- enum sub_select_type unit_type;
enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name;
enum Diagnostics_information::Which_area diag_area;
@@ -282,10 +296,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 63 shift/reduce conflicts.
+ Currently there are 59 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 63
+%expect 59
/*
Comments for TOKENS.
@@ -436,6 +450,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token LEADING /* SQL-2003-R */
%token LEAVE_SYM
%token LEFT /* SQL-2003-R */
+%token LEFT_PAREN_ALT /* INTERNAL */
+%token LEFT_PAREN_WITH /* INTERNAL */
+%token LEFT_PAREN_LIKE /* INTERNAL */
%token LEX_HOSTNAME
%token LIKE /* SQL-2003-R */
%token LIMIT
@@ -1181,7 +1198,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
NCHAR_STRING
%type <lex_str_ptr>
- opt_table_alias
+ opt_table_alias_clause
+ table_alias_clause
%type <ident_cli>
IDENT
@@ -1248,7 +1266,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_temporary all_or_any opt_distinct opt_glimit_clause
opt_ignore_leaves fulltext_options union_option
opt_not
- select_derived_init transaction_access_mode_types
+ transaction_access_mode_types
opt_natural_language_mode opt_query_expansion
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
@@ -1371,11 +1389,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
join_table_list join_table
table_factor table_ref esc_table_ref
table_primary_ident table_primary_derived
- select_derived derived_table_list
- select_derived_union
- derived_simple_table
- derived_query_specification
- derived_table_value_constructor
+ derived_table_list table_reference_list_parens
+ nested_table_reference_list join_table_parens
%type <date_time_type> date_time_type;
%type <interval> interval
@@ -1411,14 +1426,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
UNDERSCORE_CHARSET
%type <select_lex> subselect
- get_select_lex get_select_lex_derived
- simple_table
query_specification
- query_term_union_not_ready
- query_term_union_ready
- query_expression_body
- select_paren_derived
table_value_constructor
+ simple_table
+ query_primary
+ query_primary_parens
+ select_into_query_specification
+
+
+%type <select_lex_unit>
+ query_specification_start
+ query_expression_body
+ query_expression
+ query_expression_unit
%type <boolfunc2creator> comp_op
@@ -1430,11 +1450,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <virtual_column> opt_check_constraint check_constraint virtual_column_func
column_default_expr
-%type <unit_type> unit_type_decl
+
+%type <unit_operation> unit_type_decl
+
+%type <select_lock>
+ opt_procedure_or_into
+ opt_select_lock_type
+ select_lock_type
+ opt_lock_wait_timeout_new
+
+%type <select_limit> opt_limit_clause limit_clause limit_options
+
+%type <order_limit_lock>
+ query_expression_tail
+ order_or_limit
+ opt_order_limit_lock
+
+%type <select_order> opt_order_clause order_clause order_list
%type <NONE>
analyze_stmt_command
- query verb_clause create change select do drop insert replace insert2
+ query verb_clause create change select select_into
+ do drop insert replace insert2
insert_values update delete truncate rename compound_statement
show describe load alter optimize keycache preload flush
reset purge commit rollback savepoint release
@@ -1451,7 +1488,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
preload_list preload_list_or_parts preload_keys preload_keys_parts
select_item_list select_item values_list no_braces
no_braces_with_names opt_values_with_names values_with_names
- opt_limit_clause delete_limit_clause fields opt_values values
+ delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
opt_ignore opt_column opt_restrict
@@ -1471,9 +1508,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
- union_clause union_list
- subselect_start opt_and charset
- subselect_end select_var_list select_var_list_init help
+ opt_and charset
+ select_var_list select_var_list_init help
opt_extended_describe shutdown
opt_format_json
prepare prepare_src execute deallocate
@@ -1624,8 +1660,8 @@ rule: <-- starts at col 1
query:
END_OF_INPUT
{
- if (likely(!thd->bootstrap) &&
- unlikely(!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
+ if (!thd->bootstrap &&
+ (!(thd->lex->lex_options & OPTION_LEX_FOUND_COMMENT)))
my_yyabort_error((ER_EMPTY_QUERY, MYF(0)));
thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
@@ -1720,6 +1756,7 @@ statement:
| rollback
| savepoint
| select
+ | select_into
| set
| set_assign
| signal_stmt
@@ -2074,17 +2111,22 @@ connection_name:
/* create a table */
create:
- create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
+ create_or_replace opt_temporary TABLE_SYM opt_if_not_exists
{
LEX *lex= thd->lex;
lex->create_info.init();
- if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2,
- $1 | $4)))
+ if (lex->main_select_push())
+ MYSQL_YYABORT;
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
+ if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
MYSQL_YYABORT;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ }
+ table_ident
+ {
+ LEX *lex= thd->lex;
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
lex->alter_info.reset();
/*
@@ -2099,7 +2141,6 @@ create:
create_body
{
LEX *lex= thd->lex;
- lex->current_select= &lex->select_lex;
if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
!lex->create_info.db_type)
{
@@ -2108,22 +2149,24 @@ create:
ER_WARN_USING_OTHER_HANDLER,
ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
hton_name(lex->create_info.db_type)->str,
- $5->table.str);
+ $6->table.str);
}
create_table_set_open_action_and_adjust_tables(lex);
+ Lex->pop_select(); //main select
}
| create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
{
LEX *lex= thd->lex;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->create_info.init();
if (unlikely(lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2,
$1 | $4)))
MYSQL_YYABORT;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
/*
@@ -2146,8 +2189,9 @@ create:
if (unlikely(lex->create_info.seq_create_info->check_and_adjust(1)))
{
my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
- lex->select_lex.table_list.first->db.str,
- lex->select_lex.table_list.first->table_name.str);
+ lex->first_select_lex()->table_list.first->db.str,
+ lex->first_select_lex()->table_list.first->
+ table_name.str);
MYSQL_YYABORT;
}
@@ -2160,10 +2204,8 @@ create:
Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
Lex->create_info.sequence= 1;
- lex->current_select= &lex->select_lex;
- if (unlikely((lex->create_info.used_fields &
- HA_CREATE_USED_ENGINE) &&
- !lex->create_info.db_type))
+ if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
+ !lex->create_info.db_type)
{
lex->create_info.use_default_db_type(thd);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -2173,44 +2215,69 @@ create:
$5->table.str);
}
create_table_set_open_action_and_adjust_tables(lex);
+ Lex->pop_select(); //main select
}
- | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
+ | create_or_replace opt_unique INDEX_SYM opt_if_not_exists
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ ident
opt_key_algorithm_clause
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($8)))
+ if (Lex->add_create_index_prepare($9))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, $6, $1 | $4)))
+ if (Lex->add_create_index($2, &$6, $7, $1 | $4))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout normal_key_options
- opt_index_lock_algorithm { }
- | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace fulltext INDEX_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ opt_if_not_exists ident
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($7)))
+ if (Lex->add_create_index_prepare($8))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF,
- $1 | $4)))
+ if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout fulltext_key_options
- opt_index_lock_algorithm { }
- | create_or_replace spatial INDEX_SYM opt_if_not_exists ident
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace spatial INDEX_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ opt_if_not_exists ident
ON table_ident
{
- if (unlikely(Lex->add_create_index_prepare($7)))
+ if (Lex->add_create_index_prepare($8))
MYSQL_YYABORT;
- if (unlikely(Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF,
- $1 | $4)))
+ if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
MYSQL_YYABORT;
}
'(' key_list ')' opt_lock_wait_timeout spatial_key_options
- opt_index_lock_algorithm { }
+ opt_index_lock_algorithm
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
opt_create_database_options
{
@@ -2219,52 +2286,94 @@ create:
$1 | $3)))
MYSQL_YYABORT;
lex->name= $4;
+ Lex->pop_select(); //main select
}
| create_or_replace definer_opt opt_view_suid VIEW_SYM
opt_if_not_exists table_ident
{
- if (unlikely(Lex->add_create_view(thd, $1 | $5,
- DTYPE_ALGORITHM_UNDEFINED, $3,
- $6)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_create_view(thd, $1 | $5,
+ DTYPE_ALGORITHM_UNDEFINED, $3, $6))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM
opt_if_not_exists table_ident
{
- if (unlikely(Lex->add_create_view(thd, $1 | $6, $2, $4, $7)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt TRIGGER_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
trigger_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt PROCEDURE_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
sp_tail_standalone
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer_opt EVENT_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
event_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace definer FUNCTION_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
sf_tail_standalone
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace no_definer FUNCTION_SYM
- { Lex->create_info.set($1); }
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ Lex->create_info.set($1);
+ }
create_function_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->create_info.set($1);
Lex->udf.type= UDFTYPE_AGGREGATE;
}
udf_tail
- { }
+ {
+ Lex->pop_select(); //main select
+ }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
opt_require_clause opt_resource_options
{
@@ -2887,7 +2996,7 @@ clear_privileges:
lex->columns.empty();
lex->grant= lex->grant_tot_col= 0;
lex->all_privileges= 0;
- lex->select_lex.db= null_clex_str;
+ lex->first_select_lex()->db= null_clex_str;
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char *)&(lex->mqh),sizeof(lex->mqh));
@@ -3517,7 +3626,7 @@ raise_stmt:
signal_stmt:
SIGNAL_SYM signal_value opt_set_signal_information
{
- if (unlikely(Lex->add_signal_statement(thd, $2)))
+ if (Lex->add_signal_statement(thd, $2))
MYSQL_YYABORT;
}
;
@@ -3964,7 +4073,9 @@ sp_proc_stmt_return:
;
reset_lex_expr:
- { Lex->sphead->reset_lex(thd); } expr { $$= $2; }
+ { Lex->sphead->reset_lex(thd); }
+ expr
+ { $$= $2; }
;
sp_proc_stmt_exit:
@@ -3980,14 +4091,14 @@ sp_proc_stmt_exit:
}
| EXIT_SYM WHEN_SYM reset_lex_expr
{
- if (unlikely(Lex->sp_exit_statement(thd, $3)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (Lex->sp_exit_statement(thd, $3) ||
+ Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
| EXIT_SYM label_ident WHEN_SYM reset_lex_expr
{
- if (unlikely(Lex->sp_exit_statement(thd, &$2, $4)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (Lex->sp_exit_statement(thd, &$2, $4) ||
+ Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
;
@@ -4005,14 +4116,14 @@ sp_proc_stmt_continue:
}
| CONTINUE_SYM WHEN_SYM reset_lex_expr
{
- if (unlikely(Lex->sp_continue_statement(thd, $3)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (Lex->sp_continue_statement(thd, $3) ||
+ Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
| CONTINUE_SYM label_ident WHEN_SYM reset_lex_expr
{
- if (unlikely(Lex->sp_continue_statement(thd, &$2, $4)) ||
- unlikely(Lex->sphead->restore_lex(thd)))
+ if (Lex->sp_continue_statement(thd, &$2, $4) ||
+ Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
;
@@ -4071,7 +4182,7 @@ assignment_source_expr:
$$->sp_lex_in_use= true;
$$->set_item_and_free_list($3, thd->free_list);
thd->free_list= NULL;
- if (unlikely($$->sphead->restore_lex(thd)))
+ if ($$->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
;
@@ -4080,6 +4191,7 @@ for_loop_bound_expr:
assignment_source_lex
{
Lex->sphead->reset_lex(thd, $1);
+ Lex->current_select->parsing_place= FOR_LOOP_BOUND;
}
expr
{
@@ -4089,6 +4201,7 @@ for_loop_bound_expr:
$$->set_item_and_free_list($3, NULL);
if (unlikely($$->sphead->restore_lex(thd)))
MYSQL_YYABORT;
+ Lex->current_select->parsing_place= NO_MATTER;
}
;
@@ -4310,7 +4423,8 @@ case_stmt_body:
{
if (unlikely(Lex->case_stmt_action_expr($2)))
MYSQL_YYABORT;
- if (unlikely(Lex->sphead->restore_lex(thd)))
+
+ if (Lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
simple_when_clause_list
@@ -4602,7 +4716,7 @@ while_body:
LEX *lex= Lex;
if (unlikely(lex->sp_while_loop_expression(thd, $1)))
MYSQL_YYABORT;
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
}
sp_proc_stmts1 END LOOP_SYM
@@ -4625,7 +4739,7 @@ repeat_body:
if (unlikely(i == NULL) ||
unlikely(lex->sphead->add_instr(i)))
MYSQL_YYABORT;
- if (unlikely(lex->sphead->restore_lex(thd)))
+ if (lex->sphead->restore_lex(thd))
MYSQL_YYABORT;
/* We can shortcut the cont_backpatch here */
i->m_cont_dest= ip+1;
@@ -5105,26 +5219,16 @@ size_number:
*/
create_body:
- '(' create_field_list ')'
+ create_field_list_parens
{ Lex->create_info.option_list= NULL; }
opt_create_table_options opt_create_partitioning opt_create_select {}
| opt_create_table_options opt_create_partitioning opt_create_select {}
- /*
- the following rule is redundant, but there's a shift/reduce
- conflict that prevents the rule above from parsing a syntax like
- CREATE TABLE t1 (SELECT 1);
- */
- | '(' create_select_query_specification ')'
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_list {}
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_order_or_limit {}
| create_like
{
Lex->create_info.add(DDL_options_st::OPT_LIKE);
- TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd,
- $1, NULL, 0, TL_READ, MDL_SHARED_READ);
+ TABLE_LIST *src_table= Lex->first_select_lex()->
+ add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ);
if (unlikely(! src_table))
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -5134,7 +5238,7 @@ create_body:
create_like:
LIKE table_ident { $$= $2; }
- | '(' LIKE table_ident ')' { $$= $3; }
+ | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; }
;
opt_create_select:
@@ -5143,23 +5247,20 @@ opt_create_select:
;
create_select_query_expression:
- opt_with_clause SELECT_SYM create_select_part2 opt_table_expression
- create_select_part4
- {
- Select->set_braces(0);
- Select->set_with_clause($1);
+ query_expression
+ {
+ if (Lex->parsed_insert_select($1->first_select()))
+ MYSQL_YYABORT;
}
- union_clause
- | opt_with_clause SELECT_SYM create_select_part2
- create_select_part3_union_not_ready create_select_part4
+ | LEFT_PAREN_WITH with_clause query_expression_body ')'
{
- Select->set_with_clause($1);
+ SELECT_LEX *first_select= $3->first_select();
+ $3->set_with_clause($2);
+ $2->attach_to(first_select);
+
+ if (Lex->parsed_insert_select(first_select))
+ MYSQL_YYABORT;
}
- | '(' create_select_query_specification ')'
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_list {}
- | '(' create_select_query_specification ')'
- { Select->set_braces(1);} union_order_or_limit {}
;
opt_create_partitioning:
@@ -5247,8 +5348,13 @@ partition_entry:
We enter here when opening the frm file to translate
partition info string into part_info data structure.
*/
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ partition
+ {
+ Lex->pop_select(); //main select
}
- partition {}
;
partition:
@@ -5902,56 +6008,6 @@ opt_versioning_interval_start:
End of partition parser part
*/
-create_select_query_specification:
- opt_with_clause SELECT_SYM create_select_part2 create_select_part3
- create_select_part4
- {
- Select->set_with_clause($1);
- }
- ;
-
-create_select_part2:
- {
- LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_INSERT)
- lex->sql_command= SQLCOM_INSERT_SELECT;
- else if (lex->sql_command == SQLCOM_REPLACE)
- lex->sql_command= SQLCOM_REPLACE_SELECT;
- /*
- The following work only with the local list, the global list
- is created correctly in this case
- */
- lex->current_select->table_list.save_and_clear(&lex->save_list);
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- }
- select_options select_item_list
- {
- Select->parsing_place= NO_MATTER;
- }
- ;
-
-create_select_part3:
- opt_table_expression
- | create_select_part3_union_not_ready
- ;
-
-create_select_part3_union_not_ready:
- table_expression order_or_limit
- | order_or_limit
- ;
-
-create_select_part4:
- opt_select_lock_type
- {
- /*
- The following work only with the local list, the global list
- is created correctly in this case
- */
- Lex->current_select->table_list.push_front(&Lex->save_list);
- }
- ;
-
opt_as:
/* empty */ {}
| AS {}
@@ -6169,7 +6225,7 @@ create_table_option:
}
| UNION_SYM opt_equal
{
- Lex->select_lex.table_list.save_and_clear(&Lex->save_list);
+ Lex->first_select_lex()->table_list.save_and_clear(&Lex->save_list);
}
'(' opt_table_list ')'
{
@@ -6178,8 +6234,8 @@ create_table_option:
from the global list.
*/
LEX *lex=Lex;
- lex->create_info.merge_list= lex->select_lex.table_list;
- lex->select_lex.table_list= lex->save_list;
+ lex->create_info.merge_list= lex->first_select_lex()->table_list;
+ lex->first_select_lex()->table_list= lex->save_list;
/*
When excluding union list from the global list we assume that
elements of the former immediately follow elements which represent
@@ -6380,6 +6436,13 @@ create_field_list:
}
;
+create_field_list_parens:
+ LEFT_PAREN_ALT field_list ')'
+ {
+ Lex->create_last_non_select_table= Lex->last_table();
+ }
+ ;
+
field_list:
field_list_item
| field_list ',' field_list_item
@@ -6674,6 +6737,8 @@ parse_vcol_expr:
Prevent the end user from invoking this command.
*/
MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
expr
{
@@ -6681,14 +6746,15 @@ parse_vcol_expr:
if (unlikely(!v))
MYSQL_YYABORT;
Lex->last_field->vcol_info= v;
+ Lex->pop_select(); //main select
}
;
parenthesized_expr:
- subselect
+ remember_tok_start
+ query_expression
{
- $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1);
- if (unlikely($$ == NULL))
+ if (!($$= Lex->create_item_query_expression(thd, $1, $2)))
MYSQL_YYABORT;
}
| expr
@@ -7714,23 +7780,25 @@ alter:
Lex->name= null_clex_str;
Lex->table_type= TABLE_TYPE_UNKNOWN;
Lex->sql_command= SQLCOM_ALTER_TABLE;
- Lex->duplicates= DUP_ERROR;
- Lex->select_lex.init_order();
+ Lex->duplicates= DUP_ERROR;
+ Lex->first_select_lex()->order_list.empty();
Lex->create_info.init();
Lex->create_info.row_type= ROW_TYPE_NOT_USED;
Lex->alter_info.reset();
Lex->no_write_to_binlog= 0;
Lex->create_info.storage_media= HA_SM_DEFAULT;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
DBUG_ASSERT(!Lex->m_sql_cmd);
}
alter_options TABLE_SYM table_ident opt_lock_wait_timeout
{
- if (unlikely(!Lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_UPGRADABLE)))
+ if (!Lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE))
MYSQL_YYABORT;
- Lex->select_lex.db= (Lex->select_lex.table_list.first)->db;
+ Lex->first_select_lex()->db=
+ (Lex->first_select_lex()->table_list.first)->db;
Lex->create_last_non_select_table= Lex->last_table();
}
alter_commands
@@ -7742,11 +7810,14 @@ alter:
if (unlikely(Lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
}
+ Lex->pop_select(); //main select
}
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
Lex->create_info.used_fields= 0;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
create_database_options
{
@@ -7756,6 +7827,7 @@ alter:
if (lex->name.str == NULL &&
unlikely(lex->copy_db_to(&lex->name)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
}
| ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
{
@@ -7771,6 +7843,8 @@ alter:
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->sp_chistics.init();
}
sp_a_chistics
@@ -7779,6 +7853,9 @@ alter:
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
lex->spname= $3;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| ALTER FUNCTION_SYM sp_name
{
@@ -7786,6 +7863,8 @@ alter:
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->sp_chistics.init();
}
sp_a_chistics
@@ -7794,14 +7873,23 @@ alter:
lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->spname= $3;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident
{
- if (unlikely(Lex->add_alter_view(thd, $2, $4, $6)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_alter_view(thd, $2, $4, $6))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| ALTER definer_opt opt_view_suid VIEW_SYM table_ident
/*
We have two separate rules for ALTER VIEW rather that
@@ -7809,14 +7897,22 @@ alter:
with the ALTER EVENT below.
*/
{
- if (unlikely(Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5)))
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))
MYSQL_YYABORT;
}
view_list_opt AS view_select
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| ALTER definer_opt remember_name EVENT_SYM sp_name
{
- /*
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ /*
It is safe to use Lex->spname because
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
is not allowed. Lex->spname is used in the case of RENAME TO
@@ -7848,6 +7944,8 @@ alter:
*/
Lex->sql_command= SQLCOM_ALTER_EVENT;
Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr();
+
+ Lex->pop_select(); //main select
}
| ALTER TABLESPACE alter_tablespace_info
{
@@ -7891,16 +7989,17 @@ alter:
lex->create_info.init();
lex->no_write_to_binlog= 0;
DBUG_ASSERT(!lex->m_sql_cmd);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
table_ident
{
LEX *lex= Lex;
- if (unlikely(!(lex->create_info.seq_create_info=
- new (thd->mem_root) sequence_definition())) ||
- unlikely(!lex->select_lex.add_table_to_list(thd, $5, NULL,
- TL_OPTION_SEQUENCE,
- TL_WRITE,
- MDL_EXCLUSIVE)))
+ if (!(lex->create_info.seq_create_info= new (thd->mem_root)
+ sequence_definition()) ||
+ !lex->first_select_lex()->
+ add_table_to_list(thd, $5, NULL, TL_OPTION_SEQUENCE,
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
}
sequence_defs
@@ -7909,6 +8008,9 @@ alter:
Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
if (unlikely(Lex->m_sql_cmd == NULL))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
;
@@ -8058,16 +8160,14 @@ alter_commands:
WITH TABLE_SYM table_ident have_partitioning
{
LEX *lex= thd->lex;
- lex->select_lex.db= $6->db;
- if (lex->select_lex.db.str == NULL &&
- unlikely(lex->copy_db_to(&lex->select_lex.db)))
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
MYSQL_YYABORT;
lex->name= $6->table;
lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $6, NULL,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_NO_WRITE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
+ TL_READ_NO_INSERT, MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
DBUG_ASSERT(!lex->m_sql_cmd);
lex->m_sql_cmd= new (thd->mem_root)
@@ -8306,10 +8406,11 @@ alter_list_item:
| RENAME opt_to table_ident
{
LEX *lex=Lex;
- lex->select_lex.db= $3->db;
- if (lex->select_lex.db.str == NULL &&
- unlikely(lex->copy_db_to(&lex->select_lex.db)))
+ lex->first_select_lex()->db= $3->db;
+ if (lex->first_select_lex()->db.str == NULL &&
+ lex->copy_db_to(&lex->first_select_lex()->db))
MYSQL_YYABORT;
+
if (unlikely(check_table_name($3->table.str,$3->table.length,
FALSE)) ||
($3->db.str && unlikely(check_db_name((LEX_STRING*) &$3->db))))
@@ -9003,8 +9104,8 @@ adm_partition:
cache_keys_spec:
{
- Lex->select_lex.alloc_index_hints(thd);
- Select->set_index_hint_type(INDEX_HINT_USE,
+ Lex->first_select_lex()->alloc_index_hints(thd);
+ Select->set_index_hint_type(INDEX_HINT_USE,
INDEX_HINT_MASK_ALL);
}
cache_key_list_or_empty
@@ -9027,215 +9128,211 @@ opt_ignore_leaves:
select:
- opt_with_clause select_init
- {
- LEX *lex= Lex;
- lex->sql_command= SQLCOM_SELECT;
- lex->current_select->set_with_clause($1);
- }
- ;
-
-select_init:
- SELECT_SYM select_options_and_item_list select_init3
- | table_value_constructor
- | table_value_constructor union_list
- | table_value_constructor union_order_or_limit
- | '(' select_paren ')'
- | '(' select_paren ')' union_list
- | '(' select_paren ')' union_order_or_limit
- ;
-
-union_list_part2:
- SELECT_SYM select_options_and_item_list select_init3_union_query_term
- | table_value_constructor
- | table_value_constructor union_list
- | table_value_constructor union_order_or_limit
- | '(' select_paren_union_query_term ')'
- | '(' select_paren_union_query_term ')' union_list
- | '(' select_paren_union_query_term ')' union_order_or_limit
- ;
-
-select_paren:
+ query_expression_body
{
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($1->fake_select_lex ?
+ $1->fake_select_lex :
+ $1->first_select()))
+ MYSQL_YYABORT;
}
- table_value_constructor
+ opt_procedure_or_into
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Lex->pop_select();
+ if (Lex->select_finalize($1))
+ MYSQL_YYABORT;
}
- |
+ | with_clause query_expression_body
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($2->fake_select_lex ?
+ $2->fake_select_lex :
+ $2->first_select()))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_options_and_item_list select_part3
- opt_select_lock_type
+ opt_procedure_or_into
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Lex->pop_select();
+ $2->set_with_clause($1);
+ $1->attach_to($2->first_select());
+ if (Lex->select_finalize($2))
+ MYSQL_YYABORT;
}
- | '(' select_paren ')'
;
-select_paren_union_query_term:
+
+select_into:
+ select_into_query_specification
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ if (Lex->push_select($1))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_options_and_item_list select_part3_union_query_term
- opt_select_lock_type
+ opt_order_limit_lock
{
- DBUG_ASSERT(Lex->current_select->braces);
- }
- | '(' select_paren_union_query_term ')'
- ;
+ st_select_lex_unit *unit;
+ if (!(unit= Lex->parsed_body_select($1, $3)))
+ MYSQL_YYABORT;
+ if (Lex->select_finalize(unit))
+ MYSQL_YYABORT;
+ }
+ ;
-select_paren_view:
+
+simple_table:
+ query_specification { $$= $1; }
+ | table_value_constructor { $$= $1; }
+ ;
+
+table_value_constructor:
+ VALUES
+ {
+ if (Lex->parsed_TVC_start())
+ MYSQL_YYABORT;
+ }
+ values_list
+ {
+ if (!($$= Lex->parsed_TVC_end()))
+ MYSQL_YYABORT;
+ }
+ ;
+
+query_specification_start:
+ SELECT_SYM
{
- /*
- In order to correctly parse UNION's global ORDER BY we need to
- set braces before parsing the clause.
- */
- Lex->current_select->set_braces(true);
+ SELECT_LEX *sel;
+ LEX *lex= Lex;
+ if (!(sel= lex->alloc_select(TRUE)) ||
+ lex->push_select(sel))
+ MYSQL_YYABORT;
+ sel->init_select();
+ sel->braces= FALSE;
}
- SELECT_SYM select_options_and_item_list select_part3_view
- opt_select_lock_type
+ select_options
{
- DBUG_ASSERT(Lex->current_select->braces);
+ Select->parsing_place= SELECT_LIST;
}
- | '(' select_paren_view ')'
- ;
+ select_item_list
+ {
+ Select->parsing_place= NO_MATTER;
+ }
+ ;
-/* The equivalent of select_paren for nested queries. */
-select_paren_derived:
+query_specification:
+ query_specification_start
+ opt_from_clause
+ opt_where_clause
+ opt_group_clause
+ opt_having_clause
+ opt_window_clause
{
- Lex->current_select->set_braces(true);
+ $$= Lex->pop_select();
}
- table_value_constructor
+ ;
+
+select_into_query_specification:
+ query_specification_start
+ into
+ opt_from_clause
+ opt_where_clause
+ opt_group_clause
+ opt_having_clause
+ opt_window_clause
{
- DBUG_ASSERT(Lex->current_select->braces);
- $$= Lex->current_select->master_unit()->first_select();
+ $$= Lex->pop_select();
}
- |
+ ;
+
+opt_from_clause:
+ /* Empty */
+ | from_clause
+ ;
+
+query_primary:
+ simple_table
+ { $$= $1; }
+ | query_primary_parens
+ { $$= $1; }
+ ;
+
+query_primary_parens:
+ '(' query_expression_unit
{
- Lex->current_select->set_braces(true);
+ if (Lex->parsed_unit_in_brackets($2))
+ MYSQL_YYABORT;
}
- SELECT_SYM select_part2_derived
- opt_table_expression
- opt_order_clause
- opt_limit_clause
- opt_select_lock_type
+ query_expression_tail ')'
{
- DBUG_ASSERT(Lex->current_select->braces);
- $$= Lex->current_select->master_unit()->first_select();
+ $$= Lex->parsed_unit_in_brackets_tail($2, $4);
}
- | '(' select_paren_derived ')' { $$= $2; }
- ;
-
-select_init3:
- opt_table_expression
- opt_select_lock_type
+ | '(' query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ Lex->push_select($2);
}
- union_clause
- | select_part3_union_not_ready
- opt_select_lock_type
+ query_expression_tail ')'
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_in_brackets($2, $4)))
+ YYABORT;
}
;
-
-select_init3_union_query_term:
- opt_table_expression
- opt_select_lock_type
+query_expression_unit:
+ query_primary
+ unit_type_decl
+ query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type,
+ $2.distinct)))
+ YYABORT;
}
- union_clause
- | select_part3_union_not_ready_noproc
- opt_select_lock_type
+ | query_expression_unit
+ unit_type_decl
+ query_primary
{
- /* Parentheses carry no meaning here */
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type,
+ $2.distinct, TRUE)))
+ YYABORT;
}
;
-
-select_init3_view:
- opt_table_expression opt_select_lock_type
+query_expression_body:
+ query_primary
{
- Lex->current_select->set_braces(false);
+ Lex->push_select($1);
}
- | opt_table_expression opt_select_lock_type
+ query_expression_tail
{
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_body_select($1, $3)))
+ MYSQL_YYABORT;
}
- union_list_view
- | order_or_limit opt_select_lock_type
+ | query_expression_unit
{
- Lex->current_select->set_braces(false);
+ if (Lex->parsed_body_unit($1))
+ MYSQL_YYABORT;
}
- | table_expression order_or_limit opt_select_lock_type
+ query_expression_tail
{
- Lex->current_select->set_braces(false);
+ if (!($$= Lex->parsed_body_unit_tail($1, $3)))
+ MYSQL_YYABORT;
}
;
-/*
- The SELECT parts after select_item_list that cannot be followed by UNION.
-*/
-
-select_part3:
- opt_table_expression
- | select_part3_union_not_ready
- ;
-
-select_part3_union_query_term:
- opt_table_expression
- | select_part3_union_not_ready_noproc
- ;
-
-select_part3_view:
- opt_table_expression
- | order_or_limit
- | table_expression order_or_limit
- ;
-
-select_part3_union_not_ready:
- select_part3_union_not_ready_noproc
- | table_expression procedure_clause
- | table_expression order_or_limit procedure_clause
- ;
-
-select_part3_union_not_ready_noproc:
- order_or_limit
- | into opt_table_expression opt_order_clause opt_limit_clause
- | table_expression into
- | table_expression order_or_limit
- | table_expression order_or_limit into
- ;
-
-select_options_and_item_list:
+query_expression:
+ opt_with_clause
+ query_expression_body
{
- LEX *lex= Lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->linkage != UNION_TYPE)
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
+ if ($1)
+ {
+ $2->set_with_clause($1);
+ $1->attach_to($2->first_select());
+ }
+ $$= $2;
}
- select_options select_item_list
+ ;
+
+subselect:
+ remember_tok_start
+ query_expression
{
- Select->parsing_place= NO_MATTER;
+ if (!($$= Lex->parsed_subselect($2, $1)))
+ YYABORT;
}
;
@@ -9243,18 +9340,6 @@ select_options_and_item_list:
/**
<table expression>, as in the SQL standard.
*/
-table_expression:
- from_clause
- opt_where_clause
- opt_group_clause
- opt_having_clause
- opt_window_clause
- ;
-
-opt_table_expression:
- /* Empty */
- | table_expression
- ;
from_clause:
FROM table_reference_list
@@ -9303,8 +9388,9 @@ history_point:
TIMESTAMP TEXT_STRING
{
Item *item;
- if (!(item= create_temporal_literal(thd, $2.str, $2.length, YYCSCL,
- MYSQL_TYPE_DATETIME, true)))
+ if (!(item= type_handler_datetime2.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true)))
MYSQL_YYABORT;
$$= Vers_history_point(VERS_TIMESTAMP, item);
}
@@ -9357,59 +9443,70 @@ select_option:
query_expression_option
| SQL_NO_CACHE_SYM
{
- /*
- Allow this flag only on the first top-level SELECT statement, if
- SQL_CACHE wasn't specified, and only once per query.
- */
- if (unlikely(Lex->current_select != &Lex->select_lex))
- my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE))
+ /*
+ Allow this flag once per query.
+ */
+ if (Select->options & OPTION_NO_QUERY_CACHE)
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
-
- Lex->safe_to_cache_query=0;
- Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
- Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+ Select->options|= OPTION_NO_QUERY_CACHE;
}
| SQL_CACHE_SYM
{
- /*
- Allow this flag only on the first top-level SELECT statement, if
- SQL_NO_CACHE wasn't specified, and only once per query.
- */
- if (unlikely(Lex->current_select != &Lex->select_lex))
- my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE))
- my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"));
- if (unlikely(Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE))
+ /*
+ Allow this flag once per query.
+ */
+ if (Select->options & OPTION_TO_QUERY_CACHE)
my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
-
- Lex->safe_to_cache_query=1;
- Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
- Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
+ Select->options|= OPTION_TO_QUERY_CACHE;
}
;
-opt_select_lock_type:
- /* empty */
- | FOR_SYM UPDATE_SYM opt_lock_wait_timeout
+
+select_lock_type:
+ FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new
{
- LEX *lex=Lex;
- lex->current_select->lock_type= TL_WRITE;
- lex->current_select->set_lock_for_tables(TL_WRITE);
- lex->safe_to_cache_query=0;
+ $$= $3;
+ $$.defined_lock= TRUE;
+ $$.update_lock= TRUE;
}
- | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout
+ | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new
{
- LEX *lex=Lex;
- lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS;
- lex->current_select->
- set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
- lex->safe_to_cache_query=0;
+ $$= $5;
+ $$.defined_lock= TRUE;
+ $$.update_lock= FALSE;
}
;
+
+opt_select_lock_type:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | select_lock_type
+ {
+ $$= $1;
+ }
+ ;
+
+
+opt_lock_wait_timeout_new:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | WAIT_SYM ulong_num
+ {
+ $$.defined_timeout= TRUE;
+ $$.timeout= $2;
+ }
+ | NOWAIT_SYM
+ {
+ $$.defined_timeout= TRUE;
+ $$.timeout= 0;
+ }
+ ;
+
select_item_list:
select_item_list ',' select_item
| select_item
@@ -10106,7 +10203,21 @@ column_default_non_parenthesized_expr:
| param_marker { $$= $1; }
| variable
| sum_expr
+ {
+ if (!Lex->select_stack_top)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+ MYSQL_YYABORT;
+ }
+ }
| window_func_expr
+ {
+ if (!Lex->select_stack_top)
+ {
+ my_error(ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION, MYF(0));
+ MYSQL_YYABORT;
+ }
+ }
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')'
{
@@ -10303,7 +10414,7 @@ function_call_keyword_timestamp:
}
| TIMESTAMP '(' expr ',' expr ')'
{
- $$= new (thd->mem_root) Item_func_add_time(thd, $3, $5, 1, 0);
+ $$= new (thd->mem_root) Item_func_timestamp(thd, $3, $5);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
@@ -11735,10 +11846,15 @@ esc_table_ref:
/* Equivalent to <table reference list> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
derived_table_list:
- esc_table_ref { $$=$1; }
+ esc_table_ref
+ {
+ $$=$1;
+ Select->add_joined_table($1);
+ }
| derived_table_list ',' esc_table_ref
{
MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ Select->add_joined_table($3);
}
;
@@ -11757,11 +11873,18 @@ join_table:
left-associative joins.
*/
table_ref normal_join table_ref %prec TABLE_REF_PRIORITY
- { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; }
+ {
+ MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
+ $3->straight=$2;
+ }
| table_ref normal_join table_ref
ON
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $3)))
MYSQL_YYABORT;
@@ -11778,6 +11901,8 @@ join_table:
USING
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
}
'(' using_list ')'
{
@@ -11788,6 +11913,8 @@ join_table:
| table_ref NATURAL inner_join table_factor
{
MYSQL_YYABORT_UNLESS($1 && ($$=$4));
+ Select->add_joined_table($1);
+ Select->add_joined_table($4);
$4->straight=$3;
add_join_natural($1,$4,NULL,Select);
}
@@ -11797,6 +11924,8 @@ join_table:
ON
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
MYSQL_YYABORT;
@@ -11813,6 +11942,8 @@ join_table:
| table_ref LEFT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
}
USING '(' using_list ')'
{
@@ -11823,6 +11954,8 @@ join_table:
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $6);
+ Select->add_joined_table($1);
+ Select->add_joined_table($6);
add_join_natural($1,$6,NULL,Select);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
@@ -11833,6 +11966,8 @@ join_table:
ON
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
/* Change the current name resolution context to a local context. */
if (unlikely(push_new_name_resolution_context(thd, $1, $5)))
MYSQL_YYABORT;
@@ -11850,6 +11985,8 @@ join_table:
| table_ref RIGHT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $5);
+ Select->add_joined_table($1);
+ Select->add_joined_table($5);
}
USING '(' using_list ')'
{
@@ -11861,6 +11998,8 @@ join_table:
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
MYSQL_YYABORT_UNLESS($1 && $6);
+ Select->add_joined_table($1);
+ Select->add_joined_table($6);
add_join_natural($6,$1,NULL,Select);
LEX *lex= Lex;
if (unlikely(!($$= lex->current_select->convert_right_join())))
@@ -11895,238 +12034,45 @@ use_partition:
$$= $3;
}
;
-
-/*
- This is a flattening of the rules <table factor> and <table primary>
- in the SQL:2003 standard, since we don't have <sample clause>
- I.e.
- <table factor> ::= <table primary> [ <sample clause> ]
-*/
-/* Warning - may return NULL in case of incomplete SELECT */
table_factor:
- table_primary_ident
- | table_primary_derived
- ;
-
-table_primary_ident:
- {
- DBUG_ASSERT(Select);
- SELECT_LEX *sel= Select;
- sel->table_join_options= 0;
- }
- table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition
- {
- if (unlikely(!($$= Select->add_table_to_list(thd, $2, $5,
- Select->get_table_join_options(),
- YYPS->m_lock_type,
- YYPS->m_mdl_type,
- Select->
- pop_index_hints(),
- $3))))
- MYSQL_YYABORT;
- Select->add_joined_table($$);
- if ($4)
- $$->vers_conditions= Lex->vers_conditions;
- }
+ table_primary_ident { $$= $1; }
+ | table_primary_derived { $$= $1; }
+ | join_table_parens { $$= $1; }
+ | table_reference_list_parens { $$= $1; }
;
-
-
-/*
- Represents a flattening of the following rules from the SQL:2003
- standard. This sub-rule corresponds to the sub-rule
- <table primary> ::= ... | <derived table> [ AS ] <correlation name>
-
- <derived table> ::= <table subquery>
- <table subquery> ::= <subquery>
- <subquery> ::= <left paren> <query expression> <right paren>
- <query expression> ::= [ <with clause> ] <query expression body>
-
- For the time being we use the non-standard rule
- select_derived_union which is a compromise between the standard
- and our parser. Possibly this rule could be replaced by our
- query_expression_body.
-*/
-
-table_primary_derived:
- '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias
+table_reference_list_parens:
+ '(' table_reference_list_parens ')' { $$= $2; }
+ | '(' nested_table_reference_list ')'
{
- /* Use $2 instead of Lex->current_select as derived table will
- alter value of Lex->current_select. */
- if (!($3 || $6) && $2->embedding &&
- !$2->embedding->nested_join->join_list.elements)
- {
- /* we have a derived table ($3 == NULL) but no alias,
- Since we are nested in further parentheses so we
- can pass NULL to the outer level parentheses
- Permits parsing of "((((select ...))) as xyz)" */
- $$= 0;
- }
- else if (!$3)
- {
- /* Handle case of derived table, alias may be NULL if there
- are no outer parentheses, add_table_to_list() will throw
- error in this case */
- LEX *lex=Lex;
- lex->check_automatic_up(UNSPECIFIED_TYPE);
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel->master_unit();
- lex->current_select= sel= unit->outer_select();
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- if (unlikely(!($$= sel->add_table_to_list(thd,
- ti, $6, 0,
- TL_READ,
- MDL_SHARED_READ))))
- MYSQL_YYABORT;
- sel->add_joined_table($$);
- lex->pop_context();
- lex->nest_level--;
- }
- else if (unlikely($6 != NULL))
- {
- /*
- Tables with or without joins within parentheses cannot
- have aliases, and we ruled out derived tables above.
- */
- thd->parse_error();
+ if (!($$= Select->end_nested_join(thd)))
MYSQL_YYABORT;
- }
- else
- {
- /* nested join: FROM (t1 JOIN t2 ...),
- nest_level is the same as in the outer query */
- $$= $3;
- }
- /*
- Fields in derived table can be used in upper select in
- case of merge. We do not add HAVING fields because we do
- not merge such derived. We do not add union because
- also do not merge them
- */
- if ($$ && $$->derived &&
- !$$->derived->first_select()->next_select())
- $$->select_lex->add_where_field($$->derived->first_select());
- if ($5)
- {
- MYSQL_YYABORT_UNLESS(!$3);
- $$->vers_conditions= Lex->vers_conditions;
- }
}
- /* Represents derived table with WITH clause */
- | '(' get_select_lex subselect_start
- with_clause query_expression_body
- subselect_end ')' opt_for_system_time_clause opt_table_alias
- {
- LEX *lex=Lex;
- SELECT_LEX *sel= $2;
- SELECT_LEX_UNIT *unit= $5->master_unit();
- Table_ident *ti= new (thd->mem_root) Table_ident(unit);
- if (unlikely(ti == NULL))
- MYSQL_YYABORT;
- $5->set_with_clause($4);
- lex->current_select= sel;
- if (unlikely(!($$= sel->add_table_to_list(lex->thd,
- ti, $9, 0,
- TL_READ,
- MDL_SHARED_READ))))
- MYSQL_YYABORT;
- sel->add_joined_table($$);
- if ($8)
- $$->vers_conditions= Lex->vers_conditions;
- }
;
-/*
- This rule accepts just about anything. The reason is that we have
- empty-producing rules in the beginning of rules, in this case
- subselect_start. This forces bison to take a decision which rules to
- reduce by long before it has seen any tokens. This approach ties us
- to a very limited class of parseable languages, and unfortunately
- SQL is not one of them. The chosen 'solution' was this rule, which
- produces just about anything, even complete bogus statements, for
- instance ( table UNION SELECT 1 ).
- Fortunately, we know that the semantic value returned by
- select_derived is NULL if it contained a derived table, and a pointer to
- the base table's TABLE_LIST if it was a base table. So in the rule
- regarding union's, we throw a parse error manually and pretend it
- was bison that did it.
-
- Also worth noting is that this rule concerns query expressions in
- the from clause only. Top level select statements and other types of
- subqueries have their own union rules.
-*/
-select_derived_union:
- select_derived
- | select_derived union_order_or_limit
- {
- if (unlikely($1))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- }
- | select_derived union_head_non_top
+nested_table_reference_list:
+ table_ref ',' table_ref
{
- if (unlikely($1))
- {
- thd->parse_error();
+ if (Select->init_nested_join(thd))
MYSQL_YYABORT;
- }
- }
- union_list_derived_part2
- | derived_simple_table opt_select_lock_type
- | derived_simple_table order_or_limit opt_select_lock_type
- | derived_simple_table opt_select_lock_type union_list_derived
- ;
-
-union_list_derived_part2:
- query_term_union_not_ready { Lex->pop_context(); }
- | query_term_union_ready { Lex->pop_context(); }
- | query_term_union_ready { Lex->pop_context(); } union_list_derived
- ;
-
-union_list_derived:
- union_head_non_top union_list_derived_part2
- ;
-
-
-/* The equivalent of select_init2 for nested queries. */
-select_init2_derived:
- select_part2_derived
- {
- Select->set_braces(0);
- }
- ;
-
-/* The equivalent of select_part2 for nested queries. */
-select_part2_derived:
- {
- LEX *lex= Lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->linkage != UNION_TYPE)
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
+ $$= $1->embedding;
}
- opt_query_expression_options select_item_list
+ | nested_table_reference_list ',' table_ref
{
- Select->parsing_place= NO_MATTER;
+ Select->add_joined_table($3);
+ $$= $1;
}
;
-/* handle contents of parentheses in join expression */
-select_derived:
- get_select_lex_derived derived_table_list
+join_table_parens:
+ '(' join_table_parens ')' { $$= $2; }
+ | '(' join_table ')'
{
LEX *lex= Lex;
- /* for normal joins, $2 != NULL and end_nested_join() != NULL,
- for derived tables, both must equal NULL */
-
- if (unlikely(!($$= $1->end_nested_join(lex->thd)) && $2))
- MYSQL_YYABORT;
- if (unlikely(!$2 && $$))
+ if (!($$= lex->current_select->nest_last_join(thd)))
{
thd->parse_error();
MYSQL_YYABORT;
@@ -12134,83 +12080,54 @@ select_derived:
}
;
-derived_simple_table:
- derived_query_specification { $$= $1; }
- | derived_table_value_constructor { $$= $1; }
- ;
-/*
- Similar to query_specification, but for derived tables.
- Example: the inner parenthesized SELECT in this query:
- SELECT * FROM (SELECT * FROM t1);
-*/
-derived_query_specification:
- SELECT_SYM select_derived_init select_derived2
- {
- if ($2)
- Select->set_braces(1);
- $$= NULL;
- }
- ;
-derived_table_value_constructor:
- VALUES
- {
- Lex->tvc_start();
- }
- values_list
+table_primary_ident:
+ table_ident opt_use_partition opt_for_system_time_clause
+ opt_table_alias_clause opt_key_definition
{
- if (Lex->tvc_finalize_derived())
+ SELECT_LEX *sel= Select;
+ sel->table_join_options= 0;
+ if (!($$= Select->add_table_to_list(thd, $1, $4,
+ Select->get_table_join_options(),
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type,
+ Select->pop_index_hints(),
+ $2)))
MYSQL_YYABORT;
- $$= NULL;
+ if ($3)
+ $$->vers_conditions= Lex->vers_conditions;
}
;
-select_derived2:
- {
- LEX *lex= Lex;
- lex->derived_tables|= DERIVED_SUBQUERY;
- if (unlikely(!lex->expr_allows_subselect ||
- lex->sql_command == (int)SQLCOM_PURGE))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
- unlikely(mysql_new_select(lex, 1, NULL)))
- MYSQL_YYABORT;
- mysql_init_select(lex);
- lex->current_select->linkage= DERIVED_TABLE_TYPE;
- lex->current_select->parsing_place= SELECT_LIST;
- }
- select_options select_item_list
- {
- Select->parsing_place= NO_MATTER;
- }
- opt_table_expression
- ;
+/*
+ Represents a flattening of the following rules from the SQL:2003
+ standard. This sub-rule corresponds to the sub-rule
+ <table primary> ::= ... | <derived table> [ AS ] <correlation name>
-get_select_lex:
- /* Empty */ { $$= Select; }
- ;
+ <derived table> ::= <table subquery>
+ <table subquery> ::= <subquery>
+ <subquery> ::= <left paren> <query expression> <right paren>
+ <query expression> ::= [ <with clause> ] <query expression body>
+
+ For the time being we use the non-standard rule
+ select_derived_union which is a compromise between the standard
+ and our parser. Possibly this rule could be replaced by our
+ query_expression_body.
+*/
-get_select_lex_derived:
- get_select_lex
+table_primary_derived:
+ query_primary_parens opt_for_system_time_clause table_alias_clause
{
- LEX *lex= Lex;
- if (unlikely($1->init_nested_join(lex->thd)))
- MYSQL_YYABORT;
+ if (!($$= Lex->parsed_derived_select($1, $2, $3)))
+ YYABORT;
}
- ;
-
-select_derived_init:
+ | '('
+ query_expression
+ ')' opt_for_system_time_clause table_alias_clause
{
- LEX *lex= Lex;
-
- TABLE_LIST *embedding= lex->current_select->embedding;
- $$= embedding &&
- !embedding->nested_join->join_list.elements;
- /* return true if we are deeply nested */
+ if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
+ YYABORT;
}
;
@@ -12344,9 +12261,14 @@ table_alias:
| '='
;
-opt_table_alias:
+opt_table_alias_clause:
/* empty */ { $$=0; }
- | table_alias ident_table_alias
+
+ | table_alias_clause { $$= $1; }
+ ;
+
+table_alias_clause:
+ table_alias ident_table_alias
{
$$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING));
if (unlikely($$ == NULL))
@@ -12442,7 +12364,7 @@ olap_opt:
SQL-2003: GROUP BY ... CUBE(col1, col2, col3)
*/
LEX *lex=Lex;
- if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE))
+ if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH CUBE",
"global union parameters"));
lex->current_select->olap= CUBE_TYPE;
@@ -12459,7 +12381,7 @@ olap_opt:
SQL-2003: GROUP BY ... ROLLUP(col1, col2, col3)
*/
LEX *lex= Lex;
- if (unlikely(lex->current_select->linkage == GLOBAL_OPTIONS_TYPE))
+ if (unlikely(lex->current_select->get_linkage() == GLOBAL_OPTIONS_TYPE))
my_yyabort_error((ER_WRONG_USAGE, MYF(0), "WITH ROLLUP",
"global union parameters"));
lex->current_select->olap= ROLLUP_TYPE;
@@ -12519,7 +12441,7 @@ opt_window_partition_clause:
opt_window_order_clause:
/* empty */ { }
- | ORDER_SYM BY order_list
+ | ORDER_SYM BY order_list { Select->order_list= *($3); }
;
opt_window_frame_clause:
@@ -12643,70 +12565,35 @@ alter_order_item:
opt_order_clause:
/* empty */
+ { $$= NULL; }
| order_clause
+ { $$= $1; }
;
order_clause:
ORDER_SYM BY
{
- LEX *lex=Lex;
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel-> master_unit();
- if (unlikely(sel->linkage != GLOBAL_OPTIONS_TYPE &&
- sel->olap != UNSPECIFIED_OLAP_TYPE &&
- (sel->linkage != UNION_TYPE || sel->braces)))
- {
- my_error(ER_WRONG_USAGE, MYF(0),
- "CUBE/ROLLUP", "ORDER BY");
- MYSQL_YYABORT;
- }
- if (lex->sql_command != SQLCOM_ALTER_TABLE &&
- !unit->fake_select_lex)
- {
- /*
- A query of the of the form (SELECT ...) ORDER BY order_list is
- executed in the same way as the query
- SELECT ... ORDER BY order_list
- unless the SELECT construct contains ORDER BY or LIMIT clauses.
- Otherwise we create a fake SELECT_LEX if it has not been
- created yet.
- */
- SELECT_LEX *first_sl= unit->first_select();
- if (unlikely(!unit->is_unit_op() &&
- (first_sl->order_list.elements ||
- first_sl->select_limit) &&
- unit->add_fake_select_lex(thd)))
- MYSQL_YYABORT;
- }
- if (sel->master_unit()->is_unit_op() && !sel->braces)
- {
- /*
- At this point we don't know yet whether this is the last
- select in union or not, but we move ORDER BY to
- fake_select_lex anyway. If there would be one more select
- in union mysql_new_select will correctly throw error.
- */
- DBUG_ASSERT(sel->master_unit()->fake_select_lex);
- lex->current_select= sel->master_unit()->fake_select_lex;
- }
+ thd->where= "ORDER clause";
}
order_list
{
-
+ $$= $4;
}
;
order_list:
order_list ',' order_ident order_dir
{
- if (unlikely(add_order_to_list(thd, $3,(bool) $4)))
- MYSQL_YYABORT;
- }
+ $$= $1;
+ if (add_to_list(thd, *$$, $3,(bool) $4))
+ MYSQL_YYABORT;
+ }
| order_ident order_dir
{
- if (unlikely(add_order_to_list(thd, $1,(bool) $2)))
+ $$= new (thd->mem_root) SQL_I_List<ORDER>();
+ if (add_to_list(thd, *$$, $1, (bool) $2))
MYSQL_YYABORT;
- }
+ }
;
order_dir:
@@ -12716,63 +12603,61 @@ order_dir:
;
opt_limit_clause:
- /* empty */ {}
- | limit_clause {}
+ /* empty */
+ { $$.empty(); }
+ | limit_clause
+ { $$= $1; }
;
-limit_clause_init:
- LIMIT
- {
- SELECT_LEX *sel= Select;
- if (sel->master_unit()->is_unit_op() && !sel->braces)
- {
- /* Move LIMIT that belongs to UNION to fake_select_lex */
- Lex->current_select= sel->master_unit()->fake_select_lex;
- DBUG_ASSERT(Select);
- }
- }
- ;
-
limit_clause:
- limit_clause_init limit_options
+ LIMIT limit_options
{
- SELECT_LEX *sel= Select;
- if (!sel->select_limit->basic_const_item() ||
- sel->select_limit->val_int() > 0)
+ $$= $2;
+ if (!$$.select_limit->basic_const_item() ||
+ $$.select_limit->val_int() > 0)
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
- | limit_clause_init limit_options
+ | LIMIT limit_options
ROWS_SYM EXAMINED_SYM limit_rows_option
{
+ $$= $2;
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
- | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option
+ | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option
{
+ $$.select_limit= 0;
+ $$.offset_limit= 0;
+ $$.explicit_limit= 1;
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
}
;
+opt_global_limit_clause:
+ opt_limit_clause
+ {
+ Select->explicit_limit= $1.explicit_limit;
+ Select->select_limit= $1.select_limit;
+ Select->offset_limit= $1.offset_limit;
+ }
+
limit_options:
limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= 0;
- sel->explicit_limit= 1;
+ $$.select_limit= $1;
+ $$.offset_limit= 0;
+ $$.explicit_limit= 1;
}
| limit_option ',' limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $3;
- sel->offset_limit= $1;
- sel->explicit_limit= 1;
+ $$.select_limit= $3;
+ $$.offset_limit= $1;
+ $$.explicit_limit= 1;
}
| limit_option OFFSET_SYM limit_option
{
- SELECT_LEX *sel= Select;
- sel->select_limit= $1;
- sel->offset_limit= $3;
- sel->explicit_limit= 1;
+ $$.select_limit= $1;
+ $$.offset_limit= $3;
+ $$.explicit_limit= 1;
}
;
@@ -12835,6 +12720,77 @@ delete_limit_clause:
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
;
+opt_order_limit_lock:
+ /* empty */
+ { $$= NULL; }
+ | order_or_limit
+ {
+ $$= $1;
+ $$->lock.empty();
+ }
+ | order_or_limit select_lock_type
+ {
+ $$= $1;
+ $$->lock= $2;
+ }
+ | select_lock_type
+ {
+ $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ $$->order_list= NULL;
+ $$->limit.empty();
+ $$->lock= $1;
+ }
+ ;
+query_expression_tail:
+ opt_order_limit_lock
+ ;
+
+opt_procedure_or_into:
+ /* empty */
+ {
+ $$.empty();
+ }
+ | procedure_clause opt_select_lock_type
+ {
+ $$= $2;
+ }
+ | into opt_select_lock_type
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
+ "<select expression> INTO <destination>;",
+ "'SELECT <select list> INTO <destination>"
+ " FROM...'");
+ $$= $2;
+ }
+ ;
+
+
+order_or_limit:
+ order_clause opt_limit_clause
+ {
+ $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ $$->order_list= $1;
+ $$->limit= $2;
+ }
+ | limit_clause
+ {
+ Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock;
+ if (!$$)
+ YYABORT;
+ op->order_list= NULL;
+ op->limit= $1;
+ $$->order_list= NULL;
+ $$->limit= $1;
+ }
+ ;
+
+
opt_plus:
/* empty */
| '+'
@@ -12904,14 +12860,11 @@ bool:
| TRUE_SYM { $$= 1; }
| FALSE_SYM { $$= 0; }
-
procedure_clause:
PROCEDURE_SYM ident /* Procedure name */
{
LEX *lex=Lex;
- DBUG_ASSERT(&lex->select_lex == lex->current_select);
-
lex->proc_list.elements=0;
lex->proc_list.first=0;
lex->proc_list.next= &lex->proc_list.first;
@@ -12931,6 +12884,7 @@ procedure_clause:
parameters are reduced.
*/
Lex->expr_allows_subselect= false;
+ Select->options|= OPTION_PROCEDURE_CLAUSE;
}
'(' procedure_list ')'
{
@@ -13014,6 +12968,7 @@ select_outvar:
into:
INTO into_destination
+ {}
;
into_destination:
@@ -13223,10 +13178,11 @@ table_list:
table_name:
table_ident
{
- if (unlikely(!Select->add_table_to_list(thd, $1, NULL,
- TL_OPTION_UPDATING,
- YYPS->m_lock_type,
- YYPS->m_mdl_type)))
+ if (!thd->lex->current_select_or_default()->
+ add_table_to_list(thd, $1, NULL,
+ TL_OPTION_UPDATING,
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -13299,17 +13255,24 @@ insert:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_INSERT;
- lex->duplicates= DUP_ERROR;
- mysql_init_select(lex);
+ lex->duplicates= DUP_ERROR;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
}
insert_lock_option
opt_ignore insert2
{
Select->set_lock_for_tables($3);
- Lex->current_select= &Lex->select_lex;
+ Lex->current_select= Lex->first_select_lex();
}
insert_field_spec opt_insert_update
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
replace:
@@ -13318,15 +13281,22 @@ replace:
LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
- mysql_init_select(lex);
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= BEFORE_OPT_LIST;
}
replace_lock_option insert2
{
Select->set_lock_for_tables($3);
- Lex->current_select= &Lex->select_lex;
+ Lex->current_select= Lex->first_select_lex();
}
insert_field_spec
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
insert_lock_option:
@@ -13369,15 +13339,14 @@ insert_table:
table_name_with_opt_use_partition
{
LEX *lex=Lex;
- lex->field_list.empty();
+ //lex->field_list.empty();
lex->many_values.empty();
lex->insert_list=0;
};
insert_field_spec:
insert_values {}
- | '(' ')' insert_values {}
- | '(' fields ')' insert_values {}
+ | insert_field_list insert_values {}
| SET
{
LEX *lex=Lex;
@@ -13385,20 +13354,33 @@ insert_field_spec:
unlikely(lex->many_values.push_back(lex->insert_list,
thd->mem_root)))
MYSQL_YYABORT;
+ lex->current_select->parsing_place= NO_MATTER;
}
ident_eq_list
;
+insert_field_list:
+ LEFT_PAREN_ALT opt_fields ')'
+ {
+ Lex->current_select->parsing_place= AFTER_LIST;
+ }
+ ;
+
+opt_fields:
+ /* empty */
+ | fields
+ ;
+
fields:
fields ',' insert_ident
{ Lex->field_list.push_back($3, thd->mem_root); }
| insert_ident { Lex->field_list.push_back($1, thd->mem_root); }
;
+
+
insert_values:
- VALUES values_list {}
- | VALUE_SYM values_list {}
- | create_select_query_expression {}
+ create_select_query_expression {}
;
values_list:
@@ -13548,6 +13530,8 @@ update:
UPDATE_SYM
{
LEX *lex= Lex;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->sql_command= SQLCOM_UPDATE;
lex->duplicates= DUP_ERROR;
@@ -13556,13 +13540,14 @@ update:
SET update_list
{
LEX *lex= Lex;
- if (lex->select_lex.table_list.elements > 1)
+ if (lex->first_select_lex()->table_list.elements > 1)
lex->sql_command= SQLCOM_UPDATE_MULTI;
- else if (unlikely(lex->select_lex.get_table_list()->derived))
+ else if (lex->first_select_lex()->get_table_list()->derived)
{
/* it is single table update and it is update of derived table */
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
- lex->select_lex.get_table_list()->alias.str, "UPDATE");
+ lex->first_select_lex()->get_table_list()->alias.str,
+ "UPDATE");
MYSQL_YYABORT;
}
/*
@@ -13572,7 +13557,14 @@ update:
*/
Select->set_lock_for_tables($3);
}
- opt_where_clause opt_order_clause delete_limit_clause {}
+ opt_where_clause opt_order_clause delete_limit_clause
+ {
+ if ($10)
+ Select->order_list= *($10);
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
update_list:
@@ -13619,9 +13611,11 @@ delete:
mysql_init_select(lex);
YYPS->m_lock_type= TL_WRITE_DEFAULT;
YYPS->m_mdl_type= MDL_SHARED_WRITE;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
lex->ignore= 0;
- lex->select_lex.init_order();
+ lex->first_select_lex()->order_list.empty();
}
delete_part2
;
@@ -13645,6 +13639,7 @@ delete_part2:
}
;
+
delete_single_table:
FROM table_ident opt_use_partition
{
@@ -13665,7 +13660,12 @@ single_multi:
opt_where_clause
opt_order_clause
delete_limit_clause
- opt_select_expressions {}
+ opt_select_expressions
+ {
+ if ($3)
+ Select->order_list= *($3);
+ Lex->pop_select(); //main select
+ }
| table_wild_list
{
mysql_init_multi_delete(Lex);
@@ -13676,6 +13676,9 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
| FROM table_alias_ref_list
{
@@ -13687,9 +13690,13 @@ single_multi:
{
if (unlikely(multi_delete_set_locks_and_link_aux_tables(Lex)))
MYSQL_YYABORT;
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
;
+
opt_select_expressions:
/* empty */
| RETURNING_SYM select_item_list
@@ -13755,9 +13762,9 @@ truncate:
LEX* lex= Lex;
lex->sql_command= SQLCOM_TRUNCATE;
lex->alter_info.reset();
- lex->select_lex.options= 0;
- lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
- lex->select_lex.init_order();
+ lex->first_select_lex()->options= 0;
+ lex->sql_cache= LEX::SQL_CACHE_UNSPECIFIED;
+ lex->first_select_lex()->order_list.empty();
YYPS->m_lock_type= TL_WRITE;
YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
@@ -13849,6 +13856,8 @@ show:
LEX *lex=Lex;
lex->wild=0;
lex->ident= null_clex_str;
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
lex->create_info.init();
@@ -13856,6 +13865,7 @@ show:
show_param
{
Select->parsing_place= NO_MATTER;
+ Lex->pop_select(); //main select
}
;
@@ -13871,40 +13881,40 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
MYSQL_YYABORT;
}
| opt_full TRIGGERS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TRIGGERS;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
MYSQL_YYABORT;
}
| EVENTS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_EVENTS;
- lex->select_lex.db= $2;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_EVENTS)))
+ lex->first_select_lex()->db= $2;
+ if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
MYSQL_YYABORT;
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_TABLES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
MYSQL_YYABORT;
}
| OPEN_SYM TABLES opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
- lex->select_lex.db= $3;
- if (unlikely(prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)))
+ lex->first_select_lex()->db= $3;
+ if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
MYSQL_YYABORT;
}
| PLUGINS_SYM
@@ -13953,12 +13963,13 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
}
- opt_limit_clause
+ opt_global_limit_clause
| RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
- } opt_limit_clause
+ }
+ opt_global_limit_clause
| keys_or_index from_or_in table_ident opt_db opt_where_clause
{
LEX *lex= Lex;
@@ -14000,13 +14011,13 @@ show_param:
LEX_CSTRING var= {STRING_WITH_LEN("error_count")};
(void) create_select_for_variable(thd, &var);
}
- | WARNINGS opt_limit_clause
+ | WARNINGS opt_global_limit_clause
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
- | ERRORS opt_limit_clause
+ | ERRORS opt_global_limit_clause
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
| PROFILES_SYM
{ Lex->sql_command = SQLCOM_SHOW_PROFILES; }
- | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause
+ | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_PROFILE;
@@ -14068,7 +14079,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL,0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL,0))
MYSQL_YYABORT;
lex->create_info.storage_media= HA_SM_DEFAULT;
}
@@ -14076,7 +14087,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
MYSQL_YYABORT;
lex->table_type= TABLE_TYPE_VIEW;
}
@@ -14084,7 +14095,7 @@ show_param:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_SHOW_CREATE;
- if (unlikely(!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)))
+ if (!lex->first_select_lex()->add_table_to_list(thd, $3, NULL, 0))
MYSQL_YYABORT;
lex->table_type= TABLE_TYPE_SEQUENCE;
}
@@ -14301,7 +14312,7 @@ describe:
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LIST;
lex->sql_command= SQLCOM_SHOW_FIELDS;
- lex->select_lex.db= null_clex_str;
+ lex->first_select_lex()->db= null_clex_str;
lex->verbose= 0;
if (unlikely(prepare_schema_table(thd, lex, $2, SCH_COLUMNS)))
MYSQL_YYABORT;
@@ -14315,12 +14326,13 @@ describe:
explainable_command
{
LEX *lex=Lex;
- lex->select_lex.options|= SELECT_DESCRIBE;
+ lex->first_select_lex()->options|= SELECT_DESCRIBE;
}
;
explainable_command:
select
+ | select_into
| insert
| replace
| update
@@ -14341,6 +14353,8 @@ analyze_stmt_command:
opt_extended_describe:
EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
+ | EXTENDED_SYM ALL
+ { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; }
| PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
| opt_format_json {}
;
@@ -14383,8 +14397,7 @@ flush:
lex->type= 0;
lex->no_write_to_binlog= $2;
}
- flush_options
- {}
+ flush_options {}
;
flush_options:
@@ -14401,6 +14414,7 @@ flush_options:
opt_table_list opt_flush_lock
{}
| flush_options_list
+ {}
;
opt_flush_lock:
@@ -14656,7 +14670,7 @@ use:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CHANGE_DB;
- lex->select_lex.db= $2;
+ lex->first_select_lex()->db= $2;
}
;
@@ -14673,6 +14687,8 @@ load:
$2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML");
MYSQL_YYABORT;
}
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
}
load_data_lock opt_local INFILE TEXT_STRING_filesystem
{
@@ -14702,7 +14718,11 @@ load:
opt_xml_rows_identified_by
opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
opt_load_data_set_spec
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
data_or_xml:
@@ -14900,11 +14920,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- /*
- it is OK only emulate fix_fields, because we need only
- value of constant
- */
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| HEX_STRING
@@ -14913,7 +14928,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| BIN_NUM
@@ -14926,7 +14940,6 @@ hex_or_bin_String:
it is OK only emulate fix_fields, because we need only
value of constant
*/
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
;
@@ -15074,26 +15087,23 @@ NUM_literal:
temporal_literal:
DATE_SYM TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_DATE,
- true))))
+ if (unlikely(!($$= type_handler_newdate.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
| TIME_SYM TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_TIME,
- true))))
+ if (unlikely(!($$= type_handler_time2.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
| TIMESTAMP TEXT_STRING
{
- if (unlikely(!($$= create_temporal_literal(thd, $2.str, $2.length,
- YYCSCL,
- MYSQL_TYPE_DATETIME,
- true))))
+ if (unlikely(!($$= type_handler_datetime2.create_literal_item(thd,
+ $2.str, $2.length,
+ YYCSCL, true))))
MYSQL_YYABORT;
}
;
@@ -15109,17 +15119,21 @@ opt_with_clause:
with_clause:
- WITH opt_recursive
+ WITH opt_recursive
{
+ LEX *lex= Lex;
With_clause *with_clause=
new With_clause($2, Lex->curr_with_clause);
if (unlikely(with_clause == NULL))
MYSQL_YYABORT;
- Lex->derived_tables|= DERIVED_WITH;
- Lex->curr_with_clause= with_clause;
+ lex->derived_tables|= DERIVED_WITH;
+ lex->curr_with_clause= with_clause;
with_clause->add_to_list(Lex->with_clauses_list_last_next);
+ if (lex->current_select &&
+ lex->current_select->parsing_place == BEFORE_OPT_LIST)
+ lex->current_select->parsing_place= NO_MATTER;
}
- with_list
+ with_list
{
$$= Lex->curr_with_clause;
Lex->curr_with_clause= Lex->curr_with_clause->pop();
@@ -15148,11 +15162,10 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_name subselect remember_end ')'
+ AS '(' remember_name query_expression remember_end ')'
{
- With_element *elem= new With_element($1, *$2, $7->master_unit());
- if (unlikely(elem == NULL) ||
- unlikely(Lex->curr_with_clause->add_with_element(elem)))
+ With_element *elem= new With_element($1, *$2, $7);
+ if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
MYSQL_YYABORT;
if (unlikely(elem->set_unparsed_spec(thd, $6+1, $8)))
MYSQL_YYABORT;
@@ -16123,14 +16136,22 @@ set:
SET
{
LEX *lex=Lex;
+ if (lex->main_select_push())
+ MYSQL_YYABORT;
lex->set_stmt_init();
lex->var_list.empty();
sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
start_option_value_list
- {}
+ {
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
| SET STATEMENT_SYM
{
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
Lex->set_stmt_init();
}
set_stmt_option_value_following_option_type_list
@@ -16140,6 +16161,9 @@ set:
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
lex->stmt_var_list= lex->var_list;
lex->var_list.empty();
+ Lex->pop_select(); //main select
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
}
FOR_SYM verb_clause
{}
@@ -16608,7 +16632,7 @@ table_lock_list:
;
table_lock:
- table_ident opt_table_alias lock_option
+ table_ident opt_table_alias_clause lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
@@ -16653,27 +16677,36 @@ unlock:
*/
handler:
- HANDLER_SYM table_ident OPEN_SYM opt_table_alias
+ HANDLER_SYM
+ {
+ if (Lex->main_select_push())
+ MYSQL_YYABORT;
+ }
+ handler_tail
+ {
+ Lex->pop_select(); //main select
+ }
+
+handler_tail:
+ table_ident OPEN_SYM opt_table_alias_clause
{
LEX *lex= Lex;
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
lex->sql_command = SQLCOM_HA_OPEN;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, $4,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, $3, 0))
MYSQL_YYABORT;
}
- | HANDLER_SYM table_ident_nodb CLOSE_SYM
+ | table_ident_nodb CLOSE_SYM
{
LEX *lex= Lex;
if (unlikely(lex->sphead))
my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
lex->sql_command = SQLCOM_HA_CLOSE;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
MYSQL_YYABORT;
}
- | HANDLER_SYM table_ident_nodb READ_SYM
+ | table_ident_nodb READ_SYM
{
LEX *lex=Lex;
if (unlikely(lex->sphead))
@@ -16687,15 +16720,24 @@ handler:
lex->current_select->select_limit= one;
lex->current_select->offset_limit= 0;
lex->limit_rows_examined= 0;
- if (unlikely(!lex->current_select->add_table_to_list(thd, $2, 0,
- 0)))
+ if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
MYSQL_YYABORT;
}
- handler_read_or_scan opt_where_clause opt_limit_clause
+ handler_read_or_scan opt_where_clause opt_global_limit_clause
{
- Lex->expr_allows_subselect= TRUE;
+ LEX *lex=Lex;
+ lex->expr_allows_subselect= TRUE;
+ if (!lex->current_select->explicit_limit)
+ {
+ Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
+ if (one == NULL)
+ MYSQL_YYABORT;
+ lex->current_select->select_limit= one;
+ lex->current_select->offset_limit= 0;
+ lex->limit_rows_examined= 0;
+ }
/* Stored functions are not supported for HANDLER READ. */
- if (unlikely(Lex->uses_stored_routines()))
+ if (lex->uses_stored_routines())
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"stored functions in HANDLER ... READ");
@@ -17347,83 +17389,16 @@ release:
*/
unit_type_decl:
- UNION_SYM
- { $$= UNION_TYPE; }
+ UNION_SYM union_option
+ { $$.unit_type= UNION_TYPE; $$.distinct= $2; }
| INTERSECT_SYM
- { $$= INTERSECT_TYPE; }
+ { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
| EXCEPT_SYM
- { $$= EXCEPT_TYPE; }
-
-
-union_clause:
- /* empty */ {}
- | union_list
- ;
-
-union_list:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE)))
- MYSQL_YYABORT;
- }
- union_list_part2
- {
- /*
- Remove from the name resolution context stack the context of the
- last select in the union.
- */
- Lex->pop_context();
- }
- ;
-
-union_list_view:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, TRUE)))
- MYSQL_YYABORT;
- }
- query_expression_body_view
- {
- Lex->pop_context();
- }
- ;
-
-union_order_or_limit:
- {
- LEX *lex= thd->lex;
- DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
- SELECT_LEX *sel= lex->current_select;
- SELECT_LEX_UNIT *unit= sel->master_unit();
- SELECT_LEX *fake= unit->fake_select_lex;
- if (fake)
- {
- fake->no_table_names_allowed= 1;
- lex->current_select= fake;
- }
- thd->where= "global ORDER clause";
- }
- order_or_limit
- {
- thd->lex->current_select->no_table_names_allowed= 0;
- thd->where= "";
- }
- ;
-
-order_or_limit:
- order_clause opt_limit_clause
- | limit_clause
- ;
+ { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
/*
Start a UNION, for non-top level query expressions.
*/
-union_head_non_top:
- unit_type_decl union_option
- {
- if (unlikely(Lex->add_select_to_union_list((bool)$2, $1, FALSE)))
- MYSQL_YYABORT;
- }
- ;
union_option:
/* empty */ { $$=1; }
@@ -17431,128 +17406,10 @@ union_option:
| ALL { $$=0; }
;
-simple_table:
- query_specification { $$= $1; }
- | table_value_constructor { $$= $1; }
- ;
-
-table_value_constructor:
- VALUES
- {
- Lex->tvc_start();
- }
- values_list
- {
- $$= Lex->current_select;
- if (Lex->tvc_finalize())
- MYSQL_YYABORT;
- }
- ;
-
-/*
- Corresponds to the SQL Standard
- <query specification> ::=
- SELECT [ <set quantifier> ] <select list> <table expression>
-
- Notes:
- - We allow more options in addition to <set quantifier>
- - <table expression> is optional in MariaDB
-*/
-query_specification:
- SELECT_SYM select_init2_derived opt_table_expression
- {
- $$= Lex->current_select->master_unit()->first_select();
- }
- ;
-
-query_term_union_not_ready:
- simple_table order_or_limit opt_select_lock_type { $$= $1; }
- | '(' select_paren_derived ')' union_order_or_limit { $$= $2; }
- ;
-
-query_term_union_ready:
- simple_table opt_select_lock_type { $$= $1; }
- | '(' select_paren_derived ')' { $$= $2; }
- ;
-
-query_expression_body:
- query_term_union_not_ready { $$= $1; }
- | query_term_union_ready { $$= $1; }
- | query_term_union_ready union_list_derived { $$= $1; }
- ;
-
-/* Corresponds to <query expression> in the SQL:2003 standard. */
-subselect:
- subselect_start opt_with_clause query_expression_body subselect_end
- {
- $3->set_with_clause($2);
- $$= $3;
- }
- ;
-
-subselect_start:
- {
- LEX *lex=Lex;
- if (unlikely(!lex->expr_allows_subselect ||
- lex->sql_command == (int)SQLCOM_PURGE))
- {
- thd->parse_error();
- MYSQL_YYABORT;
- }
- /*
- we are making a "derived table" for the parenthesis
- as we need to have a lex level to fit the union
- after the parenthesis, e.g.
- (SELECT .. ) UNION ... becomes
- SELECT * FROM ((SELECT ...) UNION ...)
- */
- if (unlikely(mysql_new_select(Lex, 1, NULL)))
- MYSQL_YYABORT;
- }
- ;
-
-subselect_end:
- {
- LEX *lex=Lex;
-
- lex->check_automatic_up(UNSPECIFIED_TYPE);
- lex->pop_context();
- SELECT_LEX *child= lex->current_select;
- lex->current_select = lex->current_select->return_after_parsing();
- lex->nest_level--;
- lex->current_select->n_child_sum_items += child->n_sum_items;
- /*
- A subselect can add fields to an outer select. Reserve space for
- them.
- */
- lex->current_select->select_n_where_fields+=
- child->select_n_where_fields;
-
- /*
- Aggregate functions in having clause may add fields to an outer
- select. Count them also.
- */
- lex->current_select->select_n_having_items+=
- child->select_n_having_items;
- }
- ;
-
-opt_query_expression_options:
- /* empty */
- | query_expression_option_list
- ;
-
-query_expression_option_list:
- query_expression_option_list query_expression_option
- | query_expression_option
- ;
-
query_expression_option:
STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
| HIGH_PRIORITY
{
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
YYPS->m_mdl_type= MDL_SHARED_READ;
Select->options|= SELECT_HIGH_PRIORITY;
@@ -17561,18 +17418,8 @@ query_expression_option:
| UNIQUE_SYM { Select->options|= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT
- {
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
- Select->options|= OPTION_BUFFER_RESULT;
- }
- | SQL_CALC_FOUND_ROWS
- {
- if (unlikely(Lex->check_simple_select(&$1)))
- MYSQL_YYABORT;
- Select->options|= OPTION_FOUND_ROWS;
- }
+ | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
+ | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
| ALL { Select->options|= SELECT_ALL; }
;
@@ -17660,35 +17507,14 @@ view_select:
lex->parsing_options.allows_variable= FALSE;
lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr();
}
- opt_with_clause query_expression_body_view view_check_option
+ query_expression
+ view_check_option
{
- LEX *lex= Lex;
- size_t len= YYLIP->get_cpp_ptr() - lex->create_view->select.str;
- void *create_view_select= thd->memdup(lex->create_view->select.str, len);
- lex->create_view->select.length= len;
- lex->create_view->select.str= (char *) create_view_select;
- trim_whitespace(thd->charset(),
- &lex->create_view->select);
- lex->create_view->check= $4;
- lex->parsing_options.allows_variable= TRUE;
- lex->current_select->set_with_clause($2);
+ if (Lex->parsed_create_view($2, $3))
+ MYSQL_YYABORT;
}
;
-/*
- SQL Standard <query expression body> for VIEWs.
- Does not include INTO and PROCEDURE clauses.
-*/
-query_expression_body_view:
- SELECT_SYM select_options_and_item_list select_init3_view
- | table_value_constructor
- | table_value_constructor union_order_or_limit
- | table_value_constructor union_list_view
- | '(' select_paren_view ')'
- | '(' select_paren_view ')' union_order_or_limit
- | '(' select_paren_view ')' union_list_view
- ;
-
view_check_option:
/* empty */ { $$= VIEW_CHECK_NONE; }
| WITH CHECK_SYM OPTION { $$= VIEW_CHECK_CASCADED; }
@@ -17789,11 +17615,10 @@ trigger_tail:
sp_proc_stmt alternatives are not saving/restoring LEX, so
lex->query_tables can be wiped out.
*/
- if (unlikely(!lex->select_lex.
- add_table_to_list(thd, $10, (LEX_CSTRING*) 0,
- TL_OPTION_UPDATING,
- TL_READ_NO_INSERT,
- MDL_SHARED_NO_WRITE)))
+ if (!lex->first_select_lex()->
+ add_table_to_list(thd, $10, (LEX_CSTRING*) 0,
+ TL_OPTION_UPDATING, TL_READ_NO_INSERT,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
;
diff --git a/sql/structs.h b/sql/structs.h
index d8b95a3509a..355d6e75e48 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -758,6 +758,43 @@ public:
};
+class st_select_lex;
+
+class Lex_select_lock
+{
+public:
+ struct
+ {
+ uint defined_lock:1;
+ uint update_lock:1;
+ uint defined_timeout:1;
+ };
+ ulong timeout;
+
+
+ void empty()
+ {
+ defined_lock= update_lock= defined_timeout= FALSE;
+ timeout= 0;
+ }
+ void set_to(st_select_lex *sel);
+};
+
+class Lex_select_limit
+{
+public:
+ bool explicit_limit;
+ Item *select_limit, *offset_limit;
+
+ void empty()
+ {
+ explicit_limit= FALSE;
+ select_limit= offset_limit= NULL;
+ }
+};
+
+struct st_order;
+
class Load_data_param
{
protected:
@@ -794,4 +831,20 @@ public:
};
+class Timeval: public timeval
+{
+public:
+ Timeval(my_time_t sec, ulong usec)
+ {
+ tv_sec= sec;
+ tv_usec= usec;
+ }
+ Timeval &trunc(uint dec)
+ {
+ my_timeval_trunc(this, dec);
+ return *this;
+ }
+};
+
+
#endif /* STRUCTS_INCLUDED */
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 6d4c135683a..6d2dbbf646e 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2496,6 +2496,7 @@ export const char *optimizer_switch_names[]=
"orderby_uses_equalities",
"condition_pushdown_for_derived",
"split_materialized",
+ "condition_pushdown_for_subquery",
"default",
NullS
};
@@ -2720,17 +2721,6 @@ static Sys_var_ulong Sys_query_prealloc_size(
BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_thd_mem_root));
-#ifdef HAVE_SMEM
-static Sys_var_mybool Sys_shared_memory(
- "shared_memory", "Enable the shared memory",
- READ_ONLY GLOBAL_VAR(opt_enable_shared_memory), CMD_LINE(OPT_ARG),
- DEFAULT(FALSE));
-
-static Sys_var_charptr Sys_shared_memory_base_name(
- "shared_memory_base_name", "Base name of shared memory",
- READ_ONLY GLOBAL_VAR(shared_memory_base_name), CMD_LINE(REQUIRED_ARG),
- IN_FS_CHARSET, DEFAULT(0));
-#endif
// this has to be NO_CMD_LINE as the command-line option has a different name
static Sys_var_mybool Sys_skip_external_locking(
@@ -4052,6 +4042,16 @@ static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd,
return FALSE;
}
+static bool check_session_only_variable(sys_var *self, THD *,set_var *var)
+{
+ if (unlikely(var->type == OPT_GLOBAL))
+ {
+ my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), self->name.str, "SESSION");
+ return true;
+ }
+ return false;
+}
+
/**
This function checks if the sql_log_bin can be changed,
what is possible if:
@@ -4067,20 +4067,17 @@ static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd,
static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var)
{
if (check_has_super(self, thd, var))
- return TRUE;
+ return true;
- if (unlikely(var->type == OPT_GLOBAL))
- {
- my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), self->name.str, "SESSION");
- return TRUE;
- }
+ if (check_session_only_variable(self, thd, var))
+ return true;
if (unlikely(error_if_in_trans_or_substatement(thd,
ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN,
ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN)))
- return TRUE;
+ return true;
- return FALSE;
+ return false;
}
static Sys_var_mybool Sys_log_binlog(
@@ -5592,6 +5589,27 @@ static Sys_var_int Sys_keepalive_probes(
BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL));
+
+static bool update_tcp_nodelay(sys_var *self, THD *thd,
+ enum_var_type type)
+{
+ DBUG_ASSERT(thd);
+
+ Vio *vio = thd->net.vio;
+ if (vio)
+ return (MY_TEST(vio_nodelay(vio, thd->variables.tcp_nodelay)));
+
+ return false;
+}
+
+static Sys_var_mybool Sys_tcp_nodelay(
+ "tcp_nodelay",
+ "Set option TCP_NODELAY (disable Nagle's algorithm) on socket",
+ SESSION_VAR(tcp_nodelay), CMD_LINE(OPT_ARG),
+ DEFAULT(TRUE),NO_MUTEX_GUARD, NOT_IN_BINLOG,
+ ON_CHECK(check_session_only_variable),
+ ON_UPDATE(update_tcp_nodelay));
+
static Sys_var_charptr Sys_ignore_db_dirs(
"ignore_db_dirs",
"Specifies a directory to add to the ignore list when collecting "
diff --git a/sql/table.cc b/sql/table.cc
index 5eb789b779b..de5a71f6af1 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -44,6 +44,7 @@
#include "sql_cte.h"
#include "ha_sequence.h"
#include "sql_show.h"
+#include <atomic>
/* For MySQL 5.7 virtual fields */
#define MYSQL57_GENERATED_FIELD 128
@@ -79,7 +80,7 @@ LEX_CSTRING MYSQL_PROC_NAME= {STRING_WITH_LEN("proc")};
*/
static LEX_CSTRING parse_vcol_keyword= { STRING_WITH_LEN("PARSE_VCOL_EXPR ") };
-static int64 last_table_id;
+static std::atomic<ulong> last_table_id;
/* Functions defined in this file */
@@ -343,8 +344,8 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
*/
do
{
- share->table_map_id=(ulong) my_atomic_add64_explicit(&last_table_id, 1,
- MY_MEMORY_ORDER_RELAXED);
+ share->table_map_id=
+ last_table_id.fetch_add(1, std::memory_order_relaxed);
} while (unlikely(share->table_map_id == ~0UL));
}
DBUG_RETURN(share);
@@ -915,6 +916,54 @@ static uint upgrade_collation(ulong mysql_version, uint cs_number)
}
+void Column_definition_attributes::frm_pack_basic(uchar *buff) const
+{
+ int2store(buff + 3, length);
+ int2store(buff + 8, pack_flag);
+ buff[10]= (uchar) unireg_check;
+}
+
+
+void Column_definition_attributes::frm_unpack_basic(const uchar *buff)
+{
+ length= uint2korr(buff + 3);
+ pack_flag= uint2korr(buff + 8);
+ unireg_check= (Field::utype) MTYP_TYPENR((uint) buff[10]);
+}
+
+
+void Column_definition_attributes::frm_pack_charset(uchar *buff) const
+{
+ buff[11]= (uchar) (charset->number >> 8);
+ buff[14]= (uchar) charset->number;
+}
+
+
+bool Column_definition_attributes::frm_unpack_charset(TABLE_SHARE *share,
+ const uchar *buff)
+{
+ uint cs_org= buff[14] + (((uint) buff[11]) << 8);
+ uint cs_new= upgrade_collation(share->mysql_version, cs_org);
+ if (cs_org != cs_new)
+ share->incompatible_version|= HA_CREATE_USED_CHARSET;
+ if (cs_new && !(charset= get_charset(cs_new, MYF(0))))
+ {
+ const char *csname= get_charset_name((uint) cs_new);
+ char tmp[10];
+ if (!csname || csname[0] =='?')
+ {
+ my_snprintf(tmp, sizeof(tmp), "#%u", cs_new);
+ csname= tmp;
+ }
+ my_printf_error(ER_UNKNOWN_COLLATION,
+ "Unknown collation '%s' in table '%-.64s' definition",
+ MYF(0), csname, share->table_name.str);
+ return true;
+ }
+ return false;
+}
+
+
/*
In MySQL 5.7 the null bits for not stored virtual fields are last.
Calculate the position for these bits
@@ -1145,6 +1194,38 @@ end:
DBUG_RETURN(res);
}
+
+static const Type_handler *old_frm_type_handler(uint pack_flag,
+ uint interval_nr)
+{
+ enum_field_types field_type= (enum_field_types) f_packtype(pack_flag);
+ DBUG_ASSERT(field_type < 16);
+
+ if (!f_is_alpha(pack_flag))
+ return Type_handler::get_handler_by_real_type(field_type);
+
+ if (!f_is_packed(pack_flag))
+ {
+ if (field_type == MYSQL_TYPE_DECIMAL) // 3.23 or 4.0 string
+ return &type_handler_string;
+ if (field_type == MYSQL_TYPE_VARCHAR) // Since mysql-5.0
+ return &type_handler_varchar;
+ return NULL; // Error (bad frm?)
+ }
+
+ if (f_is_blob(pack_flag))
+ return &type_handler_blob; // QQ: exact type??
+
+ if (interval_nr)
+ {
+ if (f_is_enum(pack_flag))
+ return &type_handler_enum;
+ return &type_handler_set;
+ }
+ return Type_handler::get_handler_by_real_type(field_type);
+}
+
+
/**
Read data from a binary .frm file image into a TABLE_SHARE
@@ -1191,8 +1272,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
size_t UNINIT_VAR(options_len);
uchar *vcol_screen_pos;
const uchar *options= 0;
- size_t UNINIT_VAR(gis_options_len);
- const uchar *gis_options= 0;
+ LEX_CUSTRING gis_options= { NULL, 0};
KEY first_keyinfo;
uint len;
uint ext_key_parts= 0;
@@ -1288,10 +1368,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
case EXTRA2_GIS:
#ifdef HAVE_SPATIAL
{
- if (gis_options)
+ if (gis_options.str)
goto err;
- gis_options= extra2;
- gis_options_len= length;
+ gis_options.str= extra2;
+ gis_options.length= length;
}
#endif /*HAVE_SPATIAL*/
break;
@@ -1782,83 +1862,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{
- uint pack_flag, interval_nr, unireg_type, recpos, field_length;
- uint vcol_info_length=0;
- uint vcol_expr_length=0;
- enum_field_types field_type;
- CHARSET_INFO *charset=NULL;
- Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
+ uint interval_nr= 0, recpos;
LEX_CSTRING comment;
LEX_CSTRING name;
Virtual_column_info *vcol_info= 0;
- uint gis_length, gis_decimals, srid= 0;
- Field::utype unireg_check;
const Type_handler *handler;
uint32 flags= 0;
+ Column_definition_attributes attr;
if (new_frm_ver >= 3)
{
/* new frm file in 4.1 */
- field_length= uint2korr(strpos+3);
recpos= uint3korr(strpos+5);
- pack_flag= uint2korr(strpos+8);
- unireg_type= (uint) strpos[10];
- interval_nr= (uint) strpos[12];
uint comment_length=uint2korr(strpos+15);
- field_type=(enum_field_types) (uint) strpos[13];
-
- /* charset and geometry_type share the same byte in frm */
- if (field_type == MYSQL_TYPE_GEOMETRY)
- {
-#ifdef HAVE_SPATIAL
- uint gis_opt_read;
- Field_geom::storage_type st_type;
- geom_type= (Field::geometry_type) strpos[14];
- charset= &my_charset_bin;
- gis_opt_read= gis_field_options_read(gis_options, gis_options_len,
- &st_type, &gis_length, &gis_decimals, &srid);
- gis_options+= gis_opt_read;
- gis_options_len-= gis_opt_read;
-#else
- goto err;
-#endif
- }
- else
- {
- uint cs_org= strpos[14] + (((uint) strpos[11]) << 8);
- uint cs_new= upgrade_collation(share->mysql_version, cs_org);
- if (cs_org != cs_new)
- share->incompatible_version|= HA_CREATE_USED_CHARSET;
- if (!cs_new)
- charset= &my_charset_bin;
- else if (!(charset= get_charset(cs_new, MYF(0))))
- {
- const char *csname= get_charset_name((uint) cs_new);
- char tmp[10];
- if (!csname || csname[0] =='?')
- {
- my_snprintf(tmp, sizeof(tmp), "#%u", cs_new);
- csname= tmp;
- }
- my_printf_error(ER_UNKNOWN_COLLATION,
- "Unknown collation '%s' in table '%-.64s' definition",
- MYF(0), csname, share->table_name.str);
- goto err;
- }
- }
-
- if ((uchar)field_type == (uchar)MYSQL_TYPE_VIRTUAL)
- {
- if (!interval_nr) // Expect non-null expression
- goto err;
- /*
- MariaDB version 10.0 version.
- The interval_id byte in the .frm file stores the length of the
- expression statement for a virtual column.
- */
- vcol_info_length= interval_nr;
- interval_nr= 0;
- }
if (!comment_length)
{
@@ -1872,32 +1888,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
comment_pos+= comment_length;
}
- if (unireg_type & MYSQL57_GENERATED_FIELD)
+ if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL)
{
- unireg_type&= MYSQL57_GENERATED_FIELD;
-
/*
- MySQL 5.7 generated fields
-
- byte 1 = 1
- byte 2,3 = expr length
- byte 4 = stored_in_db
- byte 5.. = expr
+ MariaDB version 10.0 version.
+ The interval_id byte in the .frm file stores the length of the
+ expression statement for a virtual column.
*/
- if ((uint)(vcol_screen_pos)[0] != 1)
+ uint vcol_info_length= (uint) strpos[12];
+
+ if (!vcol_info_length) // Expect non-null expression
goto err;
- vcol_info= new (&share->mem_root) Virtual_column_info();
- vcol_info_length= uint2korr(vcol_screen_pos + 1);
- DBUG_ASSERT(vcol_info_length);
- vcol_info->stored_in_db= vcol_screen_pos[3];
- vcol_info->utf8= 0;
- vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;;
- share->virtual_fields++;
- vcol_info_length= 0;
- }
- if (vcol_info_length)
- {
+ attr.frm_unpack_basic(strpos);
+ if (attr.frm_unpack_charset(share, strpos))
+ goto err;
/*
Old virtual field information before 10.2
@@ -1911,7 +1916,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
vcol_info= new (&share->mem_root) Virtual_column_info();
bool opt_interval_id= (uint)vcol_screen_pos[0] == 2;
- field_type= (enum_field_types) (uchar) vcol_screen_pos[1];
+ enum_field_types ftype= (enum_field_types) (uchar) vcol_screen_pos[1];
+ if (!(handler= Type_handler::get_handler_by_real_type(ftype)))
+ goto err;
if (opt_interval_id)
interval_nr= (uint)vcol_screen_pos[3];
else if ((uint)vcol_screen_pos[0] != 1)
@@ -1919,26 +1926,63 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
bool stored= vcol_screen_pos[2] & 1;
vcol_info->stored_in_db= stored;
vcol_info->set_vcol_type(stored ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL);
- vcol_expr_length= vcol_info_length -
- (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id));
+ uint vcol_expr_length= vcol_info_length -
+ (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id));
vcol_info->utf8= 0; // before 10.2.1 the charset was unknown
int2store(vcol_screen_pos+1, vcol_expr_length); // for parse_vcol_defs()
vcol_screen_pos+= vcol_info_length;
share->virtual_fields++;
}
+ else
+ {
+ interval_nr= (uint) strpos[12];
+ enum_field_types field_type= (enum_field_types) strpos[13];
+ if (!(handler= Type_handler::get_handler_by_real_type(field_type)))
+ goto err; // Not supported field type
+ if (handler->Column_definition_attributes_frm_unpack(&attr, share,
+ strpos,
+ &gis_options))
+ goto err;
+ }
+
+ if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD)
+ {
+ attr.unireg_check= Field::NONE;
+
+ /*
+ MySQL 5.7 generated fields
+
+ byte 1 = 1
+ byte 2,3 = expr length
+ byte 4 = stored_in_db
+ byte 5.. = expr
+ */
+ if ((uint)(vcol_screen_pos)[0] != 1)
+ goto err;
+ vcol_info= new (&share->mem_root) Virtual_column_info();
+ uint vcol_info_length= uint2korr(vcol_screen_pos + 1);
+ DBUG_ASSERT(vcol_info_length);
+ vcol_info->stored_in_db= vcol_screen_pos[3];
+ vcol_info->utf8= 0;
+ vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;;
+ share->virtual_fields++;
+ }
}
else
{
- field_length= (uint) strpos[3];
+ attr.length= (uint) strpos[3];
recpos= uint2korr(strpos+4),
- pack_flag= uint2korr(strpos+6);
- pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files
- unireg_type= (uint) strpos[8];
+ attr.pack_flag= uint2korr(strpos+6);
+ attr.pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files
+ attr.unireg_check= (Field::utype) MTYP_TYPENR((uint) strpos[8]);
interval_nr= (uint) strpos[10];
/* old frm file */
- field_type= (enum_field_types) f_packtype(pack_flag);
- if (f_is_binary(pack_flag))
+ enum_field_types ftype= (enum_field_types) f_packtype(attr.pack_flag);
+ if (!(handler= Type_handler::get_handler_by_real_type(ftype)))
+ goto err; // Not supported field type
+
+ if (f_is_binary(attr.pack_flag))
{
/*
Try to choose the best 4.1 type:
@@ -1946,26 +1990,26 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
try to find a binary collation for character set.
- for other types (e.g. BLOB) just use my_charset_bin.
*/
- if (!f_is_blob(pack_flag))
+ if (!f_is_blob(attr.pack_flag))
{
// 3.23 or 4.0 string
- if (!(charset= get_charset_by_csname(share->table_charset->csname,
- MY_CS_BINSORT, MYF(0))))
- charset= &my_charset_bin;
+ if (!(attr.charset= get_charset_by_csname(share->table_charset->csname,
+ MY_CS_BINSORT, MYF(0))))
+ attr.charset= &my_charset_bin;
}
- else
- charset= &my_charset_bin;
}
else
- charset= share->table_charset;
+ attr.charset= share->table_charset;
bzero((char*) &comment, sizeof(comment));
+ if ((!(handler= old_frm_type_handler(attr.pack_flag, interval_nr))))
+ goto err; // Not supported field type
}
/* Remove >32 decimals from old files */
if (share->mysql_version < 100200)
- pack_flag&= ~FIELDFLAG_LONG_DECIMAL;
+ attr.pack_flag&= ~FIELDFLAG_LONG_DECIMAL;
- if (interval_nr && charset->mbminlen > 1)
+ if (interval_nr && attr.charset->mbminlen > 1)
{
/* Unescape UCS2 intervals from HEX notation */
TYPELIB *interval= share->intervals + interval_nr - 1;
@@ -1973,17 +2017,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
#ifndef TO_BE_DELETED_ON_PRODUCTION
- if (field_type == MYSQL_TYPE_NEWDECIMAL && !share->mysql_version)
+ if (handler->real_field_type() == MYSQL_TYPE_NEWDECIMAL &&
+ !share->mysql_version)
{
/*
Fix pack length of old decimal values from 5.0.3 -> 5.0.4
The difference is that in the old version we stored precision
in the .frm table while we now store the display_length
*/
- uint decimals= f_decimals(pack_flag);
- field_length= my_decimal_precision_to_length(field_length,
- decimals,
- f_is_dec(pack_flag) == 0);
+ uint decimals= f_decimals(attr.pack_flag);
+ attr.length=
+ my_decimal_precision_to_length((uint) attr.length, decimals,
+ f_is_dec(attr.pack_flag) == 0);
sql_print_error("Found incompatible DECIMAL field '%s' in %s; "
"Please do \"ALTER TABLE '%s' FORCE\" to fix it!",
share->fieldnames.type_names[i], share->table_name.str,
@@ -2014,7 +2059,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (flags & VERS_SYSTEM_FIELD)
{
- switch (field_type)
+ switch (handler->real_field_type())
{
case MYSQL_TYPE_TIMESTAMP2:
case MYSQL_TYPE_DATETIME2:
@@ -2036,22 +2081,17 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
/* Convert pre-10.2.2 timestamps to use Field::default_value */
- unireg_check= (Field::utype) MTYP_TYPENR(unireg_type);
name.str= fieldnames.type_names[i];
name.length= strlen(name.str);
- if (!(handler= Type_handler::get_handler_by_real_type(field_type)))
- goto err; // Not supported field type
+ attr.interval= interval_nr ? share->intervals + interval_nr - 1 : NULL;
+ Record_addr addr(record + recpos, null_pos, null_bit_pos);
*field_ptr= reg_field=
- make_field(share, &share->mem_root, record+recpos, (uint32) field_length,
- null_pos, null_bit_pos, pack_flag, handler, charset,
- geom_type, srid, unireg_check,
- (interval_nr ? share->intervals+interval_nr-1 : NULL),
- &name, flags);
+ attr.make_field(share, &share->mem_root, &addr, handler, &name, flags);
if (!reg_field) // Not supported field type
goto err;
- if (unireg_check == Field::TIMESTAMP_DNUN_FIELD ||
- unireg_check == Field::TIMESTAMP_DN_FIELD)
+ if (attr.unireg_check == Field::TIMESTAMP_DNUN_FIELD ||
+ attr.unireg_check == Field::TIMESTAMP_DN_FIELD)
{
reg_field->default_value= new (&share->mem_root) Virtual_column_info();
reg_field->default_value->set_vcol_type(VCOL_DEFAULT);
@@ -2075,10 +2115,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
status_var_increment(thd->status_var.feature_invisible_columns);
if (!reg_field->invisible)
share->visible_fields++;
- if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
+ if (handler->real_field_type() == MYSQL_TYPE_BIT &&
+ !f_bit_as_char(attr.pack_flag))
{
null_bits_are_used= 1;
- if ((null_bit_pos+= field_length & 7) > 7)
+ if ((null_bit_pos+= (uint) (attr.length & 7)) > 7)
{
null_pos++;
null_bit_pos-= 8;
@@ -2101,7 +2142,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
}
- if (f_no_default(pack_flag))
+ if (f_no_default(attr.pack_flag))
reg_field->flags|= NO_DEFAULT_VALUE_FLAG;
if (reg_field->unireg_check == Field::NEXT_NUMBER)
@@ -2693,7 +2734,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
if (lex->create_info.like())
return 1;
// ... create select
- if (lex->select_lex.item_list.elements)
+ if (lex->first_select_lex()->item_list.elements)
return 1;
// ... temporary
if (create_info->tmp_table())
@@ -2882,7 +2923,7 @@ bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol)
DBUG_RETURN(0);
vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0);
- DBUG_ASSERT(!vcol->expr->fixed);
+ DBUG_ASSERT(!vcol->expr->is_fixed());
DBUG_RETURN(fix_vcol_expr(thd, vcol));
}
@@ -2937,7 +2978,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
DBUG_PRINT("info", ("vcol: %p", vcol));
DBUG_ASSERT(func_expr);
- if (func_expr->fixed)
+ if (func_expr->is_fixed())
DBUG_RETURN(0); // nothing to do
if (fix_vcol_expr(thd, vcol))
@@ -2981,7 +3022,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
of the statement because the field item does not have a field
pointer at that time
*/
- myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_JUST_WARNING : 0;
+ myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_WARNING : 0;
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(warn),
"AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name);
if (!warn)
@@ -3428,17 +3469,6 @@ partititon_err:
(my_bitmap_map*) bitmaps, share->fields, FALSE);
bitmaps+= bitmap_size;
- /* Don't allocate vcol_bitmap if we don't need it */
- if (share->virtual_fields)
- {
- if (!(outparam->def_vcol_set= (MY_BITMAP*)
- alloc_root(&outparam->mem_root, sizeof(*outparam->def_vcol_set))))
- goto err;
- my_bitmap_init(outparam->def_vcol_set,
- (my_bitmap_map*) bitmaps, share->fields, FALSE);
- bitmaps+= bitmap_size;
- }
-
my_bitmap_init(&outparam->has_value_set,
(my_bitmap_map*) bitmaps, share->fields, FALSE);
bitmaps+= bitmap_size;
@@ -3631,7 +3661,7 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
int db_errno)
{
char buff[FN_REFLEN];
- const myf errortype= ME_ERROR+ME_WAITTANG; // Write fatals error to log
+ const myf errortype= ME_ERROR_LOG; // Write fatals error to log
DBUG_ENTER("open_table_error");
DBUG_PRINT("info", ("error: %d db_errno: %d", error, db_errno));
@@ -4887,7 +4917,7 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
if (where)
{
- if (where->fixed)
+ if (where->is_fixed())
where->update_used_tables();
else if (where->fix_fields(thd, &where))
DBUG_RETURN(TRUE);
@@ -4947,13 +4977,13 @@ bool TABLE_LIST::single_table_updatable()
{
if (!updatable)
return false;
- if (view && view->select_lex.table_list.elements == 1)
+ if (view && view->first_select_lex()->table_list.elements == 1)
{
/*
We need to check deeply only single table views. Multi-table views
will be turned to multi-table updates and then checked by leaf tables
*/
- return (((TABLE_LIST *)view->select_lex.table_list.first)->
+ return (((TABLE_LIST *)view->first_select_lex()->table_list.first)->
single_table_updatable());
}
return true;
@@ -4990,7 +5020,8 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
cond= table->on_expr->copy_andor_structure(thd);
if (!table->view)
DBUG_RETURN(cond);
- for (TABLE_LIST *tbl= (TABLE_LIST*)table->view->select_lex.table_list.first;
+ for (TABLE_LIST *tbl=
+ (TABLE_LIST*)table->view->first_select_lex()->table_list.first;
tbl;
tbl= tbl->next_local)
{
@@ -5032,7 +5063,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
{
DBUG_ENTER("TABLE_LIST::prep_check_option");
bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED;
- TABLE_LIST *merge_underlying_list= view->select_lex.get_table_list();
+ TABLE_LIST *merge_underlying_list= view->first_select_lex()->get_table_list();
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
{
/* see comment of check_opt_type parameter */
@@ -5150,7 +5181,7 @@ TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find)
if (!view)
return 0;
- for (TABLE_LIST *tbl= view->select_lex.get_table_list();
+ for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list();
tbl;
tbl= tbl->next_local)
{
@@ -5212,7 +5243,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure)
main_view->db.str);
const char *name_table= (main_view->view ? main_view->view_name.str :
main_view->table_name.str);
- my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0),
+ my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_WARNING : 0),
name_db, name_table);
return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR;
}
@@ -5256,7 +5287,7 @@ int TABLE::verify_constraints(bool ignore_failure)
}
field_error.append((*chk)->name.str);
my_error(ER_CONSTRAINT_FAILED,
- MYF(ignore_failure ? ME_JUST_WARNING : 0), field_error.c_ptr(),
+ MYF(ignore_failure ? ME_WARNING : 0), field_error.c_ptr(),
s->db.str, s->error_table_name());
return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR;
}
@@ -5348,7 +5379,8 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root)
{
DBUG_PRINT("info", ("setting insert_value for view"));
DBUG_ASSERT(is_view_or_derived() && is_merged_derived());
- for (TABLE_LIST *tbl= (TABLE_LIST*)view->select_lex.table_list.first;
+ for (TABLE_LIST *tbl=
+ (TABLE_LIST*)view->first_select_lex()->table_list.first;
tbl;
tbl= tbl->next_local)
if (tbl->set_insert_values(mem_root))
@@ -5515,7 +5547,7 @@ void TABLE_LIST::register_want_access(ulong want_access)
}
if (!view)
return;
- for (TABLE_LIST *tbl= view->select_lex.get_table_list();
+ for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list();
tbl;
tbl= tbl->next_local)
tbl->register_want_access(want_access);
@@ -5707,6 +5739,7 @@ void TABLE_LIST::set_check_materialized()
The subtree should be already excluded
*/
DBUG_ASSERT(!derived->first_select()->first_inner_unit() ||
+ derived->first_select()->first_inner_unit()->with_element ||
derived->first_select()->first_inner_unit()->first_select()->
exclude_from_table_unique_test);
}
@@ -5723,14 +5756,14 @@ TABLE *TABLE_LIST::get_real_join_table()
break;
/* we do not support merging of union yet */
DBUG_ASSERT(tbl->view == NULL ||
- tbl->view->select_lex.next_select() == NULL);
+ tbl->view->first_select_lex()->next_select() == NULL);
DBUG_ASSERT(tbl->derived == NULL ||
tbl->derived->first_select()->next_select() == NULL);
{
List_iterator_fast<TABLE_LIST>
ti(tbl->view != NULL ?
- tbl->view->select_lex.top_join_list :
+ tbl->view->first_select_lex()->top_join_list :
tbl->derived->first_select()->top_join_list);
for (;;)
{
@@ -5901,7 +5934,7 @@ Item *Field_iterator_view::create_item(THD *thd)
Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
LEX_CSTRING *name)
{
- bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
+ bool save_wrapper= thd->lex->first_select_lex()->no_wrap_view_item;
Item *field= *field_ref;
DBUG_ENTER("create_view_field");
@@ -5912,13 +5945,13 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
('mysql_schema_table' function). So we can return directly the
field. This case happens only for 'show & where' commands.
*/
- DBUG_ASSERT(field && field->fixed);
+ DBUG_ASSERT(field && field->is_fixed());
DBUG_RETURN(field);
}
DBUG_ASSERT(field);
thd->lex->current_select->no_wrap_view_item= TRUE;
- if (!field->fixed)
+ if (!field->is_fixed())
{
if (field->fix_fields(thd, field_ref))
{
@@ -5932,8 +5965,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
{
DBUG_RETURN(field);
}
- Name_resolution_context *context= view->view ? &view->view->select_lex.context :
- &thd->lex->select_lex.context;
+ Name_resolution_context *context= (view->view ?
+ &view->view->first_select_lex()->context:
+ &thd->lex->first_select_lex()->context);
Item *item= (new (thd->mem_root)
Item_direct_view_ref(thd, context, field_ref, view->alias.str,
name, view));
@@ -6256,13 +6290,12 @@ void TABLE::clear_column_bitmaps()
Reset column read/write usage. It's identical to:
bitmap_clear_all(&table->def_read_set);
bitmap_clear_all(&table->def_write_set);
- if (s->virtual_fields) bitmap_clear_all(table->def_vcol_set);
The code assumes that the bitmaps are allocated after each other, as
guaranteed by open_table_from_share()
*/
bzero((char*) def_read_set.bitmap,
s->column_bitmap_size * (s->virtual_fields ? 3 : 2));
- column_bitmaps_set(&def_read_set, &def_write_set, def_vcol_set);
+ column_bitmaps_set(&def_read_set, &def_write_set);
rpl_write_set= 0; // Safety
}
@@ -6409,13 +6442,8 @@ void TABLE::mark_columns_needed_for_delete()
Field **reg_field;
for (reg_field= field ; *reg_field ; reg_field++)
{
- Field *cur_field= *reg_field;
- if (cur_field->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG))
- {
- bitmap_set_bit(read_set, cur_field->field_index);
- if (cur_field->vcol_info)
- bitmap_set_bit(vcol_set, cur_field->field_index);
- }
+ if ((*reg_field)->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG))
+ mark_column_with_deps(*reg_field);
}
need_signal= true;
}
@@ -6494,13 +6522,7 @@ void TABLE::mark_columns_needed_for_update()
if (any_written && !all_read)
{
for (KEY_PART_INFO *kp= k->key_part; kp < kpend; kp++)
- {
- int idx= kp->fieldnr - 1;
- if (bitmap_fast_test_and_set(read_set, idx))
- continue;
- if (field[idx]->vcol_info)
- mark_virtual_col(field[idx]);
- }
+ mark_column_with_deps(field[kp->fieldnr - 1]);
}
}
need_signal= true;
@@ -6697,49 +6719,12 @@ void TABLE::mark_columns_per_binlog_row_image()
DBUG_ASSERT(FALSE);
}
}
- /*
- We have to ensure that all virtual columns that are part of read set
- are calculated.
- */
- if (vcol_set)
- bitmap_union(vcol_set, read_set);
file->column_bitmaps_signal();
}
DBUG_VOID_RETURN;
}
-/*
- @brief Mark a column as virtual used by the query
-
- @param field the field for the column to be marked
-
- @details
- The function marks the column for 'field' as virtual (computed)
- in the bitmap vcol_set.
- If the column is marked for the first time the expression to compute
- the column is traversed and all columns that are occurred there are
- marked in the read_set of the table.
-
- @retval
- TRUE if column is marked for the first time
- @retval
- FALSE otherwise
-*/
-
-bool TABLE::mark_virtual_col(Field *field)
-{
- bool res;
- DBUG_ASSERT(field->vcol_info);
- if (!(res= bitmap_fast_test_and_set(vcol_set, field->field_index)))
- {
- Item *vcol_item= field->vcol_info->expr;
- DBUG_ASSERT(vcol_item);
- vcol_item->walk(&Item::register_field_in_read_map, 1, 0);
- }
- return res;
-}
-
/*
@brief Mark virtual columns for update/insert commands
@@ -6781,13 +6766,13 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl
{
tmp_vfield= *vfield_ptr;
if (bitmap_is_set(write_set, tmp_vfield->field_index))
- bitmap_updated|= mark_virtual_col(tmp_vfield);
+ bitmap_updated|= mark_virtual_column_with_deps(tmp_vfield);
else if (tmp_vfield->vcol_info->stored_in_db ||
(tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG |
PART_INDIRECT_KEY_FLAG)))
{
bitmap_set_bit(write_set, tmp_vfield->field_index);
- mark_virtual_col(tmp_vfield);
+ mark_virtual_column_with_deps(tmp_vfield);
bitmap_updated= true;
}
}
@@ -6917,8 +6902,6 @@ void TABLE::mark_columns_used_by_virtual_fields(void)
void TABLE::mark_check_constraint_columns_for_read(void)
{
bitmap_union(read_set, s->check_set);
- if (vcol_set)
- bitmap_union(vcol_set, s->check_set);
}
@@ -7672,6 +7655,20 @@ public:
}
};
+
+/*
+ to satisfy ASSERT_COLUMN_MARKED_FOR_WRITE Field's assert we temporarily
+ mark field for write before storing the generated value in it
+*/
+#ifndef DBUG_OFF
+#define DBUG_FIX_WRITE_SET(f) bool _write_set_fixed= !bitmap_fast_test_and_set(write_set, (f)->field_index)
+#define DBUG_RESTORE_WRITE_SET(f) if (_write_set_fixed) bitmap_clear_bit(write_set, (f)->field_index)
+#else
+#define DBUG_FIX_WRITE_SET(f)
+#define DBUG_RESTORE_WRITE_SET(f)
+#endif
+
+
/*
@brief Compute values for virtual columns used in query
@@ -7735,17 +7732,17 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
switch (update_mode) {
case VCOL_UPDATE_FOR_READ:
update= (!vcol_info->stored_in_db &&
- bitmap_is_set(vcol_set, vf->field_index));
+ bitmap_is_set(read_set, vf->field_index));
swap_values= 1;
break;
case VCOL_UPDATE_FOR_DELETE:
case VCOL_UPDATE_FOR_WRITE:
- update= bitmap_is_set(vcol_set, vf->field_index);
+ update= bitmap_is_set(read_set, vf->field_index);
break;
case VCOL_UPDATE_FOR_REPLACE:
update= ((!vcol_info->stored_in_db &&
(vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) &&
- bitmap_is_set(vcol_set, vf->field_index)) ||
+ bitmap_is_set(read_set, vf->field_index)) ||
update_all_columns);
if (update && (vf->flags & BLOB_FLAG))
{
@@ -7765,7 +7762,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
/* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */
update= (!vcol_info->stored_in_db &&
(vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) &&
- !bitmap_is_set(vcol_set, vf->field_index));
+ !bitmap_is_set(read_set, vf->field_index));
swap_values= 1;
break;
}
@@ -7774,8 +7771,10 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode)
{
int field_error __attribute__((unused)) = 0;
/* Compute the actual value of the virtual fields */
+ DBUG_FIX_WRITE_SET(vf);
if (vcol_info->expr->save_in_field(vf, 0))
field_error= error= 1;
+ DBUG_RESTORE_WRITE_SET(vf);
DBUG_PRINT("info", ("field '%s' - updated error: %d",
vf->field_name.str, field_error));
if (swap_values && (vf->flags & BLOB_FLAG))
@@ -7809,7 +7808,9 @@ int TABLE::update_virtual_field(Field *vf)
in_use->set_n_backup_active_arena(expr_arena, &backup_arena);
bitmap_clear_all(&tmp_set);
vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set);
+ DBUG_FIX_WRITE_SET(vf);
vf->vcol_info->expr->save_in_field(vf, 0);
+ DBUG_RESTORE_WRITE_SET(vf);
in_use->restore_active_arena(expr_arena, &backup_arena);
DBUG_RETURN(in_use->is_error());
}
@@ -8474,200 +8475,6 @@ double KEY::actual_rec_per_key(uint i)
}
-/**
- @brief
- Mark subformulas of a condition unusable for the condition pushed into table
-
- @param cond The condition whose subformulas are to be marked
-
- @details
- This method recursively traverses the AND-OR condition cond and for each subformula
- of the codition it checks whether it can be usable for the extraction of a condition
- that can be pushed into this table. The subformulas that are not usable are
- marked with the flag NO_EXTRACTION_FL.
- @note
- This method is called before any call of TABLE_LIST::build_pushable_cond_for_table.
- The flag NO_EXTRACTION_FL set in a subformula allows to avoid building clone
- for the subformula when extracting the pushable condition.
-*/
-
-void TABLE_LIST::check_pushable_cond_for_table(Item *cond)
-{
- table_map tab_map= table->map;
- cond->clear_extraction_flag();
- if (cond->type() == Item::COND_ITEM)
- {
- bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC;
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
- uint count= 0;
- Item *item;
- while ((item=li++))
- {
- check_pushable_cond_for_table(item);
- if (item->get_extraction_flag() != NO_EXTRACTION_FL)
- count++;
- else if (!and_cond)
- break;
- }
- if ((and_cond && count == 0) || item)
- {
- cond->set_extraction_flag(NO_EXTRACTION_FL);
- if (and_cond)
- li.rewind();
- while ((item= li++))
- item->clear_extraction_flag();
- }
- }
- else if (!cond->excl_dep_on_table(tab_map))
- cond->set_extraction_flag(NO_EXTRACTION_FL);
-}
-
-
-/**
- @brief
- Build condition extractable from the given one depended only on this table
-
- @param thd The thread handle
- @param cond The condition from which the pushable one is to be extracted
-
- @details
- For the given condition cond this method finds out what condition depended
- only on this table can be extracted from cond. If such condition C exists
- the method builds the item for it.
- The method uses the flag NO_EXTRACTION_FL set by the preliminary call of
- the method TABLE_LIST::check_pushable_cond_for_table to figure out whether
- a subformula depends only on this table or not.
- @note
- The built condition C is always implied by the condition cond
- (cond => C). The method tries to build the most restictive such
- condition (i.e. for any other condition C' such that cond => C'
- we have C => C').
- @note
- The build item is not ready for usage: substitution for the field items
- has to be done and it has to be re-fixed.
-
- @retval
- the built condition pushable into this table if such a condition exists
- NULL if there is no such a condition
-*/
-
-Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond)
-{
- table_map tab_map= table->map;
- bool is_multiple_equality= cond->type() == Item::FUNC_ITEM &&
- ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC;
- if (cond->get_extraction_flag() == NO_EXTRACTION_FL)
- return 0;
- if (cond->type() == Item::COND_ITEM)
- {
- bool cond_and= false;
- Item_cond *new_cond;
- if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
- {
- cond_and= true;
- new_cond=new (thd->mem_root) Item_cond_and(thd);
- }
- else
- new_cond= new (thd->mem_root) Item_cond_or(thd);
- if (!new_cond)
- return 0;
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
- Item *item;
- bool is_fix_needed= false;
- while ((item=li++))
- {
- if (item->get_extraction_flag() == NO_EXTRACTION_FL)
- {
- if (!cond_and)
- return 0;
- continue;
- }
- Item *fix= build_pushable_cond_for_table(thd, item);
- if (!fix && !cond_and)
- return 0;
- if (!fix)
- continue;
-
- if (fix->type() == Item::COND_ITEM &&
- ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC)
- is_fix_needed= true;
-
- new_cond->argument_list()->push_back(fix, thd->mem_root);
- }
- if (is_fix_needed && new_cond->fix_fields(thd, 0))
- return 0;
-
- switch (new_cond->argument_list()->elements)
- {
- case 0:
- return 0;
- case 1:
- return new_cond->argument_list()->head();
- default:
- return new_cond;
- }
- }
- else if (is_multiple_equality)
- {
- if (!(cond->used_tables() & tab_map))
- return 0;
- Item *new_cond= NULL;
- int i= 0;
- Item_equal *item_equal= (Item_equal *) cond;
- Item *left_item = item_equal->get_const();
- Item_equal_fields_iterator it(*item_equal);
- Item *item;
- if (!left_item)
- {
- while ((item=it++))
- if (item->used_tables() == tab_map)
- {
- left_item= item;
- break;
- }
- }
- if (!left_item)
- return 0;
- while ((item=it++))
- {
- if (!(item->used_tables() == tab_map))
- continue;
- Item_func_eq *eq= 0;
- Item *left_item_clone= left_item->build_clone(thd);
- Item *right_item_clone= item->build_clone(thd);
- if (left_item_clone && right_item_clone)
- {
- left_item_clone->set_item_equal(NULL);
- right_item_clone->set_item_equal(NULL);
- eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone,
- left_item_clone);
- }
- if (eq)
- {
- i++;
- switch (i)
- {
- case 1:
- new_cond= eq;
- break;
- case 2:
- new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq);
- break;
- default:
- ((Item_cond_and*)new_cond)->argument_list()->push_back(eq,
- thd->mem_root);
- }
- }
- }
- if (new_cond)
- new_cond->fix_fields(thd, &new_cond);
- return new_cond;
- }
- else if (cond->get_extraction_flag() != NO_EXTRACTION_FL)
- return cond->build_clone(thd);
- return 0;
-}
-
LEX_CSTRING *fk_option_name(enum_fk_option opt)
{
static LEX_CSTRING names[]=
@@ -8754,7 +8561,7 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id)
return true;
store(FLD_BEGIN_TS, thd->transaction_time());
- timeval end_time= {thd->query_start(), long(thd->query_start_sec_part())};
+ timeval end_time= {thd->query_start(), int(thd->query_start_sec_part())};
store(FLD_TRX_ID, start_id);
store(FLD_COMMIT_ID, end_id);
store(FLD_COMMIT_TS, end_time);
@@ -8775,7 +8582,7 @@ bool TR_table::query(ulonglong trx_id)
READ_RECORD info;
int error;
List<TABLE_LIST> dummy;
- SELECT_LEX &slex= thd->lex->select_lex;
+ SELECT_LEX &slex= *(thd->lex->first_select_lex());
Name_resolution_context_backup backup(slex.context, *this);
Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]);
Item *value= newx Item_int(thd, trx_id);
@@ -8805,7 +8612,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
READ_RECORD info;
int error;
List<TABLE_LIST> dummy;
- SELECT_LEX &slex= thd->lex->select_lex;
+ SELECT_LEX &slex= *(thd->lex->first_select_lex());
Name_resolution_context_backup backup(slex.context, *this);
Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]);
Item *value= newx Item_datetime_literal(thd, &commit_time, 6);
@@ -9054,7 +8861,8 @@ bool Vers_history_point::resolve_unit(THD *thd)
return false;
if (item->fix_fields_if_needed(thd, &item))
return true;
- return item->this_item()->type_handler_for_system_time()->
+ return item->this_item()->real_type_handler()->
+ type_handler_for_system_time()->
Vers_history_point_resolve_unit(thd, this);
}
diff --git a/sql/table.h b/sql/table.h
index 80f5e1283a3..b75fa9074a4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1153,8 +1153,6 @@ public:
MY_BITMAP cond_set; /* used to mark fields from sargable conditions*/
/* Active column sets */
MY_BITMAP *read_set, *write_set, *rpl_write_set;
- /* Set if using virtual fields */
- MY_BITMAP *vcol_set, *def_vcol_set;
/* On INSERT: fields that the user specified a value for */
MY_BITMAP has_value_set;
@@ -1375,7 +1373,9 @@ public:
void mark_columns_needed_for_delete(void);
void mark_columns_needed_for_insert(void);
void mark_columns_per_binlog_row_image(void);
- bool mark_virtual_col(Field *field);
+ inline bool mark_column_with_deps(Field *field);
+ inline bool mark_virtual_column_with_deps(Field *field);
+ inline void mark_virtual_column_deps(Field *field);
bool mark_virtual_columns_for_write(bool insert_fl);
bool check_virtual_columns_marked_for_read();
bool check_virtual_columns_marked_for_write();
@@ -1397,39 +1397,21 @@ public:
if (file)
file->column_bitmaps_signal();
}
- inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
- MY_BITMAP *write_set_arg,
- MY_BITMAP *vcol_set_arg)
- {
- read_set= read_set_arg;
- write_set= write_set_arg;
- vcol_set= vcol_set_arg;
- if (file)
- file->column_bitmaps_signal();
- }
inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg,
MY_BITMAP *write_set_arg)
{
read_set= read_set_arg;
write_set= write_set_arg;
}
- inline void column_bitmaps_set_no_signal(MY_BITMAP *read_set_arg,
- MY_BITMAP *write_set_arg,
- MY_BITMAP *vcol_set_arg)
- {
- read_set= read_set_arg;
- write_set= write_set_arg;
- vcol_set= vcol_set_arg;
- }
inline void use_all_columns()
{
column_bitmaps_set(&s->all_set, &s->all_set);
}
+ inline void use_all_stored_columns();
inline void default_column_bitmaps()
{
read_set= &def_read_set;
write_set= &def_write_set;
- vcol_set= def_vcol_set; /* Note that this may be 0 */
rpl_write_set= 0;
}
/** Should this instance of the table be reopened? */
@@ -2601,8 +2583,6 @@ struct TABLE_LIST
return false;
}
void set_lock_type(THD* thd, enum thr_lock_type lock);
- void check_pushable_cond_for_table(Item *cond);
- Item *build_pushable_cond_for_table(THD *thd, Item *cond);
private:
bool prep_check_option(THD *thd, uint8 check_opt_type);
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index 61e54c8f0f9..e82bb13228b 100644
--- a/sql/table_cache.cc
+++ b/sql/table_cache.cc
@@ -645,7 +645,7 @@ bool tdc_init(void)
void tdc_start_shutdown(void)
{
- DBUG_ENTER("table_def_start_shutdown");
+ DBUG_ENTER("tdc_start_shutdown");
if (tdc_inited)
{
/*
diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc
index 0cc683c631d..3bc1ae3b371 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -75,7 +75,6 @@ static bool skip_completion_port_on_success = false;
io_completion_callback - handle client request
timer_callback - handle wait timeout (kill connection)
- shm_read_callback, shm_close_callback - shared memory stuff
login_callback - user login (submitted as threadpool work)
*/
@@ -89,9 +88,6 @@ static void CALLBACK io_completion_callback(PTP_CALLBACK_INSTANCE instance,
static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work);
-static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance,
- PVOID Context, PTP_WAIT wait,TP_WAIT_RESULT wait_result);
-
static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance);
/* Get current time as Windows time */
@@ -120,7 +116,6 @@ public:
PTP_CALLBACK_INSTANCE callback_instance;
PTP_IO io;
PTP_TIMER timer;
- PTP_WAIT shm_read;
PTP_WORK work;
bool long_callback;
@@ -149,7 +144,6 @@ TP_connection_win::TP_connection_win(CONNECT *c) :
callback_instance(0),
io(0),
timer(0),
- shm_read(0),
work(0)
{
}
@@ -170,30 +164,20 @@ int TP_connection_win::init()
case VIO_TYPE_NAMEDPIPE:
handle= (HANDLE)vio->hPipe;
break;
- case VIO_TYPE_SHARED_MEMORY:
- handle= vio->event_server_wrote;
- break;
default:
abort();
}
- if (vio_type == VIO_TYPE_SHARED_MEMORY)
+
+ /* Performance tweaks (s. MSDN documentation)*/
+ UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE;
+ if (skip_completion_port_on_success)
{
- CHECK_ALLOC_ERROR(shm_read= CreateThreadpoolWait(shm_read_callback, this, &callback_environ));
+ flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
}
- else
- {
- /* Performance tweaks (s. MSDN documentation)*/
- UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE;
- if (skip_completion_port_on_success)
- {
- flags |= FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
- }
- (void)SetFileCompletionNotificationModes(handle, flags);
- /* Assign io completion callback */
- CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ));
- }
-
+ (void)SetFileCompletionNotificationModes(handle, flags);
+ /* Assign io completion callback */
+ CHECK_ALLOC_ERROR(io= CreateThreadpoolIo(handle, io_completion_callback, this, &callback_environ));
CHECK_ALLOC_ERROR(timer= CreateThreadpoolTimer(timer_callback, this, &callback_environ));
CHECK_ALLOC_ERROR(work= CreateThreadpoolWork(work_callback, this, &callback_environ));
return 0;
@@ -214,11 +198,6 @@ int TP_connection_win::start_io()
DWORD last_error= 0;
int retval;
- if (shm_read)
- {
- SetThreadpoolWait(shm_read, handle, NULL);
- return 0;
- }
StartThreadpoolIo(io);
if (vio_type == VIO_TYPE_TCPIP || vio_type == VIO_TYPE_SSL)
@@ -297,9 +276,6 @@ TP_connection_win::~TP_connection_win()
if (io)
CloseThreadpoolIo(io);
- if (shm_read)
- CloseThreadpoolWait(shm_read);
-
if (work)
CloseThreadpoolWork(work);
@@ -420,29 +396,6 @@ static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance,
}
}
-
-/*
- Shared memory read callback.
- Invoked when read event is set on connection.
-*/
-
-static void CALLBACK shm_read_callback(PTP_CALLBACK_INSTANCE instance,
- PVOID context, PTP_WAIT wait,TP_WAIT_RESULT wait_result)
-{
- TP_connection_win *c= (TP_connection_win *)context;
- /* Disarm wait. */
- SetThreadpoolWait(wait, NULL, NULL);
-
- /*
- This is an autoreset event, and one wakeup is eaten already by threadpool,
- and the current state is "not set". Thus we need to reset the event again,
- or vio_read will hang.
- */
- SetEvent(c->handle);
- tp_callback(instance, context);
-}
-
-
static void CALLBACK work_callback(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_WORK work)
{
tp_callback(instance, context);
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 6540e11578b..4692b2d74d1 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -897,32 +897,12 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
while ((field=it++))
{
uint recpos;
- int2store(buff+3, field->length);
/* The +1 is here becasue the col offset in .frm file have offset 1 */
recpos= field->offset+1 + (uint) data_offset;
int3store(buff+5,recpos);
- int2store(buff+8,field->pack_flag);
- buff[10]= (uchar) field->unireg_check;
buff[12]= (uchar) field->interval_id;
- buff[13]= (uchar) field->real_field_type();
- if (field->real_field_type() == MYSQL_TYPE_GEOMETRY)
- {
- buff[11]= 0;
- buff[14]= (uchar) field->geom_type;
-#ifndef HAVE_SPATIAL
- DBUG_ASSERT(0); // Should newer happen
-#endif
- }
- else if (field->charset)
- {
- buff[11]= (uchar) (field->charset->number >> 8);
- buff[14]= (uchar) field->charset->number;
- }
- else
- {
- buff[11]= buff[14]= 0; // Numerical
- }
-
+ buff[13]= (uchar) field->type_handler()->real_field_type();
+ field->type_handler()->Column_definition_attributes_frm_pack(field, buff);
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
@@ -1043,21 +1023,16 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
while ((field=it++))
{
+ Record_addr addr(buff + field->offset + data_offset,
+ null_pos + null_count / 8, null_count & 7);
+ Column_definition_attributes tmp(*field);
+ tmp.interval= field->save_interval ?
+ field->save_interval : field->interval;
/* regfield don't have to be deleted as it's allocated on THD::mem_root */
- Field *regfield= make_field(&share, thd->mem_root,
- buff+field->offset + data_offset,
- (uint32)field->length,
- null_pos + null_count / 8,
- null_count & 7,
- field->pack_flag,
- field->type_handler(),
- field->charset,
- field->geom_type, field->srid,
- field->unireg_check,
- field->save_interval ? field->save_interval
- : field->interval,
- &field->field_name,
- field->flags);
+ Field *regfield= tmp.make_field(&share, thd->mem_root, &addr,
+ field->type_handler(),
+ &field->field_name,
+ field->flags);
if (!regfield)
{
error= 1;
diff --git a/sql/unireg.h b/sql/unireg.h
index 88d0c882824..6f224ab4894 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -56,11 +56,6 @@
#endif
#define ER_THD_OR_DEFAULT(thd,X) ((thd) ? ER_THD(thd, (X)) : ER_DEFAULT(X))
-
-#define ME_INFO (ME_HOLDTANG | ME_NOREFRESH)
-#define ME_ERROR (ME_BELL | ME_NOREFRESH)
-#define MYF_RW MYF(MY_WME+MY_NABP) /* Vid my_read & my_write */
-
#define SPECIAL_USE_LOCKS 1 /* Lock used databases */
#define SPECIAL_NO_NEW_FUNC 2 /* Skip new functions */
#define SPECIAL_SKIP_SHOW_DB 4 /* Don't allow 'show db' */
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 76b27c91d01..667fdb779ea 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1327,7 +1327,7 @@ static int
create_view_query(THD *thd, uchar** buf, size_t* buf_len)
{
LEX *lex= thd->lex;
- SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX *select_lex= lex->first_select_lex();
TABLE_LIST *first_table= select_lex->table_list.first;
TABLE_LIST *views = first_table;
LEX_USER *definer;
@@ -1419,7 +1419,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
DBUG_ASSERT(table_list || db);
LEX* lex= thd->lex;
- SELECT_LEX* select_lex= &lex->select_lex;
+ SELECT_LEX* select_lex= lex->first_select_lex();
TABLE_LIST* first_table= select_lex->table_list.first;
switch (lex->sql_command)