summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/event_data_objects.cc6
-rw-r--r--sql/event_parse_data.cc10
-rw-r--r--sql/events.cc47
-rw-r--r--sql/field.cc1284
-rw-r--r--sql/field.h458
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/filesort.cc31
-rw-r--r--sql/ha_partition.cc4
-rw-r--r--sql/handle_connections_win.cc555
-rw-r--r--sql/handle_connections_win.h20
-rw-r--r--sql/handler.cc19
-rw-r--r--sql/handler.h2
-rw-r--r--sql/init.h2
-rw-r--r--sql/item.cc1180
-rw-r--r--sql/item.h1313
-rw-r--r--sql/item_buff.cc25
-rw-r--r--sql/item_cmpfunc.cc479
-rw-r--r--sql/item_cmpfunc.h97
-rw-r--r--sql/item_create.cc110
-rw-r--r--sql/item_create.h15
-rw-r--r--sql/item_func.cc407
-rw-r--r--sql/item_func.h403
-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.h30
-rw-r--r--sql/item_strfunc.cc46
-rw-r--r--sql/item_strfunc.h17
-rw-r--r--sql/item_subselect.cc50
-rw-r--r--sql/item_subselect.h27
-rw-r--r--sql/item_sum.cc98
-rw-r--r--sql/item_sum.h65
-rw-r--r--sql/item_timefunc.cc873
-rw-r--r--sql/item_timefunc.h680
-rw-r--r--sql/item_vers.cc7
-rw-r--r--sql/item_vers.h2
-rw-r--r--sql/item_windowfunc.cc13
-rw-r--r--sql/item_windowfunc.h6
-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.h136
-rw-r--r--sql/mysqld.cc890
-rw-r--r--sql/mysqld.h6
-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/partition_info.h5
-rw-r--r--sql/procedure.h14
-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/share/errmsg-utf8.txt2
-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_acl.cc1437
-rw-r--r--sql/sql_admin.cc30
-rw-r--r--sql/sql_alter.cc9
-rw-r--r--sql/sql_analyse.cc103
-rw-r--r--sql/sql_base.cc68
-rw-r--r--sql/sql_base.h6
-rw-r--r--sql/sql_basic_types.h83
-rw-r--r--sql/sql_binlog.cc2
-rw-r--r--sql/sql_cache.cc11
-rw-r--r--sql/sql_class.cc25
-rw-r--r--sql/sql_class.h85
-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.cc213
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_error.h4
-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.cc136
-rw-r--r--sql/sql_partition.cc22
-rw-r--r--sql/sql_partition_admin.cc4
-rw-r--r--sql/sql_plugin.cc76
-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.cc335
-rw-r--r--sql/sql_time.h106
-rw-r--r--sql/sql_trigger.cc25
-rw-r--r--sql/sql_truncate.cc2
-rw-r--r--sql/sql_tvc.cc11
-rw-r--r--sql/sql_type.cc2048
-rw-r--r--sql/sql_type.h1843
-rw-r--r--sql/sql_type_int.h38
-rw-r--r--sql/sql_union.cc10
-rw-r--r--sql/sql_update.cc65
-rw-r--r--sql/sql_view.cc53
-rw-r--r--sql/sql_yacc.yy2175
-rw-r--r--sql/sql_yacc_ora.yy2061
-rw-r--r--sql/structs.h60
-rw-r--r--sql/sys_vars.cc56
-rw-r--r--sql/sys_vars.ic4
-rw-r--r--sql/table.cc658
-rw-r--r--sql/table.h28
-rw-r--r--sql/table_cache.cc2
-rw-r--r--sql/threadpool_win.cc94
-rw-r--r--sql/unireg.cc47
-rw-r--r--sql/unireg.h5
-rw-r--r--sql/wsrep_mysqld.cc11
127 files changed, 15734 insertions, 10767 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index d85e588abeb..83bf909192e 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -152,6 +152,7 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR
ADD_DEFINITIONS(-DHAVE_POOL_OF_THREADS)
IF(WIN32)
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_win.cc)
+ SET(SQL_SOURCE ${SQL_SOURCE} handle_connections_win.cc)
ENDIF()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_generic.cc)
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 86a710f87c6..a6803982171 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -654,7 +654,7 @@ my_time_t
add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
interval_type scale, INTERVAL interval)
{
- if (date_add_interval(ltime, scale, interval))
+ if (date_add_interval(current_thd, ltime, scale, interval))
return 0;
uint not_used;
@@ -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..bfda8438885 100644
--- a/sql/event_parse_data.cc
+++ b/sql/event_parse_data.cc
@@ -216,7 +216,7 @@ Event_parse_data::init_execute_at(THD *thd)
(starts_null && ends_null)));
DBUG_ASSERT(starts_null && ends_null);
- if (item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_execute_at->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
@@ -275,7 +275,7 @@ Event_parse_data::init_interval(THD *thd)
if (item_expression->fix_fields(thd, &item_expression))
goto wrong_value;
- if (get_interval_value(item_expression, interval, &interval_tmp))
+ if (get_interval_value(thd, item_expression, interval, &interval_tmp))
goto wrong_value;
expression= 0;
@@ -378,7 +378,7 @@ Event_parse_data::init_starts(THD *thd)
if (item_starts->fix_fields(thd, &item_starts))
goto wrong_value;
- if (item_starts->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_starts->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto wrong_value;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
@@ -433,7 +433,7 @@ Event_parse_data::init_ends(THD *thd)
goto error_bad_params;
DBUG_PRINT("info", ("convert to TIME"));
- if (item_ends->get_date(&ltime, TIME_NO_ZERO_DATE))
+ if (item_ends->get_date(thd, &ltime, TIME_NO_ZERO_DATE))
goto error_bad_params;
ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
@@ -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 c3a578f1097..196c8df591d 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -336,7 +336,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
DBUG_RETURN(TRUE);
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (lock_object_name(thd, MDL_key::EVENT,
parse_data->dbname.str, parse_data->name.str))
@@ -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
@@ -419,10 +419,10 @@ Events::create_event(THD *thd, Event_parse_data *parse_data)
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
-
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -550,9 +550,10 @@ Events::update_event(THD *thd, Event_parse_data *parse_data,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -617,9 +618,10 @@ Events::drop_event(THD *thd, const LEX_CSTRING *dbname,
thd->restore_stmt_binlog_format(save_binlog_format);
DBUG_RETURN(ret);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -824,12 +826,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 +927,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 +949,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 +1166,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 +1192,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 +1231,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 4ba31e17fa4..d7214687e2d 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);
}
@@ -1823,7 +1832,7 @@ int Field::store_timestamp(my_time_t ts, ulong sec_part)
{
MYSQL_TIME ltime;
THD *thd= get_thd();
- thd->timestamp_to_TIME(&ltime, ts, sec_part, 0);
+ thd->timestamp_to_TIME(&ltime, ts, sec_part, date_mode_t(0));
return store_time_dec(&ltime, decimals());
}
@@ -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));
@@ -2063,17 +2064,16 @@ my_decimal* Field_int::val_decimal(my_decimal *decimal_value)
}
-bool Field_int::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_int::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
ASSERT_COLUMN_MARKED_FOR_READ;
- longlong nr= val_int();
- bool neg= !(flags & UNSIGNED_FLAG) && nr < 0;
- return int_to_datetime_with_warn(neg, neg ? -nr : nr, ltime, fuzzydate,
- field_name.str);
+ Longlong_hybrid nr(val_int(), (flags & UNSIGNED_FLAG));
+ return int_to_datetime_with_warn(get_thd(), nr, ltime,
+ fuzzydate, field_name.str);
}
-bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id)
+bool Field_vers_trx_id::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id)
{
ASSERT_COLUMN_MARKED_FOR_READ;
DBUG_ASSERT(ltime);
@@ -2201,7 +2201,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 &
@@ -2253,12 +2253,13 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
}
-bool Field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
+ str_to_datetime_with_warn(get_thd(),
+ res->charset(), res->ptr(), res->length(),
ltime, fuzzydate))
return 1;
return 0;
@@ -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;
@@ -3136,7 +3167,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
@@ -3147,7 +3178,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
@@ -3174,8 +3205,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))
{
@@ -3183,7 +3214,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,
@@ -3205,7 +3236,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*)");
@@ -3289,7 +3320,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();
@@ -3314,7 +3345,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;
@@ -3336,7 +3367,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);
}
@@ -3348,37 +3379,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;
@@ -3391,27 +3391,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);
@@ -3566,8 +3545,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;
@@ -3577,9 +3556,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;
@@ -3605,7 +3584,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;
@@ -3617,7 +3596,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)
@@ -3660,7 +3639,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)
@@ -3765,7 +3744,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;
@@ -3779,7 +3758,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);
@@ -3824,7 +3803,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;
@@ -3939,7 +3918,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;
@@ -3953,7 +3932,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)
@@ -3999,7 +3978,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)
@@ -4137,7 +4116,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;
@@ -4151,7 +4130,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);
@@ -4196,7 +4175,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;
@@ -4310,7 +4289,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;
@@ -4333,7 +4312,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()))
@@ -4346,7 +4325,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
@@ -4457,7 +4436,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);
}
@@ -4494,7 +4473,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);
@@ -4673,7 +4652,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);
@@ -4819,13 +4798,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));
@@ -4858,11 +4830,12 @@ my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
}
-bool Field_real::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_real::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double nr= val_real();
- return double_to_datetime_with_warn(nr, ltime, fuzzydate, field_name.str);
+ return double_to_datetime_with_warn(get_thd(), nr, ltime, fuzzydate,
+ field_name.str);
}
@@ -5053,119 +5026,103 @@ 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)
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
{
- error= 1;
- set_datetime_warning(WARN_DATA_TRUNCATED,
- str, MYSQL_TIMESTAMP_DATETIME, 1);
- }
- else if (MYSQL_TIME_WARN_HAVE_NOTES(was_cut))
- {
- 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;
-}
+ // Store the value
+ DBUG_ASSERT(!dt->fraction_remainder(decimals()));
+ store_TIMEVAL(Timeval(timestamp, l_time->second_part));
-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);
}
-sql_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
+date_mode_t Field_timestamp::sql_mode_for_timestamp(THD *thd) const
{
// We don't want to store invalid or fuzzy datetime values in TIMESTAMP
- return (thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE;
+ return date_mode_t((thd->variables.sql_mode & MODE_NO_ZERO_DATE) | MODE_NO_ZERO_IN_DATE);
}
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), decimals());
+ 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);
+ MYSQL_TIME_STATUS st;
+ Datetime dt(&st, from, len, cs, sql_mode_for_timestamp(thd), decimals());
+ return store_TIME_with_warning(thd, &dt, &str, st.warnings);
}
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, Sec6(nr), sql_mode_for_timestamp(thd), decimals());
+ 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);
+ ErrConvInteger str(Longlong_hybrid(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, Sec6(nr, unsigned_val), sql_mode_for_timestamp(thd));
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
@@ -5173,7 +5130,7 @@ int Field_timestamp::store_timestamp(my_time_t ts, ulong sec_part)
{
store_TIME(ts, sec_part);
if (ts == 0 && sec_part == 0 &&
- get_thd()->variables.sql_mode & TIME_NO_ZERO_DATE)
+ get_thd()->variables.sql_mode & (ulonglong) TIME_NO_ZERO_DATE)
{
ErrConvString s(
STRING_WITH_LEN("0000-00-00 00:00:00.000000") - (decimals() ? 6 - decimals() : 7),
@@ -5282,11 +5239,11 @@ Field_timestamp::validate_value_in_record(THD *thd, const uchar *record) const
DBUG_ASSERT(!is_null_in_record(record));
ulong sec_part;
return !get_timestamp(ptr_in_record(record), &sec_part) && !sec_part &&
- (sql_mode_for_dates(thd) & TIME_NO_ZERO_DATE) != 0;
+ bool(sql_mode_for_dates(thd) & TIME_NO_ZERO_DATE) != false;
}
-bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
ulong sec_part;
my_time_t ts= get_timestamp(&sec_part);
@@ -5297,7 +5254,7 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
bool Field_timestamp::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_timestamp::get_date(&ltime, 0);
+ Field_timestamp::get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, 0);
}
@@ -5427,10 +5384,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,
@@ -5455,29 +5412,17 @@ double Field_timestamp_with_dec::val_real(void)
my_decimal *Field_timestamp_with_dec::val_decimal(my_decimal *d)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_my_decimal(&ltime, 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, Sec6(d), sql_mode_for_timestamp(thd), decimals());
+ return store_TIME_with_warning(thd, &dt, &str, error);
}
int Field_timestamp_with_dec::set_time()
@@ -5492,7 +5437,7 @@ int Field_timestamp_with_dec::set_time()
bool Field_timestamp_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- Field_timestamp::get_date(&ltime, 0);
+ Field_timestamp::get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, dec);
}
@@ -5521,19 +5466,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();
@@ -5601,110 +5542,66 @@ 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,
- const ErrConv *str,
- int was_cut,
- int have_smth_to_conv)
+int Field_datetime::store_TIME_with_warning(const Datetime *dt,
+ const ErrConv *str,
+ int was_cut)
{
- Sql_condition::enum_warning_level trunc_level= Sql_condition::WARN_LEVEL_WARN;
- int ret= 2;
-
- ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
-
- if (was_cut == 0 && have_smth_to_conv == 0) // special case: zero date
- {
- was_cut= MYSQL_TIME_WARN_OUT_OF_RANGE;
- }
- else if (!have_smth_to_conv)
- {
- bzero(ltime, sizeof(*ltime));
- was_cut= MYSQL_TIME_WARN_TRUNCATED;
- ret= 1;
- }
- 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))))
- {
- trunc_level= Sql_condition::WARN_LEVEL_NOTE;
- was_cut|= MYSQL_TIME_WARN_TRUNCATED;
- ret= 3;
- }
- set_warnings(trunc_level, str, was_cut,
- type_handler()->mysql_timestamp_type());
- store_TIME(ltime);
- return was_cut ? ret : 0;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
+ return store_invalid_with_warning(str, was_cut, MYSQL_TIMESTAMP_DATETIME);
+ // Store the value
+ DBUG_ASSERT(!dt->fraction_remainder(decimals()));
+ store_TIME(dt->get_mysql_time());
+ // Caclulate return value and send warnings if needed
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATETIME);
}
-int Field_temporal_with_date::store(const char *from, size_t len, CHARSET_INFO *cs)
+int Field_datetime::store(const char *from, size_t len, CHARSET_INFO *cs)
{
- MYSQL_TIME ltime;
- MYSQL_TIME_STATUS status;
- THD *thd= get_thd();
+ MYSQL_TIME_STATUS st;
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(&st, from, len, cs, sql_mode_for_dates(get_thd()), decimals());
+ return store_TIME_with_warning(&dt, &str, st.warnings);
}
-
-int Field_temporal_with_date::store(double nr)
+int Field_datetime::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, Sec6(nr), sql_mode_for_dates(get_thd()), decimals());
+ return store_TIME_with_warning(&dt, &str, error);
}
-int Field_temporal_with_date::store(longlong nr, bool unsigned_val)
+int Field_datetime::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);
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
+ Datetime dt(&error, Sec6(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 Field_datetime::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), decimals());
+ return store_TIME_with_warning(&dt, &str, error);
}
+int Field_datetime::store_decimal(const my_decimal *d)
+{
+ int error;
+ ErrConvDecimal str(d);
+ Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd()), decimals());
+ return store_TIME_with_warning(&tm, &str, error);
+}
+
bool
Field_temporal_with_date::validate_value_in_record(THD *thd,
const uchar *record) const
@@ -5718,7 +5615,7 @@ Field_temporal_with_date::validate_value_in_record(THD *thd,
my_decimal *Field_temporal::val_decimal(my_decimal *d)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(&ltime, date_mode_t(0)))
{
bzero(&ltime, sizeof(ltime));
ltime.time_type= type_handler()->mysql_timestamp_type();
@@ -5751,7 +5648,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd,
const_item->field_type() != MYSQL_TYPE_TIMESTAMP) ||
const_item->decimals != decimals())
{
- Datetime dt(thd, const_item, 0);
+ Datetime dt(thd, const_item, date_mode_t(0));
if (!dt.is_valid_datetime())
return NULL;
/*
@@ -5766,7 +5663,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)
@@ -5787,36 +5684,18 @@ 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)
- {
- bzero(ltime, sizeof(*ltime));
- store_TIME(ltime);
- 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))
- {
- set_warnings(Sql_condition::WARN_LEVEL_NOTE, str,
- was_cut | MYSQL_TIME_WARN_TRUNCATED);
- return 3;
- }
- set_warnings(Sql_condition::WARN_LEVEL_WARN, str, was_cut);
- return was_cut ? 2 : 0;
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!t->is_valid_time())
+ return store_invalid_with_warning(str, warn, MYSQL_TIMESTAMP_TIME);
+ // Store the value
+ DBUG_ASSERT(!t->fraction_remainder(decimals()));
+ 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);
}
@@ -5833,88 +5712,39 @@ 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);
- }
+ MYSQL_TIME_STATUS st;
+ THD *thd= get_thd();
+ Time tm(thd, &st, from, len, cs, sql_mode_for_dates(thd), decimals());
+ return store_TIME_with_warning(&tm, &str, st.warnings);
}
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, decimals());
+ 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(get_thd(), &was_cut, Sec6(nr), decimals());
+ 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);
+ ErrConvInteger str(Longlong_hybrid(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);
+ // Need fractional digit truncation if nr overflows to '838:59:59.999999'
+ Time tm(get_thd(), &was_cut, Sec6(nr, unsigned_val), decimals());
+ return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -5973,7 +5803,7 @@ String *Field_time::val_str(String *str,
}
-bool Field_time::check_zero_in_date_with_warn(ulonglong fuzzydate)
+bool Field_time::check_zero_in_date_with_warn(date_mode_t fuzzydate)
{
if (!(fuzzydate & TIME_TIME_ONLY) && (fuzzydate & TIME_NO_ZERO_IN_DATE))
{
@@ -5995,7 +5825,7 @@ bool Field_time::check_zero_in_date_with_warn(ulonglong fuzzydate)
DATE_FORMAT(time, "%l.%i %p")
*/
-bool Field_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_time::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6069,16 +5899,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(get_thd(), &was_cut, Sec6(d), decimals());
+ return store_TIME_with_warning(&tm, &str, was_cut);
}
@@ -6118,14 +5942,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(get_thd(), 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:
@@ -6137,8 +5975,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);
}
@@ -6147,8 +5986,9 @@ 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(get_thd(), 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
@@ -6164,7 +6004,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;
}
@@ -6189,7 +6030,7 @@ double Field_time_with_dec::val_real(void)
return TIME_to_double(&ltime);
}
-bool Field_time_hires::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_time_hires::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6241,7 +6082,7 @@ void Field_timef::store_TIME(const MYSQL_TIME *ltime)
my_time_packed_to_binary(tmp, ptr, dec);
}
-bool Field_timef::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_zero_in_date_with_warn(fuzzydate))
return true;
@@ -6258,7 +6099,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);
@@ -6306,7 +6147,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;
@@ -6375,12 +6216,13 @@ String *Field_year::val_str(String *val_buffer,
}
-bool Field_year::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Field_year::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
int tmp= (int) ptr[0];
if (tmp || field_length != 4)
tmp+= 1900;
- return int_to_datetime_with_warn(false, tmp * 10000,
+ return int_to_datetime_with_warn(get_thd(),
+ Longlong_hybrid(tmp * 10000, true),
ltime, fuzzydate, field_name.str);
}
@@ -6393,6 +6235,67 @@ void Field_year::sql_type(String &res) const
}
+/*****************************************************************************/
+
+int Field_date_common::store_TIME_with_warning(const Datetime *dt,
+ const ErrConv *str,
+ int was_cut)
+{
+ ASSERT_COLUMN_MARKED_FOR_WRITE;
+ // Handle totally bad values
+ if (!dt->is_valid_datetime())
+ return store_invalid_with_warning(str, was_cut, MYSQL_TIMESTAMP_DATE);
+ // Store the value
+ if (!dt->hhmmssff_is_zero())
+ was_cut|= MYSQL_TIME_NOTE_TRUNCATED;
+ store_TIME(dt->get_mysql_time());
+ // Caclulate return value and send warnings if needed
+ return store_TIME_return_code_with_warnings(was_cut, str,
+ MYSQL_TIMESTAMP_DATE);
+}
+
+int Field_date_common::store(const char *from, size_t len, CHARSET_INFO *cs)
+{
+ MYSQL_TIME_STATUS st;
+ ErrConvString str(from, len, cs);
+ Datetime dt(&st, from, len, cs, sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, st.warnings);
+}
+
+int Field_date_common::store(double nr)
+{
+ int error;
+ ErrConvDouble str(nr);
+ Datetime dt(&error, Sec6(nr), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store(longlong nr, bool unsigned_val)
+{
+ int error;
+ ErrConvInteger str(Longlong_hybrid(nr, unsigned_val));
+ Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store_time_dec(const MYSQL_TIME *ltime, uint dec)
+{
+ int error;
+ ErrConvTime str(ltime);
+ THD *thd= get_thd();
+ Datetime dt(thd, &error, ltime, sql_mode_for_dates(thd));
+ return store_TIME_with_warning(&dt, &str, error);
+}
+
+int Field_date_common::store_decimal(const my_decimal *d)
+{
+ int error;
+ ErrConvDecimal str(d);
+ Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd()));
+ return store_TIME_with_warning(&tm, &str, error);
+}
+
+
/****************************************************************************
** date type
** In string context: YYYY-MM-DD
@@ -6400,7 +6303,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);
@@ -6436,7 +6339,7 @@ longlong Field_date::val_int(void)
bool Field_date::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
int32 tmp= sint4korr(pos);
@@ -6453,7 +6356,7 @@ String *Field_date::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
MYSQL_TIME ltime;
- get_TIME(&ltime, ptr, 0);
+ get_TIME(&ltime, ptr, date_mode_t(0));
val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
uint length= (uint) my_date_to_str(&ltime,
const_cast<char*>(val_buffer->ptr()));
@@ -6493,7 +6396,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);
@@ -6503,7 +6406,7 @@ void Field_newdate::store_TIME(MYSQL_TIME *ltime)
bool Field_newdate::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
- Field_newdate::get_date(&tm,0);
+ Field_newdate::get_date(&tm, date_mode_t(0));
return protocol->store_date(&tm);
}
@@ -6555,7 +6458,7 @@ String *Field_newdate::val_str(String *val_buffer,
bool Field_newdate::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
uint32 tmp=(uint32) uint3korr(pos);
@@ -6599,7 +6502,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;
/*
@@ -6626,7 +6529,7 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx,
case IDENTITY_SUBST:
if (const_item->field_type() != MYSQL_TYPE_DATE)
{
- Date d(thd, const_item, 0);
+ Date d(thd, const_item, date_mode_t(0));
if (!d.is_valid_date())
return NULL;
return new (thd->mem_root) Item_date_literal(thd, d.get_mysql_time());
@@ -6644,7 +6547,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);
@@ -6653,7 +6556,7 @@ void Field_datetime::store_TIME(MYSQL_TIME *ltime)
bool Field_datetime::send_binary(Protocol *protocol)
{
MYSQL_TIME tm;
- Field_datetime::get_date(&tm, 0);
+ Field_datetime::get_date(&tm, date_mode_t(0));
return protocol->store(&tm, 0);
}
@@ -6719,7 +6622,7 @@ String *Field_datetime::val_str(String *val_buffer,
}
bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong tmp= sint8korr(pos);
@@ -6782,44 +6685,23 @@ 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());
}
-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);
-}
-
bool Field_datetime_with_dec::send_binary(Protocol *protocol)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return protocol->store(&ltime, dec);
}
@@ -6827,14 +6709,14 @@ bool Field_datetime_with_dec::send_binary(Protocol *protocol)
double Field_datetime_with_dec::val_real(void)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_double(&ltime);
}
longlong Field_datetime_with_dec::val_int(void)
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
return TIME_to_ulonglong_datetime(&ltime);
}
@@ -6843,7 +6725,7 @@ String *Field_datetime_with_dec::val_str(String *str,
String *unused __attribute__((unused)))
{
MYSQL_TIME ltime;
- get_date(&ltime, 0);
+ get_date(&ltime, date_mode_t(0));
str->alloc(field_length+1);
str->length(field_length);
my_datetime_to_str(&ltime, (char*) str->ptr(), dec);
@@ -6853,7 +6735,7 @@ String *Field_datetime_with_dec::val_str(String *str,
bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
ulonglong packed= read_bigendian(pos, Field_datetime_hires::pack_length());
@@ -6886,15 +6768,14 @@ 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);
}
bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
longlong tmp= my_datetime_packed_from_binary(pos, dec);
@@ -6998,7 +6879,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;
@@ -7044,7 +6925,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);
@@ -7081,9 +6962,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());
}
@@ -7300,11 +7180,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))
@@ -7541,7 +7422,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;
@@ -8078,7 +7959,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(),
@@ -8210,7 +8091,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;
@@ -8698,7 +8579,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,
@@ -9041,7 +8922,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);
@@ -9093,7 +8974,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)
{
@@ -9224,7 +9105,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;
@@ -9264,7 +9145,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;
@@ -9643,7 +9524,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
@@ -10079,7 +9960,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);
@@ -10570,322 +10451,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)
{
@@ -10903,66 +10552,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;
-
- interval_list.empty(); // prepare_interval_field() needs this
+ type_handler()->Column_definition_reuse_fix_attributes(thd, this, old_field);
- char_length= (uint)length;
+ type_handler()->Column_definition_implicit_upgrade(this);
/*
Copy the default (constant/function) from the column object orig_field, if
@@ -11044,11 +10636,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..d5b2a621d48 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);
@@ -1355,7 +1342,7 @@ public:
}
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
- virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); }
virtual TYPELIB *get_typelib() const { return NULL; }
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
@@ -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,9 +1956,9 @@ 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);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
my_decimal *val_decimal(my_decimal *);
bool val_bool() { return val_real() != 0e0; }
uint32 max_display_length() const { return field_length; }
@@ -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, date_mode_t fuzzydate)
+ {
+ return my_decimal(ptr, precision, dec).
+ to_datetime_with_warn(get_thd(), 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);
@@ -2038,7 +2127,7 @@ public:
return nr < 0 && !unsigned_flag ? 0 : (ulonglong) nr;
}
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual const Type_limits_int *type_limits_int() const= 0;
uint32 max_display_length() const
{
@@ -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);
+ }
};
@@ -2315,8 +2410,8 @@ public:
{}
const Type_handler *type_handler() const { return &type_handler_vers_trx_id; }
uint size_of() const { return sizeof(*this); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate, ulonglong trx_id);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate, ulonglong trx_id);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return get_date(ltime, fuzzydate, (ulonglong) val_int());
}
@@ -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,35 @@ class Field_temporal: public Field {
protected:
Item *get_equal_const_item_datetime(THD *thd, const Context &ctx,
Item *const_item);
+ void set_warnings(Sql_condition::enum_warning_level trunc_level,
+ const ErrConv *str, int was_cut, timestamp_type ts_type);
+ 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;
+ }
+ int store_invalid_with_warning(const ErrConv *str, int was_cut,
+ timestamp_type ts_type)
+ {
+ reset();
+ Sql_condition::enum_warning_level level= Sql_condition::WARN_LEVEL_WARN;
+ if (was_cut == 0) // special case: zero date
+ {
+ DBUG_ASSERT(ts_type != MYSQL_TIMESTAMP_TIME);
+ set_warnings(level, str, MYSQL_TIME_WARN_OUT_OF_RANGE, ts_type);
+ return 2;
+ }
+ set_warnings(level, str, MYSQL_TIME_WARN_TRUNCATED, ts_type);
+ return 1;
+ }
public:
Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -2509,7 +2638,7 @@ public:
int save_in_field(Field *to)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(&ltime, date_mode_t(0)))
return to->reset();
return to->store_time_dec(&ltime, decimals());
}
@@ -2528,8 +2657,6 @@ public:
return (Field::eq_def(field) && decimals() == field->decimals());
}
my_decimal *val_decimal(my_decimal*);
- void set_warnings(Sql_condition::enum_warning_level trunc_level,
- const ErrConv *str, int was_cut, timestamp_type ts_type);
double pos_in_interval(Field *min, Field *max)
{
return pos_in_interval_val_real(min, max);
@@ -2544,6 +2671,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,18 +2686,16 @@ 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;
+ virtual void store_TIME(const MYSQL_TIME *ltime) = 0;
virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos,
- ulonglong fuzzydate) const = 0;
+ date_mode_t fuzzydate) const = 0;
bool validate_MMDD(bool not_zero_date, uint month, uint day,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
if (!not_zero_date)
- return fuzzydate & TIME_NO_ZERO_DATE;
+ return bool(fuzzydate & TIME_NO_ZERO_DATE);
if (!month || !day)
- return fuzzydate & TIME_NO_ZERO_IN_DATE;
+ return bool(fuzzydate & TIME_NO_ZERO_IN_DATE);
return false;
}
public:
@@ -2578,20 +2706,19 @@ public:
:Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{}
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_time_dec(const MYSQL_TIME *ltime, uint dec);
- int store_decimal(const my_decimal *);
bool validate_value_in_record(THD *thd, const uchar *record) const;
};
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);
+ date_mode_t sql_mode_for_timestamp(THD *thd) const;
+ 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,11 +2758,11 @@ 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);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
uchar *pack(uchar *to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -2703,6 +2830,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 +2843,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 +2858,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 +2887,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 +2904,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))
@@ -2812,7 +2942,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send_binary(Protocol *protocol);
Information_schema_numeric_attributes
information_schema_numeric_attributes() const
@@ -2824,18 +2954,43 @@ public:
};
-class Field_date :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+class Field_date_common: public Field_temporal_with_date
+{
+protected:
+ int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
+ int was_cut);
+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);
+ int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr, bool unsigned_val);
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec);
+ int store_decimal(const my_decimal *);
+};
+
+
+class Field_date :public Field_date_common
+{
+ void store_TIME(const MYSQL_TIME *ltime);
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t 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; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_date::get_TIME(ltime, ptr, fuzzydate); }
double val_real(void);
longlong val_int(void);
@@ -2859,14 +3014,15 @@ public:
};
-class Field_newdate :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+class Field_newdate :public Field_date_common
+{
+ void store_TIME(const MYSQL_TIME *ltime);
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t 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; }
@@ -2879,7 +3035,7 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_newdate::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
@@ -2895,14 +3051,8 @@ 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);
- void set_warnings(Sql_condition::enum_warning_level level,
- const ErrConv *str, int was_cut)
- {
- Field_temporal::set_warnings(level, str, was_cut, MYSQL_TIMESTAMP_TIME);
- }
- bool check_zero_in_date_with_warn(ulonglong fuzzydate);
+ int store_TIME_with_warning(const Time *ltime, const ErrConv *str, int warn);
+ bool check_zero_in_date_with_warn(date_mode_t fuzzydate);
static void do_field_time(Copy_field *copy);
public:
Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
@@ -2936,7 +3086,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send_binary(Protocol *protocol);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
@@ -2997,7 +3147,7 @@ public:
((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec);
}
int reset(void);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
int cmp(const uchar *,const uchar *);
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return Type_handler_time::hires_bytes(dec); }
@@ -3048,14 +3198,17 @@ public:
return memcmp(a_ptr, b_ptr, pack_length());
}
int reset();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
uint size_of() const { return sizeof(*this); }
};
class Field_datetime :public Field_temporal_with_date {
- void store_TIME(MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime);
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
+protected:
+ int store_TIME_with_warning(const Datetime *ltime, const ErrConv *str,
+ int was_cut);
public:
Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3069,6 +3222,11 @@ public:
}
const Type_handler *type_handler() const { return &type_handler_datetime; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
+ int store(const char *to, size_t length, CHARSET_INFO *charset);
+ int store(double nr);
+ 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);
String *val_str(String*,String *);
@@ -3077,7 +3235,7 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetime::get_TIME(ltime, ptr, fuzzydate); }
int set_time();
int evaluate_update_default_function()
@@ -3147,8 +3305,8 @@ public:
DATETIME(1..6)
*/
class Field_datetime_hires :public Field_datetime_with_dec {
- void store_TIME(MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime);
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
public:
Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -3160,7 +3318,7 @@ public:
}
int cmp(const uchar *,const uchar *);
uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
};
@@ -3170,8 +3328,8 @@ public:
DATETIME(0..6) - MySQL56 version
*/
class Field_datetimef :public Field_datetime_with_dec {
- void store_TIME(MYSQL_TIME *ltime);
- bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const;
+ void store_TIME(const MYSQL_TIME *ltime);
+ bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
int save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= (uchar) decimals();
@@ -3202,7 +3360,7 @@ public:
return memcmp(a_ptr, b_ptr, pack_length());
}
int reset();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); }
uint size_of() const { return sizeof(*this); }
};
@@ -3475,6 +3633,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 +3766,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 +3932,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 +4340,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 +4390,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 +4491,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 +4498,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 +4518,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 +4650,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 +4983,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 dddb2182051..8b3d9c04656 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);
}
@@ -429,7 +429,7 @@ void Field::do_field_temporal(Copy_field *copy)
{
MYSQL_TIME ltime;
// TODO: we now need to check result
- if (copy->from_field->get_date(&ltime, 0))
+ if (copy->from_field->get_date(&ltime, date_mode_t(0)))
copy->to_field->reset();
else
copy->to_field->store_time_dec(&ltime, copy->from_field->decimals());
diff --git a/sql/filesort.cc b/sql/filesort.cc
index a4be9e4acfa..6f2a6096aa2 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 */
@@ -1063,7 +1057,7 @@ Type_handler_temporal_result::make_sort_key(uchar *to, Item *item,
Sort_param *param) const
{
MYSQL_TIME buf;
- if (item->get_date_result(&buf, TIME_INVALID_DATES))
+ if (item->get_date_result(current_thd, &buf, TIME_INVALID_DATES))
{
DBUG_ASSERT(item->maybe_null);
DBUG_ASSERT(item->null_value);
@@ -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 c985ada64e6..37a3decdbca 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -6814,7 +6814,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;
@@ -10688,8 +10688,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/handle_connections_win.cc b/sql/handle_connections_win.cc
new file mode 100644
index 00000000000..b37b4dedad1
--- /dev/null
+++ b/sql/handle_connections_win.cc
@@ -0,0 +1,555 @@
+/* Copyright (c) 2018 MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/* Accepting connections on Windows */
+
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_connect.h>
+#include <mysqld.h>
+#include <mswsock.h>
+#include <mysql/psi/mysql_socket.h>
+#include <sddl.h>
+
+#include <handle_connections_win.h>
+
+/* From mysqld.cc */
+extern HANDLE hEventShutdown;
+extern MYSQL_SOCKET base_ip_sock, extra_ip_sock;
+extern PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ();
+extern void tp_win_callback_prolog();
+static SECURITY_ATTRIBUTES pipe_security;
+
+/**
+ Abstract base class for accepting new connection,
+ asynchronously (i.e the accept() operation can be posted,
+ and result is retrieved later) , and creating a new connection.
+*/
+
+struct Listener
+{
+ /** Windows handle of the Listener.
+ Subclasses would use SOCKET or named pipe handle
+ */
+ HANDLE m_handle;
+ /** Required for all async IO*/
+ OVERLAPPED m_overlapped;
+
+ /** Create new listener
+ @param handle - @see m_handle
+ @param wait_handle - usually, event handle or INVALID_HANDLE_VALUE
+ @see wait_handle
+ */
+ Listener(HANDLE handle, HANDLE wait_handle):
+ m_handle(handle), m_overlapped()
+ {
+ m_overlapped.hEvent= wait_handle;
+ }
+
+ /**
+ if not NULL, this handle can be be used in WaitForSingle/MultipleObject(s).
+ This handle will be closed when object is destroyed.
+
+ If NULL, the completion notification happens in threadpool.
+ */
+ HANDLE wait_handle()
+ {
+ return m_overlapped.hEvent;
+ }
+
+ /* Start waiting for new client connection. */
+ virtual void begin_accept()= 0;
+
+ /**
+ Completion callback,called whenever IO posted by begin_accept is finisjed
+ Listener needs to create a new THD then (or, call scheduler so it creates one)
+
+ @param success - whether IO completed successfull
+ */
+ virtual void completion_callback(bool success)= 0;
+
+ /**
+ Completion callback for Listener, that uses events for waiting
+ to IO. Not suitable for threadpool etc. Retrieves the status of
+ completed IO from the OVERLAPPED structure
+ */
+ void completion_callback()
+ {
+ DBUG_ASSERT(wait_handle() && (wait_handle() != INVALID_HANDLE_VALUE));
+ DWORD bytes;
+ return completion_callback(
+ GetOverlappedResult(wait_handle(), &m_overlapped, &bytes, FALSE));
+ }
+
+ /** Cancel an in-progress IO. Useful for threadpool-bound IO */
+ void cancel()
+ {
+ CancelIoEx(m_handle, &m_overlapped);
+ }
+
+ /* Destructor. Closes wait handle, if it was passed in constructor */
+ virtual ~Listener()
+ {
+ if (m_overlapped.hEvent)
+ CloseHandle(m_overlapped.hEvent);
+ };
+};
+
+/* Winsock extension finctions. */
+static LPFN_ACCEPTEX my_AcceptEx;
+static LPFN_GETACCEPTEXSOCKADDRS my_GetAcceptExSockaddrs;
+
+/**
+ Listener that handles socket connections.
+ Can be threadpool-bound (i.e the completion is executed in threadpool thread),
+ or use events for waits.
+
+ Threadpool-bound listener should be used with theradpool scheduler, for better
+ performance.
+*/
+struct Socket_Listener: public Listener
+{
+ /** Client socket passed to AcceptEx() call.*/
+ SOCKET m_client_socket;
+
+ /** Buffer for sockaddrs passed to AcceptEx()/GetAcceptExSockaddrs() */
+ char m_buffer[2 * sizeof(sockaddr_storage) + 32];
+
+ /* Threadpool IO struct.*/
+ PTP_IO m_tp_io;
+
+ /**
+ Callback for Windows threadpool's StartThreadpoolIo() function.
+ */
+ static void CALLBACK tp_accept_completion_callback(
+ PTP_CALLBACK_INSTANCE, PVOID context, PVOID , ULONG io_result,
+ ULONG_PTR, PTP_IO io)
+ {
+ tp_win_callback_prolog();
+ Listener *listener= (Listener *)context;
+
+ if (io_result == ERROR_OPERATION_ABORTED)
+ {
+ /* ERROR_OPERATION_ABORTED caused by CancelIoEx()*/
+ CloseThreadpoolIo(io);
+ delete listener;
+ return;
+ }
+ listener->completion_callback(io_result == 0);
+ }
+
+ /**
+ Constructor
+ @param listen_socket - listening socket
+ @PTP_CALLBACK_ENVIRON callback_environ - threadpool environment, or NULL
+ if threadpool is not used for completion callbacks.
+ */
+ Socket_Listener(MYSQL_SOCKET listen_socket, PTP_CALLBACK_ENVIRON callback_environ) :
+ Listener((HANDLE)listen_socket.fd,0),
+ m_client_socket(INVALID_SOCKET)
+ {
+ if (callback_environ)
+ {
+ /* Accept executed in threadpool. */
+ m_tp_io= CreateThreadpoolIo(m_handle,
+ tp_accept_completion_callback, this, callback_environ);
+ }
+ else
+ {
+ /* Completion signaled via event. */
+ m_tp_io= 0;
+ m_overlapped.hEvent= CreateEvent(0, FALSE , FALSE, 0);
+ }
+ }
+
+ /*
+ Use AcceptEx to asynchronously wait for new connection;
+ */
+ void begin_accept()
+ {
+retry :
+ m_client_socket= socket(server_socket_ai_family, SOCK_STREAM, IPPROTO_TCP);
+ if (m_client_socket == INVALID_SOCKET)
+ {
+ sql_perror("socket() call failed.");
+ unireg_abort(1);
+ }
+
+ DWORD bytes_received;
+ if (m_tp_io)
+ StartThreadpoolIo(m_tp_io);
+
+ BOOL ret= my_AcceptEx(
+ (SOCKET)m_handle,
+ m_client_socket,
+ m_buffer,
+ 0,
+ sizeof(sockaddr_storage) + 16,
+ sizeof(sockaddr_storage) + 16,
+ &bytes_received,
+ &m_overlapped);
+
+ DWORD last_error= ret? 0: WSAGetLastError();
+ if (last_error == WSAECONNRESET)
+ {
+ if (m_tp_io)
+ CancelThreadpoolIo(m_tp_io);
+ goto retry;
+ }
+
+ if (ret || last_error == ERROR_IO_PENDING || abort_loop)
+ return;
+
+ sql_print_error("my_AcceptEx failed, last error %u", last_error);
+ abort();
+ }
+
+ /* Create new socket connection.*/
+ void completion_callback(bool success)
+ {
+ if (!success)
+ {
+ /* my_AcceptEx() returned error */
+ closesocket(m_client_socket);
+ begin_accept();
+ return;
+ }
+
+ MYSQL_SOCKET s_client{m_client_socket};
+ MYSQL_SOCKET s_listen{(SOCKET)m_handle};
+
+#ifdef HAVE_PSI_SOCKET_INTERFACE
+ /* Parse socket addresses buffer filled by AcceptEx(),
+ only needed for PSI instrumentation. */
+ sockaddr *local_addr, *remote_addr;
+ int local_addr_len, remote_addr_len;
+
+ my_GetAcceptExSockaddrs(m_buffer,
+ 0, sizeof(sockaddr_storage) + 16, sizeof(sockaddr_storage) + 16,
+ &local_addr, &local_addr_len, &remote_addr, &remote_addr_len);
+
+ s_client.m_psi= PSI_SOCKET_CALL(init_socket)
+ (key_socket_client_connection, (const my_socket*)&s_listen.fd, remote_addr, remote_addr_len);
+#endif
+
+ /* Start accepting new connection. After this point, do not use
+ any member data, they could be used by a different (threadpool) thread. */
+ begin_accept();
+
+ /* Some chores post-AcceptEx() that we need to create a normal socket.*/
+ if (setsockopt(s_client.fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char *)&s_listen.fd, sizeof(s_listen.fd)))
+ {
+ if (!abort_loop)
+ {
+ sql_perror("setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed.");
+ abort();
+ }
+ }
+
+ /* Create a new connection.*/
+ handle_accepted_socket(s_client, s_listen);
+ }
+
+ ~Socket_Listener()
+ {
+ if (m_client_socket != INVALID_SOCKET)
+ closesocket(m_client_socket);
+ }
+
+ /*
+ Retrieve the pointer to the Winsock extension functions
+ AcceptEx and GetAcceptExSockaddrs.
+ */
+ static void init_winsock_extensions()
+ {
+ SOCKET s= mysql_socket_getfd(base_ip_sock);
+ if (s == INVALID_SOCKET)
+ s= mysql_socket_getfd(extra_ip_sock);
+ if (s == INVALID_SOCKET)
+ {
+ /* --skip-networking was used*/
+ return;
+ }
+ GUID guid_AcceptEx= WSAID_ACCEPTEX;
+ GUID guid_GetAcceptExSockaddrs= WSAID_GETACCEPTEXSOCKADDRS;
+
+ GUID *guids[]= { &guid_AcceptEx, &guid_GetAcceptExSockaddrs };
+ void *funcs[]= { &my_AcceptEx, &my_GetAcceptExSockaddrs };
+ DWORD bytes;
+ for (int i= 0; i < array_elements(guids); i++)
+ {
+ if (WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ guids[i], sizeof(GUID),
+ funcs[i], sizeof(void *),
+ &bytes, 0, 0) == -1)
+ {
+ sql_print_error("WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
+ unireg_abort(1);
+ }
+ }
+ }
+};
+
+
+/**
+ Pipe Listener.
+ Only event notification mode is implemented, no threadpool
+*/
+struct Pipe_Listener : public Listener
+{
+ PTP_CALLBACK_ENVIRON m_tp_env;
+ Pipe_Listener():
+ Listener(INVALID_HANDLE_VALUE, CreateEvent(0, FALSE, FALSE, 0)),
+ m_tp_env(get_threadpool_win_callback_environ())
+ {
+ }
+
+ /*
+ Creates local named pipe instance \\.\pipe\$socket for named pipe connection.
+ */
+ static HANDLE create_named_pipe()
+ {
+ static bool first_instance= true;
+ static char pipe_name[512];
+ DWORD open_mode= PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED;
+
+ if (first_instance)
+ {
+ snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\%s", mysqld_unix_port);
+ open_mode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
+ "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)",
+ 1, &pipe_security.lpSecurityDescriptor, NULL))
+ {
+ sql_perror("Can't start server : Initialize security descriptor");
+ unireg_abort(1);
+ }
+ pipe_security.nLength= sizeof(SECURITY_ATTRIBUTES);
+ pipe_security.bInheritHandle= FALSE;
+ }
+ HANDLE pipe_handle= CreateNamedPipe(pipe_name,
+ open_mode,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ (int)global_system_variables.net_buffer_length,
+ (int)global_system_variables.net_buffer_length,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &pipe_security);
+ if (pipe_handle == INVALID_HANDLE_VALUE)
+ {
+ sql_perror("Create named pipe failed");
+ sql_print_error("Aborting\n");
+ exit(1);
+ }
+ first_instance= false;
+ return pipe_handle;
+ }
+
+ static void create_pipe_connection(HANDLE pipe)
+ {
+ CONNECT *connect;
+ if (!(connect= new CONNECT) || !(connect->vio= vio_new_win32pipe(pipe)))
+ {
+ CloseHandle(pipe);
+ delete connect;
+ statistic_increment(aborted_connects, &LOCK_status);
+ statistic_increment(connection_errors_internal, &LOCK_status);
+ return;
+ }
+ connect->host= my_localhost;
+ create_new_thread(connect);
+ }
+
+ /* Threadpool callback.*/
+ static void CALLBACK tp_create_pipe_connection(
+ PTP_CALLBACK_INSTANCE,void *Context)
+ {
+ tp_win_callback_prolog();
+ create_pipe_connection(Context);
+ }
+
+ void begin_accept()
+ {
+ m_handle= create_named_pipe();
+ BOOL connected= ConnectNamedPipe(m_handle, &m_overlapped);
+ if (connected)
+ {
+ /* Overlapped ConnectNamedPipe should return zero. */
+ sql_perror("Overlapped ConnectNamedPipe() already connected.");
+ abort();
+ }
+ DWORD last_error= GetLastError();
+ switch (last_error)
+ {
+ case ERROR_PIPE_CONNECTED:
+ /* Client is already connected, so signal an event.*/
+ {
+ /*
+ Cleanup overlapped (so that subsequent GetOverlappedResult()
+ does not show results of previous IO
+ */
+ HANDLE e= m_overlapped.hEvent;
+ memset(&m_overlapped, 0, sizeof(m_overlapped));
+ m_overlapped.hEvent = e;
+ }
+ if (!SetEvent(m_overlapped.hEvent))
+ {
+ sql_perror("SetEvent() failed for connected pipe.");
+ abort();
+ }
+ break;
+ case ERROR_IO_PENDING:
+ break;
+ default:
+ sql_perror("ConnectNamedPipe() failed.");
+ abort();
+ break;
+ }
+ }
+
+ void completion_callback(bool success)
+ {
+ if (!success)
+ {
+#ifdef DBUG_OFF
+ sql_print_warning("ConnectNamedPipe completed with %u", GetLastError());
+#endif
+ CloseHandle(m_handle);
+ m_handle= INVALID_HANDLE_VALUE;
+ begin_accept();
+ return;
+ }
+ HANDLE pipe= m_handle;
+ begin_accept();
+ // If threadpool is on, create connection in threadpool thread
+ if (!m_tp_env || !TrySubmitThreadpoolCallback(tp_create_pipe_connection, pipe, m_tp_env))
+ create_pipe_connection(pipe);
+ }
+
+ ~Pipe_Listener()
+ {
+ if (m_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(m_handle);
+ }
+ }
+
+ static void cleanup()
+ {
+ LocalFree(pipe_security.lpSecurityDescriptor);
+ }
+};
+
+/**
+ Accept new client connections on Windows.
+
+ Since we deal with pipe and sockets, they cannot be put into a select/loop.
+ But we can use asynchronous IO, and WaitForMultipleObject() loop.
+
+ In addition, for slightly better performance, if we're using threadpool,
+ socket connections are accepted directly in the threadpool.
+
+ The mode of operation is therefore
+
+ 1. There is WaitForMultipleObject() loop that waits for shutdown notification
+ (hEventShutdown),and possibly pipes and sockets(e.g if threadpool is not used)
+ This loop ends when shutdown notification is detected.
+
+ 2. If threadpool is used, new socket connections are accepted there.
+*/
+
+
+#define MAX_WAIT_HANDLES 32
+#define NUM_PIPE_LISTENERS 24
+#define SHUTDOWN_IDX 0
+#define LISTENER_START_IDX 1
+
+void handle_connections_win()
+{
+ Listener* all_listeners[MAX_WAIT_HANDLES]= {};
+ HANDLE wait_events[MAX_WAIT_HANDLES]= {};
+ int n_listeners= 0;
+ int n_waits= 0;
+
+ Socket_Listener::init_winsock_extensions();
+
+ /* Listen for TCP connections on "extra-port" (no threadpool).*/
+ if (extra_ip_sock.fd != INVALID_SOCKET)
+ all_listeners[n_listeners++]= new Socket_Listener(extra_ip_sock, 0);
+
+ /* Listen for named pipe connections */
+ if (mysqld_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe)
+ {
+ /*
+ Use several listeners for pipe, to reduce ERROR_PIPE_BUSY on client side.
+ */
+ for (int i= 0; i < NUM_PIPE_LISTENERS; i++)
+ all_listeners[n_listeners++]= new Pipe_Listener();
+ }
+
+ if (base_ip_sock.fd != INVALID_SOCKET)
+ {
+ /* Wait for TCP connections.*/
+ SetFileCompletionNotificationModes((HANDLE)base_ip_sock.fd, FILE_SKIP_SET_EVENT_ON_HANDLE);
+ all_listeners[n_listeners++]= new Socket_Listener(base_ip_sock, get_threadpool_win_callback_environ());
+ }
+
+ if (!n_listeners && !opt_bootstrap)
+ {
+ sql_print_error("Either TCP connections or named pipe connections must be enabled.");
+ unireg_abort(1);
+ }
+
+ wait_events[SHUTDOWN_IDX]= hEventShutdown;
+ n_waits = 1;
+
+ for (int i= 0; i < n_listeners; i++)
+ {
+ HANDLE wait_handle= all_listeners[i]->wait_handle();
+ if(wait_handle)
+ {
+ DBUG_ASSERT((i == 0) || (all_listeners[i-1]->wait_handle() != 0));
+ wait_events[n_waits++]= wait_handle;
+ }
+ all_listeners[i]->begin_accept();
+ }
+
+ for (;;)
+ {
+ DWORD idx = WaitForMultipleObjects(n_waits ,wait_events, FALSE, INFINITE);
+ DBUG_ASSERT((int)idx >= 0 && (int)idx < n_waits);
+
+ if (idx == SHUTDOWN_IDX)
+ break;
+
+ all_listeners[idx - LISTENER_START_IDX]->completion_callback();
+ }
+
+ /* Cleanup */
+ for (int i= 0; i < n_listeners; i++)
+ {
+ Listener *listener= all_listeners[i];
+ if (listener->wait_handle())
+ delete listener;
+ else
+ // Threadpool-bound listener will be deleted in threadpool
+ // Do not call destructor, because callback maybe running.
+ listener->cancel();
+ }
+ Pipe_Listener::cleanup();
+} \ No newline at end of file
diff --git a/sql/handle_connections_win.h b/sql/handle_connections_win.h
new file mode 100644
index 00000000000..a81f4346fb2
--- /dev/null
+++ b/sql/handle_connections_win.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2018 MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
+
+/**
+ Handles incoming socket and pipe connections, on Windows.
+ Creates new (THD) connections..
+*/
+extern void handle_connections_win();
diff --git a/sql/handler.cc b/sql/handler.cc
index 897d468f2ba..1b847e605ad 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -296,7 +296,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));
@@ -2544,7 +2544,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;
@@ -3601,7 +3601,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
@@ -3736,14 +3736,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:
@@ -3870,14 +3870,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;
}
}
@@ -4049,7 +4049,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;
@@ -4971,7 +4972,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 788ac4dd474..6245bf7970f 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -3253,7 +3253,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/init.h b/sql/init.h
index e8dec0c1e2e..e96bb478cee 100644
--- a/sql/init.h
+++ b/sql/init.h
@@ -17,6 +17,6 @@
#define INIT_INCLUDED
void unireg_init(ulong options);
-ATTRIBUTE_NORETURN void unireg_end(void);
+void unireg_end(void);
#endif /* INIT_INCLUDED */
diff --git a/sql/item.cc b/sql/item.cc
index 4eb47dc01c3..88bb929fc05 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -115,63 +115,20 @@ void Item::push_note_converted_to_positive_complement(THD *thd)
}
-longlong Item::val_datetime_packed_result()
+longlong Item::val_datetime_packed_result(THD *thd)
{
MYSQL_TIME ltime, tmp;
- if (get_date_result(&ltime, TIME_FUZZY_DATES | TIME_INVALID_DATES))
+ if (get_date_result(thd, &ltime, Datetime::comparison_flags_for_get_date()))
return 0;
if (ltime.time_type != MYSQL_TIMESTAMP_TIME)
return pack_time(&ltime);
- if ((null_value= time_to_datetime_with_warn(current_thd, &ltime, &tmp, 0)))
+ if ((null_value= time_to_datetime_with_warn(thd, &ltime,
+ &tmp, date_mode_t(0))))
return 0;
return pack_time(&tmp);
}
-/**
- 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 +210,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 +260,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,93 +291,10 @@ 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;
- if (get_time(&ltime))
+ if (get_time(field->table->in_use, &ltime))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
@@ -475,7 +304,8 @@ int Item::save_time_in_field(Field *field, bool no_conversions)
int Item::save_date_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, sql_mode_for_dates(field->table->in_use)))
+ THD *thd= field->table->in_use;
+ if (get_date(thd, &ltime, sql_mode_for_dates(thd)))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
return field->store_time_dec(&ltime, decimals);
@@ -515,11 +345,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 +393,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 +465,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 +484,7 @@ void Item::cleanup()
bool Item::cleanup_processor(void *arg)
{
- if (fixed)
+ if (is_fixed())
cleanup();
return FALSE;
}
@@ -749,7 +576,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 +771,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 +1007,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 +1156,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 +1206,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;
@@ -1444,11 +1274,10 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
As a extra convenience the time structure is reset on error or NULL values!
*/
-bool Item::get_date_from_int(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item::get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- longlong value= val_int();
- bool neg= !unsigned_flag && value < 0;
- if (null_value || int_to_datetime_with_warn(neg, neg ? -value : value,
+ Longlong_hybrid value(val_int(), unsigned_flag);
+ if (null_value || int_to_datetime_with_warn(thd, value,
ltime, fuzzydate,
field_name_or_null()))
return null_value|= make_zero_date(ltime, fuzzydate);
@@ -1456,60 +1285,29 @@ 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)
+bool Item::get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
double value= val_real();
- if (null_value || double_to_datetime_with_warn(value, ltime, fuzzydate,
+ if (null_value || double_to_datetime_with_warn(thd, value, ltime, fuzzydate,
field_name_or_null()))
return null_value|= make_zero_date(ltime, fuzzydate);
return null_value= false;
}
-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)
+bool Item::get_date_from_string(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
+ str_to_datetime_with_warn(thd, res->charset(), res->ptr(), res->length(),
ltime, fuzzydate))
return null_value|= make_zero_date(ltime, fuzzydate);
return null_value= false;
}
-bool Item::make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item::make_zero_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
/*
if the item was not null and convertion failed, we return a zero date
@@ -1535,21 +1333,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()
{
@@ -1693,7 +1476,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
@@ -1705,7 +1488,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;
@@ -1786,11 +1569,11 @@ my_decimal *Item_sp_variable::val_decimal(my_decimal *decimal_value)
}
-bool Item_sp_variable::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_sp_variable::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
Item *it= this_item();
- bool val= it->get_date(ltime, fuzzydate);
+ bool val= it->get_date(thd, ltime, fuzzydate);
null_value= it->null_value;
return val;
}
@@ -1826,10 +1609,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);
}
@@ -2167,10 +1950,10 @@ my_decimal *Item_name_const::val_decimal(my_decimal *decimal_value)
return val;
}
-bool Item_name_const::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_name_const::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
- bool rc= value_item->get_date(ltime, fuzzydate);
+ bool rc= value_item->get_date(thd, ltime, fuzzydate);
null_value= value_item->null_value;
return rc;
}
@@ -2182,54 +1965,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)
{
@@ -2372,7 +2126,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.
@@ -2380,7 +2134,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 ||
@@ -2755,7 +2509,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".
@@ -2904,7 +2658,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;
@@ -2937,7 +2691,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;
@@ -3116,7 +2870,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;
@@ -3433,7 +3190,7 @@ String *Item_field::str_result(String *str)
return result_field->val_str(str,&str_value);
}
-bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_field::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate))
{
@@ -3443,7 +3200,7 @@ bool Item_field::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
return 0;
}
-bool Item_field::get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_field::get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (result_field->is_null() || result_field->get_date(ltime,fuzzydate))
{
@@ -3652,6 +3409,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.
@@ -3671,7 +3470,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;
}
@@ -3683,8 +3481,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;
}
@@ -3721,8 +3517,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;
}
@@ -3744,7 +3538,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,
@@ -3756,7 +3549,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,
@@ -3769,7 +3561,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,
@@ -3786,16 +3577,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,
@@ -3804,63 +3593,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);
@@ -3882,8 +3623,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;
}
@@ -3891,8 +3630,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);
}
@@ -3953,7 +3690,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);
}
@@ -3964,7 +3700,6 @@ double Item_string::val_real()
*/
longlong Item_string::val_int()
{
- DBUG_ASSERT(fixed == 1);
return longlong_from_string_with_check(&str_value);
}
@@ -3977,23 +3712,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;
}
@@ -4004,10 +3733,8 @@ my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
}
-bool Item_null::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_null::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- // following assert is redundant, because fixed=1 assigned in constructor
- DBUG_ASSERT(fixed == 1);
make_zero_date(ltime, fuzzydate);
return (null_value= true);
}
@@ -4057,8 +3784,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),
@@ -4117,7 +3842,6 @@ void Item_param::sync_clones()
c->Type_geometry_attributes::operator=(*this);
c->state= state;
- c->item_type= item_type;
c->m_empty_string_is_null= m_empty_string_is_null;
c->value.PValue_simple::operator=(value);
@@ -4152,7 +3876,6 @@ void Item_param::set_null()
max_length= 0;
decimals= 0;
state= NULL_VALUE;
- fix_type(Item::NULL_ITEM);
DBUG_VOID_RETURN;
}
@@ -4167,7 +3890,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;
}
@@ -4182,7 +3904,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;
}
@@ -4215,7 +3936,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;
}
@@ -4233,7 +3953,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);
}
@@ -4245,7 +3964,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);
}
@@ -4330,7 +4048,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);
}
@@ -4364,7 +4081,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);
}
@@ -4428,7 +4144,7 @@ bool Item_param::set_from_item(THD *thd, Item *item)
}
}
struct st_value tmp;
- if (!item->save_in_value(&tmp))
+ if (!item->save_in_value(thd, &tmp))
{
const Type_handler *h= item->type_handler();
set_handler(h);
@@ -4466,16 +4182,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;
}
@@ -4541,7 +4247,7 @@ void Item_param::invalid_default_param() const
}
-bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
+bool Item_param::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
/*
LIMIT clause parameter should not call get_date()
@@ -4555,7 +4261,7 @@ bool Item_param::get_date(MYSQL_TIME *res, ulonglong fuzzydate)
*res= value.time;
return 0;
}
- return type_handler()->Item_get_date(this, res, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, res, fuzzydate);
}
@@ -4567,11 +4273,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:
@@ -4596,11 +4298,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:
@@ -4650,7 +4348,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:
@@ -4691,8 +4389,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:
@@ -4797,11 +4494,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;
}
@@ -4862,48 +4568,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)
@@ -4957,12 +4621,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);
}
@@ -4972,7 +4634,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
@@ -4988,7 +4649,6 @@ void Item_param::set_ignore()
{
m_is_settable_routine_parameter= false;
state= IGNORE_VALUE;
- fixed= true;
null_value= true;
}
@@ -5017,7 +4677,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
correctly fetches the value from the client-server protocol,
using set_param_func().
*/
- if (arg->save_in_value(&tmp) ||
+ if (arg->save_in_value(thd, &tmp) ||
set_value(thd, arg, &tmp, arg->type_handler()))
{
set_null();
@@ -5163,17 +4823,6 @@ my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
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);
@@ -5227,9 +4876,9 @@ String* Item_ref_null_helper::val_str(String* s)
}
-bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_ref_null_helper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (owner->was_null|= null_value= (*ref)->get_date_result(ltime, fuzzydate));
+ return (owner->was_null|= null_value= (*ref)->get_date_result(thd, ltime, fuzzydate));
}
@@ -5522,7 +5171,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);
@@ -5564,7 +5213,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)
@@ -5687,7 +5336,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;
@@ -5841,7 +5490,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;
}
@@ -5883,7 +5532,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
@@ -6459,7 +6108,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;
}
@@ -6831,12 +6480,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());
}
@@ -6903,14 +6551,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;
}
@@ -7113,7 +6765,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;
}
@@ -7169,7 +6820,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;
}
@@ -7248,19 +6898,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'");
@@ -7277,12 +6917,11 @@ Item *Item_date_literal::clone_item(THD *thd)
}
-bool Item_date_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_date_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- DBUG_ASSERT(fixed);
- fuzzy_date |= sql_mode_for_dates(current_thd);
+ fuzzydate |= sql_mode_for_dates(thd);
*ltime= cached_time;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7303,12 +6942,11 @@ Item *Item_datetime_literal::clone_item(THD *thd)
}
-bool Item_datetime_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_datetime_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- DBUG_ASSERT(fixed);
- fuzzy_date |= sql_mode_for_dates(current_thd);
+ fuzzydate |= sql_mode_for_dates(thd);
*ltime= cached_time;
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7329,13 +6967,12 @@ Item *Item_time_literal::clone_item(THD *thd)
}
-bool Item_time_literal::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_time_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- DBUG_ASSERT(fixed);
*ltime= cached_time;
- if (fuzzy_date & TIME_TIME_ONLY)
+ if (fuzzydate & TIME_TIME_ONLY)
return (null_value= false);
- return (null_value= check_date_with_warn(ltime, fuzzy_date,
+ return (null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR));
}
@@ -7451,7 +7088,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;
}
@@ -7502,6 +7139,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)
{
@@ -7621,18 +7483,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();
@@ -7646,7 +7508,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;
}
}
@@ -7655,26 +7517,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)
@@ -7710,7 +7571,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();
}
@@ -7759,7 +7620,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();
}
@@ -7885,7 +7746,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;
}
@@ -8008,7 +7869,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);
/*
@@ -8033,13 +7894,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;
@@ -8065,7 +7926,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;
@@ -8337,9 +8198,9 @@ bool Item_ref::is_null()
}
-bool Item_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
+ return (null_value=(*ref)->get_date_result(thd, ltime, fuzzydate));
}
@@ -8474,9 +8335,9 @@ bool Item_direct_ref::is_null()
}
-bool Item_direct_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_direct_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return (null_value=(*ref)->get_date(ltime,fuzzydate));
+ return (null_value=(*ref)->get_date(thd, ltime, fuzzydate));
}
@@ -8488,10 +8349,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;
@@ -8550,7 +8411,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;
}
@@ -8853,18 +8714,18 @@ bool Item_cache_wrapper::is_null()
Get the date value of the possibly cached item
*/
-bool Item_cache_wrapper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_cache_wrapper::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
Item *cached_value;
DBUG_ENTER("Item_cache_wrapper::get_date");
if (!expr_cache)
- DBUG_RETURN((null_value= orig_item->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= orig_item->get_date(thd, ltime, fuzzydate)));
if ((cached_value= check_cache()))
- DBUG_RETURN((null_value= cached_value->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= cached_value->get_date(thd, ltime, fuzzydate)));
cache();
- DBUG_RETURN((null_value= expr_value->get_date(ltime, fuzzydate)));
+ DBUG_RETURN((null_value= expr_value->get_date(thd, ltime, fuzzydate)));
}
@@ -8880,7 +8741,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);
}
@@ -8910,7 +8771,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)
@@ -9196,7 +9057,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)
{
@@ -9282,10 +9142,10 @@ my_decimal *Item_default_value::val_decimal(my_decimal *decimal_value)
return Item_field::val_decimal(decimal_value);
}
-bool Item_default_value::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_default_value::get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate)
{
calculate();
- return Item_field::get_date(ltime, fuzzydate);
+ return Item_field::get_date(thd, ltime, fuzzydate);
}
bool Item_default_value::send(Protocol *protocol, st_value *buffer)
@@ -9388,7 +9248,7 @@ my_decimal *Item_ignore_value::val_decimal(my_decimal *decimal_value)
return 0;
}
-bool Item_ignore_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_ignore_value::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0); // never should be called
null_value= 1;
@@ -9412,7 +9272,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;
@@ -9624,7 +9484,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();
}
@@ -9683,73 +9543,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)
- {
- 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)
+ Type_handler_hybrid_field_type cmp(field->type_handler_for_comparison());
+ if (cmp.aggregate_for_comparison(item->type_handler_for_comparison()))
{
- 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);
}
@@ -9812,7 +9613,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());
@@ -9822,7 +9622,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);
@@ -9831,7 +9630,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;
@@ -9839,7 +9637,6 @@ double Item_cache_int::val_real()
longlong Item_cache_int::val_int()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return value;
@@ -9879,88 +9676,12 @@ 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)
return false;
value_cached= true;
- value= example->val_datetime_packed_result();
+ value= example->val_datetime_packed_result(current_thd);
null_value= example->null_value;
return true;
}
@@ -9971,16 +9692,14 @@ bool Item_cache_time::cache_value()
if (!example)
return false;
value_cached= true;
- value= example->val_time_packed_result();
+ value= example->val_time_packed_result(current_thd);
null_value= example->null_value;
return true;
}
-bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_cache_temporal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- ErrConvInteger str(value);
-
if (!has_value())
{
bzero((char*) ltime,sizeof(*ltime));
@@ -9995,7 +9714,7 @@ bool Item_cache_temporal::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
int Item_cache_temporal::save_in_field(Field *field, bool no_conversions)
{
MYSQL_TIME ltime;
- if (get_date(&ltime, 0))
+ if (get_date(field->get_thd(), &ltime, date_mode_t(0)))
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
int error= field->store_time_dec(&ltime, decimals);
@@ -10038,21 +9757,21 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd)
Item *Item_cache_datetime::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATETIME);
+ unpack_time(val_datetime_packed(thd), &ltime, MYSQL_TIMESTAMP_DATETIME);
return new (thd->mem_root) Item_datetime_literal(thd, &ltime, decimals);
}
Item *Item_cache_date::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_datetime_packed(), &ltime, MYSQL_TIMESTAMP_DATE);
+ unpack_time(val_datetime_packed(thd), &ltime, MYSQL_TIMESTAMP_DATE);
return new (thd->mem_root) Item_date_literal(thd, &ltime);
}
Item *Item_cache_time::make_literal(THD *thd)
{
MYSQL_TIME ltime;
- unpack_time(val_time_packed(), &ltime, MYSQL_TIMESTAMP_TIME);
+ unpack_time(val_time_packed(thd), &ltime, MYSQL_TIMESTAMP_TIME);
return new (thd->mem_root) Item_time_literal(thd, &ltime, decimals);
}
@@ -10069,7 +9788,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;
@@ -10077,7 +9795,6 @@ double Item_cache_real::val_real()
longlong Item_cache_real::val_int()
{
- DBUG_ASSERT(fixed == 1);
if (!has_value())
return 0;
return Converter_double_to_longlong(value, unsigned_flag).result();
@@ -10086,7 +9803,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());
@@ -10096,7 +9812,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);
@@ -10131,38 +9846,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;
@@ -10179,9 +9878,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;
}
@@ -10214,7 +9912,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;
@@ -10223,7 +9920,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;
@@ -10232,7 +9928,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;
@@ -10241,7 +9936,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;
@@ -10425,7 +10119,7 @@ String *Item_type_holder::val_str(String*)
return 0;
}
-bool Item_type_holder::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_type_holder::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0); // should never be called
return true;
@@ -10434,7 +10128,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 d743cf6c19c..d15dbade60f 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -100,7 +100,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;
@@ -108,6 +111,7 @@ struct KEY_FIELD;
struct SARGABLE_PARAM;
class RANGE_OPT_PARAM;
class SEL_TREE;
+class With_sum_func_cache;
enum precedence {
LOWEST_PRECEDENCE,
@@ -596,6 +600,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;
@@ -628,6 +633,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
{
@@ -652,16 +736,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 };
@@ -703,11 +797,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);
@@ -715,21 +832,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);
@@ -739,31 +856,33 @@ 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;
return value;
}
- bool get_date_from_item(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date_from_item(THD *thd, Item *item,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- bool rc= item->get_date(ltime, fuzzydate);
+ bool rc= item->get_date(thd, ltime, fuzzydate);
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,
otherwise - null.
*/
- bool make_zero_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool make_zero_date(MYSQL_TIME *ltime, date_mode_t 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();
@@ -783,14 +902,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
@@ -820,7 +937,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)
{
@@ -834,7 +951,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.
@@ -854,11 +991,14 @@ 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)
+ bool save_in_value(THD *thd, struct st_value *value)
{
- return type_handler()->Item_save_in_value(this, value);
+ return type_handler()->Item_save_in_value(thd, this, value);
}
/* Function returns 1 on overflow and -1 on fatal errors */
@@ -883,6 +1023,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();
@@ -891,13 +1046,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
@@ -953,6 +1104,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
@@ -1028,6 +1183,16 @@ public:
If value is not null null_value flag will be reset to FALSE.
*/
virtual longlong val_int()=0;
+ Longlong_null to_longlong_null()
+ {
+ longlong nr= val_int();
+ /*
+ C++ does not guarantee the order of parameter evaluation,
+ so to make sure "null_value" is passed to the constructor
+ after the val_int() call, val_int() is caled on a separate line.
+ */
+ return Longlong_null(nr, null_value);
+ }
/**
Get a value for CAST(x AS SIGNED).
Too large positive unsigned integer values are converted
@@ -1049,7 +1214,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();
/*
@@ -1215,7 +1379,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
@@ -1230,28 +1394,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);
@@ -1311,6 +1462,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); }
@@ -1358,14 +1517,14 @@ public:
/**
TIME or DATETIME precision of the item: 0..6
*/
- uint time_precision()
+ uint time_precision(THD *thd)
{
- return const_item() ? type_handler()->Item_time_precision(this) :
+ return const_item() ? type_handler()->Item_time_precision(thd, this) :
MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
}
- uint datetime_precision()
+ uint datetime_precision(THD *thd)
{
- return const_item() ? type_handler()->Item_datetime_precision(this) :
+ return const_item() ? type_handler()->Item_datetime_precision(thd, this) :
MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
}
virtual longlong val_int_min() const
@@ -1463,78 +1622,33 @@ public:
void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
List<Item> &fields,
Item **ref, uint flags);
- virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)= 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);
+ virtual bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)= 0;
+ bool get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_real(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_string(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_time(THD *thd, MYSQL_TIME *ltime)
+ { return get_date(thd, ltime, Time::flags_for_get_date()); }
// Get a DATE or DATETIME value in numeric packed format for comparison
- virtual longlong val_datetime_packed()
+ virtual longlong val_datetime_packed(THD *thd)
{
- 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;
+ date_mode_t 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()
+ virtual longlong val_time_packed(THD *thd)
{
- Time tm(this, Time::comparison_flags_for_get_date());
- return tm.is_valid_time() ? pack_time(tm.get_mysql_time()) : 0;
+ return Time(thd, this, Time::comparison_flags_for_get_date()).to_packed();
}
- longlong val_datetime_packed_result();
- longlong val_time_packed_result()
+ longlong val_datetime_packed_result(THD *thd);
+ longlong val_time_packed_result(THD *thd)
{
MYSQL_TIME ltime;
- ulonglong fuzzydate= Time::comparison_flags_for_get_date();
- return get_date_result(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
+ date_mode_t fuzzydate= Time::comparison_flags_for_get_date();
+ return get_date_result(thd, &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); }
+ virtual bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date(thd, ltime,fuzzydate); }
/*
The method allows to determine nullness of a complex expression
without fully evaluating it, instead of calling val/result*() then
@@ -1549,35 +1663,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);
}
/*
@@ -1595,10 +1681,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) {}
@@ -1709,7 +1794,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; }
@@ -1869,11 +1962,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; }
@@ -1885,8 +1984,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; }
@@ -1940,6 +2043,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; }
@@ -2013,13 +2117,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);
@@ -2083,6 +2190,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);
@@ -2097,6 +2231,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
@@ -2220,6 +2414,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)
@@ -2271,6 +2476,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; }
@@ -2305,27 +2534,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
@@ -2362,66 +2603,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);
- }
- }
};
@@ -2432,7 +2647,7 @@ public:
- CASE expression (Item_case_expr);
*****************************************************************************/
-class Item_sp_variable :public Item
+class Item_sp_variable :public Item_fixed_hybrid
{
protected:
/*
@@ -2464,7 +2679,7 @@ public:
longlong val_int();
String *val_str(String *sp);
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool is_null();
public:
@@ -2472,6 +2687,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)
@@ -2575,6 +2795,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;
+ }
};
@@ -2721,11 +2955,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);
@@ -2736,7 +2969,7 @@ public:
longlong val_int();
String *val_str(String *sp);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool is_null();
virtual void print(String *str, enum_query_type query_type);
@@ -2750,6 +2983,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);
@@ -2767,15 +3011,27 @@ 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)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
};
@@ -2784,24 +3040,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)
{
@@ -2894,11 +3152,17 @@ 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); }
my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return field->get_date(ltime, fuzzydate);
}
@@ -2999,24 +3263,25 @@ 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
{
return MONOTONIC_STRICT_INCREASING;
}
longlong val_int_endpoint(bool left_endp, bool *incl_endp);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool is_null() { return field->is_null(); }
void update_null_value();
void update_table_bitmaps()
@@ -3026,13 +3291,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()
@@ -3109,10 +3368,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)
@@ -3217,22 +3479,21 @@ 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);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
bool send(Protocol *protocol, st_value *buffer);
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)
@@ -3258,6 +3519,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);
@@ -3325,8 +3592,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:
@@ -3349,14 +3616,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
@@ -3455,7 +3714,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;
@@ -3479,9 +3737,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()
{
@@ -3499,7 +3805,7 @@ public:
{
return can_return_value() ? value.val_str(str, this) : NULL;
}
- bool get_date(MYSQL_TIME *tm, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *tm, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void set_default();
@@ -3576,8 +3882,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; }
@@ -3607,12 +3919,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()
@@ -3660,50 +3966,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); }
};
@@ -3719,8 +4019,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.
+ */
+ }
};
@@ -3730,8 +4042,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);
@@ -3752,7 +4063,7 @@ public:
longlong val_int();
double val_real() { return (double)val_int(); }
void set(longlong packed, enum_mysql_timestamp_type ts_type);
- bool get_date(MYSQL_TIME *to, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
{
*to= ltime;
return false;
@@ -3770,24 +4081,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); }
@@ -3807,21 +4120,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;
@@ -3834,12 +4144,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); }
};
@@ -3866,14 +4173,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)
@@ -3884,41 +4189,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 ?
@@ -3927,16 +4232,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));
@@ -3946,26 +4251,23 @@ 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 *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_string(ltime, fuzzydate);
+ return get_date_from_string(thd, ltime, fuzzydate);
}
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)
{
@@ -3977,7 +4279,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
@@ -4006,34 +4307,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);
@@ -4220,38 +4493,30 @@ 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; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ const String *const_ptr_string() const { return &str_value; }
+ String *val_str(String*) { return &str_value; }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
};
@@ -4267,22 +4532,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;
@@ -4292,14 +4553,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); }
@@ -4323,12 +4576,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)
@@ -4354,7 +4605,7 @@ public:
};
-class Item_temporal_literal :public Item_basic_constant
+class Item_temporal_literal :public Item_literal
{
protected:
MYSQL_TIME cached_time;
@@ -4364,37 +4615,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); }
};
@@ -4410,7 +4645,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.
@@ -4423,7 +4657,11 @@ 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);
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ 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(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_date_literal>(thd, this); }
};
@@ -4439,12 +4677,15 @@ 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);
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ 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(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_time_literal>(thd, this); }
};
@@ -4460,14 +4701,23 @@ 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);
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ 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(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_datetime_literal>(thd, this); }
};
@@ -4504,7 +4754,7 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal
public:
Item_date_literal_for_invalid_dates(THD *thd, const MYSQL_TIME *ltime)
:Item_date_literal(thd, ltime) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
*ltime= cached_time;
return (null_value= false);
@@ -4522,7 +4772,7 @@ public:
Item_datetime_literal_for_invalid_dates(THD *thd,
const MYSQL_TIME *ltime, uint dec_arg)
:Item_datetime_literal(thd, ltime, dec_arg) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
*ltime= cached_time;
return (null_value= false);
@@ -4717,8 +4967,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;
@@ -4740,9 +4992,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();
@@ -4778,7 +5036,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; }
@@ -4795,7 +5054,7 @@ public:
bool val_bool();
String *val_str(String* tmp);
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
@@ -4816,6 +5075,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,
@@ -4945,6 +5206,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();
@@ -4961,6 +5224,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; }
};
@@ -5000,7 +5265,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual Ref_Type ref_type() { return DIRECT_REF; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_direct_ref>(thd, this); }
@@ -5048,7 +5313,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 */
@@ -5076,6 +5342,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);
@@ -5093,7 +5361,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool is_null();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
void save_org_in_field(Field *field,
fast_field_copier data __attribute__ ((__unused__)))
@@ -5251,10 +5519,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)
{
@@ -5305,14 +5575,14 @@ public:
else
return Item_direct_ref::is_null();
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (check_null_ref())
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
}
- return Item_direct_ref::get_date(ltime, fuzzydate);
+ return Item_direct_ref::get_date(thd, ltime, fuzzydate);
}
bool send(Protocol *protocol, st_value *buffer);
void save_org_in_field(Field *field,
@@ -5428,7 +5698,7 @@ public:
String* val_str(String* s);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
virtual void print(String *str, enum_query_type query_type);
table_map used_tables() const;
Item *get_copy(THD *thd)
@@ -5520,12 +5790,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:
@@ -5546,6 +5816,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; }
@@ -5587,8 +5863,8 @@ public:
my_decimal *val_decimal(my_decimal *);
double val_real();
longlong val_int();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
void copy();
int save_in_field(Field *field, bool no_conversions);
Item *get_copy(THD *thd)
@@ -5729,7 +6005,7 @@ public:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
int save_in_field(Field *field_arg, bool no_conversions);
bool save_in_param(THD *thd, Item_param *param)
@@ -5781,7 +6057,7 @@ public:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *decimal_value);
- bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate);
bool send(Protocol *protocol, st_value *buffer);
};
@@ -5927,7 +6203,7 @@ public:
for any value.
*/
-class Item_cache: public Item_basic_constant,
+class Item_cache: public Item,
public Type_handler_hybrid_field_type
{
protected:
@@ -5946,25 +6222,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;
}
@@ -5979,10 +6257,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);
@@ -6013,7 +6299,7 @@ public:
void cleanup()
{
clear();
- Item_basic_constant::cleanup();
+ Item::cleanup();
}
/**
Check if saved item has a non-NULL value.
@@ -6065,7 +6351,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); }
};
@@ -6084,8 +6374,8 @@ public:
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
bool cache_value();
int save_in_field(Field *field, bool no_conversions);
Item *convert_to_basic_const_item(THD *thd);
@@ -6097,9 +6387,13 @@ public:
class Item_cache_year: public Item_cache_int
{
public:
- Item_cache_year(THD *thd): Item_cache_int(thd, &type_handler_year) { }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_year(ltime, fuzzydate); }
+ Item_cache_year(THD *thd, const Type_handler *handler)
+ :Item_cache_int(thd, handler) { }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ {
+ return null_value=
+ VYear(this).to_mysql_time_with_warn(thd, ltime, fuzzydate, NULL);
+ }
};
@@ -6108,14 +6402,8 @@ 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);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
int save_in_field(Field *field, bool no_conversions);
void store_packed(longlong val_arg, Item *example);
/*
@@ -6138,6 +6426,31 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_time>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed(THD *thd)
+ {
+ date_mode_t fuzzy= Datetime::comparison_flags_for_get_date();
+ return has_value() ? Datetime(thd, this, fuzzy).to_packed() : 0;
+ }
+ longlong val_time_packed(THD *thd)
+ {
+ 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;
+ }
};
@@ -6149,6 +6462,30 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_datetime>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed(THD *thd)
+ {
+ return has_value() ? value : 0;
+ }
+ longlong val_time_packed(THD *thd)
+ {
+ return Time(thd, 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;
+ }
};
@@ -6160,6 +6497,24 @@ public:
Item *get_copy(THD *thd)
{ return get_item_copy<Item_cache_date>(thd, this); }
Item *make_literal(THD *);
+ longlong val_datetime_packed(THD *thd)
+ {
+ return has_value() ? value : 0;
+ }
+ longlong val_time_packed(THD *thd)
+ {
+ return Time(thd, 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;
+ }
};
@@ -6174,8 +6529,8 @@ public:
longlong val_int();
String* val_str(String *str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_real(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_real(thd, ltime, fuzzydate); }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)
@@ -6194,8 +6549,8 @@ public:
longlong val_int();
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); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return VDec(this).to_datetime_with_warn(thd, ltime, fuzzydate, this); }
bool cache_value();
Item *convert_to_basic_const_item(THD *thd);
Item *get_copy(THD *thd)
@@ -6222,8 +6577,8 @@ public:
longlong val_int();
String* val_str(String *);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
CHARSET_INFO *charset() const { return value->charset(); };
int save_in_field(Field *field, bool no_conversions);
bool cache_value();
@@ -6304,7 +6659,7 @@ public:
illegal_method_call((const char*)"val_decimal");
return 0;
};
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
illegal_method_call((const char*)"val_decimal");
return true;
@@ -6353,7 +6708,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,
@@ -6387,8 +6742,9 @@ public:
longlong val_int();
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)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ 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),
@@ -6528,4 +6884,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 ccbae1bad34..f5c49214076 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
@@ -707,10 +684,11 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
int Arg_comparator::compare_time()
{
- longlong val1= (*a)->val_time_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_time_packed(thd);
if (!(*a)->null_value)
{
- longlong val2= (*b)->val_time_packed();
+ longlong val2= (*b)->val_time_packed(thd);
if (!(*b)->null_value)
return compare_not_null_values(val1, val2);
}
@@ -722,8 +700,9 @@ int Arg_comparator::compare_time()
int Arg_comparator::compare_e_time()
{
- longlong val1= (*a)->val_time_packed();
- longlong val2= (*b)->val_time_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_time_packed(thd);
+ longlong val2= (*b)->val_time_packed(thd);
if ((*a)->null_value || (*b)->null_value)
return MY_TEST((*a)->null_value && (*b)->null_value);
return MY_TEST(val1 == val2);
@@ -733,10 +712,11 @@ int Arg_comparator::compare_e_time()
int Arg_comparator::compare_datetime()
{
- longlong val1= (*a)->val_datetime_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_datetime_packed(thd);
if (!(*a)->null_value)
{
- longlong val2= (*b)->val_datetime_packed();
+ longlong val2= (*b)->val_datetime_packed(thd);
if (!(*b)->null_value)
return compare_not_null_values(val1, val2);
}
@@ -748,8 +728,9 @@ int Arg_comparator::compare_datetime()
int Arg_comparator::compare_e_datetime()
{
- longlong val1= (*a)->val_datetime_packed();
- longlong val2= (*b)->val_datetime_packed();
+ THD *thd= current_thd;
+ longlong val1= (*a)->val_datetime_packed(thd);
+ longlong val2= (*b)->val_datetime_packed(thd);
if ((*a)->null_value || (*b)->null_value)
return MY_TEST((*a)->null_value && (*b)->null_value);
return MY_TEST(val1 == val2);
@@ -818,17 +799,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 +826,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 +1269,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 +1277,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 +1317,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]);
@@ -1892,7 +1869,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;
@@ -1971,11 +1948,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
@@ -2121,23 +2098,27 @@ 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;
+ THD *thd= current_thd;
+ longlong value= args[0]->val_datetime_packed(thd), 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(thd);
+ b= args[2]->val_datetime_packed(thd);
+ return val_int_cmp_int_finalize(value, a, b);
+}
+
+
+longlong Item_func_between::val_int_cmp_time()
+{
+ THD *thd= current_thd;
+ longlong value= args[0]->val_time_packed(thd), a, b;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ a= args[1]->val_time_packed(thd);
+ b= args[2]->val_time_packed(thd);
+ return val_int_cmp_int_finalize(value, a, b);
}
@@ -2176,39 +2157,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);
}
@@ -2316,12 +2299,12 @@ Item_func_ifnull::str_op(String *str)
}
-bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_ifnull::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < 2; i++)
{
- Datetime dt(current_thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
+ Datetime dt(thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
if (!(dt.copy_to_mysql_time(ltime, mysql_timestamp_type())))
return (null_value= false);
}
@@ -2329,12 +2312,12 @@ bool Item_func_ifnull::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item_func_ifnull::time_op(MYSQL_TIME *ltime)
+bool Item_func_ifnull::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < 2; i++)
{
- if (!Time(args[i]).copy_to_mysql_time(ltime))
+ if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
return (null_value= false);
}
return (null_value= true);
@@ -2816,23 +2799,23 @@ Item_func_nullif::decimal_op(my_decimal * decimal_value)
bool
-Item_func_nullif::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+Item_func_nullif::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (!compare())
return (null_value= true);
- Datetime dt(current_thd, args[2], fuzzydate);
+ Datetime dt(thd, args[2], fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
bool
-Item_func_nullif::time_op(MYSQL_TIME *ltime)
+Item_func_nullif::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
if (!compare())
return (null_value= true);
- return (null_value= Time(args[2]).copy_to_mysql_time(ltime));
+ return (null_value= Time(thd, args[2]).copy_to_mysql_time(ltime));
}
@@ -2914,7 +2897,7 @@ Item *Item_func_case_simple::find_item()
Item *Item_func_decode_oracle::find_item()
{
uint idx;
- if (!Predicant_to_list_comparator::cmp_nulls_equal(this, &idx))
+ if (!Predicant_to_list_comparator::cmp_nulls_equal(current_thd, this, &idx))
return args[idx + when_count()];
Item **pos= Item_func_decode_oracle::else_expr_addr();
return pos ? pos[0] : 0;
@@ -2990,24 +2973,24 @@ my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value)
}
-bool Item_func_case::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_case::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
Item *item= find_item();
if (!item)
return (null_value= true);
- Datetime dt(current_thd, item, fuzzydate);
+ Datetime dt(thd, item, fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
-bool Item_func_case::time_op(MYSQL_TIME *ltime)
+bool Item_func_case::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
Item *item= find_item();
if (!item)
return (null_value= true);
- return (null_value= Time(item).copy_to_mysql_time(ltime));
+ return (null_value= Time(thd, item).copy_to_mysql_time(ltime));
}
@@ -3343,12 +3326,12 @@ double Item_func_coalesce::real_op()
}
-bool Item_func_coalesce::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_coalesce::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < arg_count; i++)
{
- Datetime dt(current_thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
+ Datetime dt(thd, args[i], fuzzydate & ~TIME_FUZZY_DATES);
if (!dt.copy_to_mysql_time(ltime, mysql_timestamp_type()))
return (null_value= false);
}
@@ -3356,12 +3339,12 @@ bool Item_func_coalesce::date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
}
-bool Item_func_coalesce::time_op(MYSQL_TIME *ltime)
+bool Item_func_coalesce::time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
for (uint i= 0; i < arg_count; i++)
{
- if (!Time(args[i]).copy_to_mysql_time(ltime))
+ if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
return (null_value= false);
}
return (null_value= true);
@@ -3649,7 +3632,7 @@ void in_datetime::set(uint pos,Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
- buff->val= item->val_datetime_packed();
+ buff->val= item->val_datetime_packed(current_thd);
buff->unsigned_flag= 1L;
}
@@ -3657,13 +3640,22 @@ void in_time::set(uint pos,Item *item)
{
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
- buff->val= item->val_time_packed();
+ buff->val= item->val_time_packed(current_thd);
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(current_thd);
+ 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(current_thd);
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@@ -3875,39 +3867,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;
}
@@ -4000,9 +3968,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);
}
@@ -4019,14 +3986,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());
@@ -4037,7 +3996,7 @@ int cmp_item_datetime::cmp_not_null(const Value *val)
int cmp_item_datetime::cmp(Item *arg)
{
- const bool rc= value != arg->val_datetime_packed();
+ const bool rc= value != arg->val_datetime_packed(current_thd);
return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
@@ -4052,7 +4011,7 @@ int cmp_item_time::cmp_not_null(const Value *val)
int cmp_item_time::cmp(Item *arg)
{
- const bool rc= value != arg->val_time_packed();
+ const bool rc= value != arg->val_time_packed(current_thd);
return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
@@ -4296,25 +4255,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;
}
}
@@ -4324,19 +4342,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;
@@ -4375,8 +4384,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);
}
@@ -4647,7 +4655,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();
@@ -6301,76 +6309,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)
@@ -6675,7 +6660,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 60b56090a23..cf210a71433 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)
@@ -1008,8 +1011,8 @@ public:
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_length_and_dec()
{
if (aggregate_for_result(func_name(), args, arg_count, true))
@@ -1087,8 +1090,8 @@ public:
longlong int_op();
String *str_op(String *str);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_length_and_dec()
{
if (Item_func_case_abbreviation2::fix_length_and_dec2(args))
@@ -1122,12 +1125,12 @@ public:
:Item_func_case_abbreviation2(thd, a, b, c)
{ }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- Datetime dt(current_thd, find_item(), fuzzydate);
+ Datetime dt(thd, find_item(), fuzzydate);
return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type()));
}
- bool time_op(MYSQL_TIME *ltime)
+ bool time_op(THD *thd, MYSQL_TIME *ltime)
{
return (null_value= Time(find_item()).copy_to_mysql_time(ltime));
}
@@ -1240,8 +1243,8 @@ public:
Item_func_hybrid_field_type::cleanup();
arg_count= 2; // See the comment to the constructor
}
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
double real_op();
longlong int_op();
String *str_op(String *str);
@@ -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(current_thd);
+ 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(current_thd);
+ m_null_value= item->null_value;
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
@@ -1891,7 +1897,7 @@ class Predicant_to_list_comparator
return UNKNOWN;
return in_item->cmp(args->arguments()[m_comparators[i].m_arg_index]);
}
- int cmp_args_nulls_equal(Item_args *args, uint i)
+ int cmp_args_nulls_equal(THD *thd, Item_args *args, uint i)
{
Predicant_to_value_comparator *cmp=
&m_comparators[m_comparators[i].m_handler_index];
@@ -1902,7 +1908,7 @@ class Predicant_to_list_comparator
ValueBuffer<MAX_FIELD_WIDTH> val;
if (m_comparators[i].m_handler_index == i)
in_item->store_value(predicant);
- m_comparators[i].m_handler->Item_save_in_value(arg, &val);
+ m_comparators[i].m_handler->Item_save_in_value(thd, arg, &val);
if (predicant->null_value && val.is_null())
return FALSE; // Two nulls are equal
if (predicant->null_value || val.is_null())
@@ -2083,12 +2089,12 @@ public:
/*
Same as above, but treats two NULLs as equal, e.g. as in DECODE_ORACLE().
*/
- bool cmp_nulls_equal(Item_args *args, uint *idx)
+ bool cmp_nulls_equal(THD *thd, Item_args *args, uint *idx)
{
for (uint i= 0 ; i < m_comparator_count ; i++)
{
DBUG_ASSERT(m_comparators[i].m_handler != NULL);
- if (cmp_args_nulls_equal(args, i) == FALSE)
+ if (cmp_args_nulls_equal(thd, args, i) == FALSE)
{
*idx= m_comparators[i].m_arg_index;
return false; // Found a matching value
@@ -2124,8 +2130,8 @@ public:
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate);
- bool time_op(MYSQL_TIME *ltime);
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool time_op(THD *thd, MYSQL_TIME *ltime);
bool fix_fields(THD *thd, Item **ref);
table_map not_null_tables() const { return 0; }
const char *func_name() const { return "case"; }
@@ -2421,12 +2427,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)
{
@@ -2507,9 +2520,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;
@@ -3084,7 +3096,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 */
@@ -3142,6 +3153,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>;
@@ -3293,11 +3306,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
@@ -3398,11 +3408,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 c5ac97f2905..20c0a2564bb 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();
}
}
@@ -734,7 +734,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);
}
@@ -806,50 +806,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();
@@ -875,14 +831,13 @@ Item_func_hybrid_field_type::val_decimal_from_int_op(my_decimal *dec)
return dec;
}
-bool Item_func_hybrid_field_type::get_date_from_int_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
+bool Item_func_hybrid_field_type::get_date_from_int_op(THD *thd,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
- 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()))
+ Longlong_hybrid value(int_op(), unsigned_flag);
+ if (null_value || int_to_datetime_with_warn(thd, value,
+ ltime, fuzzydate, NULL))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
}
@@ -912,12 +867,13 @@ Item_func_hybrid_field_type::val_decimal_from_real_op(my_decimal *dec)
return dec;
}
-bool Item_func_hybrid_field_type::get_date_from_real_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
+bool Item_func_hybrid_field_type::get_date_from_real_op(THD *thd,
+ MYSQL_TIME *ltime,
+ date_mode_t 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(thd, value, ltime, fuzzydate, NULL))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
}
@@ -926,7 +882,7 @@ bool Item_func_hybrid_field_type::get_date_from_real_op(MYSQL_TIME *ltime,
String *Item_func_hybrid_field_type::val_str_from_date_op(String *str)
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime) ||
+ if (date_op_with_null_check(current_thd, &ltime) ||
(null_value= str->alloc(MAX_DATE_STRING_REP_LENGTH)))
return (String *) 0;
str->length(my_TIME_to_str(&ltime, const_cast<char*>(str->ptr()), decimals));
@@ -938,7 +894,7 @@ String *Item_func_hybrid_field_type::val_str_from_date_op(String *str)
double Item_func_hybrid_field_type::val_real_from_date_op()
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
return 0;
return TIME_to_double(&ltime);
}
@@ -946,7 +902,7 @@ double Item_func_hybrid_field_type::val_real_from_date_op()
longlong Item_func_hybrid_field_type::val_int_from_date_op()
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
return 0;
return TIME_to_ulonglong(&ltime);
}
@@ -955,7 +911,7 @@ my_decimal *
Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec)
{
MYSQL_TIME ltime;
- if (date_op_with_null_check(&ltime))
+ if (date_op_with_null_check(current_thd, &ltime))
{
my_decimal_set_zero(dec);
return 0;
@@ -967,7 +923,7 @@ Item_func_hybrid_field_type::val_decimal_from_date_op(my_decimal *dec)
String *Item_func_hybrid_field_type::val_str_from_time_op(String *str)
{
MYSQL_TIME ltime;
- if (time_op_with_null_check(&ltime) ||
+ if (time_op_with_null_check(current_thd, &ltime) ||
(null_value= my_TIME_to_str(&ltime, str, decimals)))
return NULL;
return str;
@@ -976,20 +932,22 @@ String *Item_func_hybrid_field_type::val_str_from_time_op(String *str)
double Item_func_hybrid_field_type::val_real_from_time_op()
{
MYSQL_TIME ltime;
- return time_op_with_null_check(&ltime) ? 0 : TIME_to_double(&ltime);
+ return time_op_with_null_check(current_thd, &ltime) ? 0 :
+ TIME_to_double(&ltime);
}
longlong Item_func_hybrid_field_type::val_int_from_time_op()
{
MYSQL_TIME ltime;
- return time_op_with_null_check(&ltime) ? 0 : TIME_to_ulonglong(&ltime);
+ return time_op_with_null_check(current_thd, &ltime) ? 0 :
+ TIME_to_ulonglong(&ltime);
}
my_decimal *
Item_func_hybrid_field_type::val_decimal_from_time_op(my_decimal *dec)
{
MYSQL_TIME ltime;
- if (time_op_with_null_check(&ltime))
+ if (time_op_with_null_check(current_thd, &ltime))
{
my_decimal_set_zero(dec);
return 0;
@@ -1017,13 +975,14 @@ Item_func_hybrid_field_type::val_decimal_from_str_op(my_decimal *decimal_value)
return res ? decimal_from_string_with_check(decimal_value, res) : 0;
}
-bool Item_func_hybrid_field_type::get_date_from_str_op(MYSQL_TIME *ltime,
- ulonglong fuzzydate)
+bool Item_func_hybrid_field_type::get_date_from_str_op(THD *thd,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
StringBuffer<40> tmp;
String *res;
if (!(res= str_op_with_null_check(&tmp)) ||
- str_to_datetime_with_warn(res->charset(), res->ptr(), res->length(),
+ str_to_datetime_with_warn(thd, res->charset(), res->ptr(), res->length(),
ltime, fuzzydate))
return make_zero_mysql_time(ltime, fuzzydate);
return (null_value= 0);
@@ -1048,47 +1007,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)
{
@@ -1272,17 +1199,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;
}
@@ -1412,18 +1335,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;
}
@@ -1522,17 +1440,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;
}
@@ -1583,21 +1497,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)
@@ -1687,20 +1595,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();
@@ -1708,8 +1610,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;
@@ -1811,17 +1712,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;
@@ -1891,10 +1786,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;
}
@@ -1918,7 +1813,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
@@ -1989,10 +1884,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;
@@ -2314,25 +2209,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();
}
@@ -2350,10 +2235,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;
}
@@ -2361,25 +2245,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();
}
@@ -2397,10 +2275,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;
}
@@ -2589,16 +2466,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;
}
@@ -2736,14 +2613,15 @@ bool Item_func_min_max::fix_attributes(Item **items, uint nitems)
0 Otherwise
*/
-bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_min_max::get_date_native(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
longlong UNINIT_VAR(min_max);
DBUG_ASSERT(fixed == 1);
for (uint i=0; i < arg_count ; i++)
{
- longlong res= args[i]->val_datetime_packed();
+ longlong res= args[i]->val_datetime_packed(thd);
/* Check if we need to stop (because of error or KILL) and stop the loop */
if (unlikely(args[i]->null_value))
@@ -2754,8 +2632,8 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
unpack_time(min_max, ltime, mysql_timestamp_type());
- if (!(fuzzy_date & TIME_TIME_ONLY) &&
- unlikely((null_value= check_date_with_warn(ltime, fuzzy_date,
+ if (!(fuzzydate & TIME_TIME_ONLY) &&
+ unlikely((null_value= check_date_with_warn(thd, ltime, fuzzydate,
MYSQL_TIMESTAMP_ERROR))))
return true;
@@ -2763,17 +2641,17 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
-bool Item_func_min_max::get_time_native(MYSQL_TIME *ltime)
+bool Item_func_min_max::get_time_native(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(fixed == 1);
- Time value(args[0]);
+ Time value(thd, args[0], Time::Options(), decimals);
if (!value.is_valid_time())
return (null_value= true);
for (uint i= 1; i < arg_count ; i++)
{
- Time tmp(args[i]);
+ Time tmp(thd, args[i], Time::Options(), decimals);
if (!tmp.is_valid_time())
return (null_value= true);
@@ -3018,14 +2896,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);
}
}
@@ -3278,6 +3156,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++)
@@ -3301,7 +3180,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);
@@ -3605,32 +3485,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;
@@ -3646,21 +3500,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()
@@ -3727,7 +3566,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;
}
@@ -4438,7 +4277,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))+
@@ -4693,7 +4532,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;
@@ -4758,11 +4597,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:
@@ -4787,11 +4622,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;
@@ -5528,10 +5359,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;
/*
@@ -5589,7 +5419,8 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
}
-bool Item_user_var_as_out_param::get_date(MYSQL_TIME *ltime, ulonglong fuzzy)
+bool Item_user_var_as_out_param::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
@@ -5628,7 +5459,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;
}
@@ -6468,7 +6299,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;
/*
@@ -6483,7 +6314,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
if (res)
{
- context->process_error(thd);
+ process_error(thd);
DBUG_RETURN(res);
}
}
@@ -6500,7 +6331,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);
}
@@ -6685,10 +6516,10 @@ my_decimal *Item_func_last_value::val_decimal(my_decimal *decimal_value)
}
-bool Item_func_last_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_func_last_value::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
evaluate_sideeffects();
- bool tmp= last_value->get_date(ltime, fuzzydate);
+ bool tmp= last_value->get_date(thd, ltime, fuzzydate);
null_value= last_value->null_value;
return tmp;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index fd789ffdc51..602b13fad7a 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;
@@ -80,49 +80,56 @@ public:
CASE_SEARCHED_FUNC, // Used by ColumnStore/Spider
CASE_SIMPLE_FUNC // Used by ColumnStore/spider
};
+ 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 ||
@@ -134,11 +141,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()
{
@@ -174,16 +180,12 @@ public:
virtual void print(String *str, enum_query_type query_type);
void print_op(String *str, enum_query_type query_type);
void print_args(String *str, uint from, enum_query_type query_type);
- inline bool get_arg0_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
- {
- DBUG_ASSERT(!(fuzzy_date & TIME_TIME_ONLY));
- Datetime dt(current_thd, args[0], fuzzy_date);
- return (null_value= dt.copy_to_mysql_time(ltime));
- }
bool is_null() {
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)
@@ -338,6 +340,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
@@ -380,6 +387,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; }
};
@@ -400,8 +411,8 @@ public:
DBUG_ASSERT(fixed == 1);
return Converter_double_to_longlong(val_real(), unsigned_flag).result();
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_real(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_real(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const { return &type_handler_double; }
bool fix_length_and_dec()
{
@@ -441,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(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t 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(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate)
+ {
+ return m_func_handler->get_date(thd, this, to, fuzzydate);
+ }
+};
+
+
/**
Functions that at fix_fields() time determine the returned field type,
trying to preserve the exact data type of the arguments.
@@ -463,15 +661,15 @@ class Item_func_hybrid_field_type: public Item_hybrid_func
Helper methods to make sure that the result of
decimal_op(), str_op() and date_op() is properly synched with null_value.
*/
- bool date_op_with_null_check(MYSQL_TIME *ltime)
+ bool date_op_with_null_check(THD *thd, MYSQL_TIME *ltime)
{
- bool rc= date_op(ltime, 0);
+ bool rc= date_op(thd, ltime, date_mode_t(0));
DBUG_ASSERT(!rc ^ null_value);
return rc;
}
- bool time_op_with_null_check(MYSQL_TIME *ltime)
+ bool time_op_with_null_check(THD *thd, MYSQL_TIME *ltime)
{
- bool rc= time_op(ltime);
+ bool rc= time_op(thd, ltime);
DBUG_ASSERT(!rc ^ null_value);
DBUG_ASSERT(rc || ltime->time_type == MYSQL_TIMESTAMP_TIME);
return rc;
@@ -482,13 +680,7 @@ 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)
+ bool make_zero_mysql_time(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
bzero(ltime, sizeof(*ltime));
return null_value|= !(fuzzydate & TIME_FUZZY_DATES);
@@ -500,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();
@@ -514,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);
@@ -528,20 +715,17 @@ 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);
+ bool get_date_from_str_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_real_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
+ bool get_date_from_int_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
public:
Item_func_hybrid_field_type(THD *thd):
@@ -586,11 +770,11 @@ public:
DBUG_ASSERT(null_value == (res == NULL));
return res;
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
return Item_func_hybrid_field_type::type_handler()->
- Item_func_hybrid_field_type_get_date(this, res, fuzzy_date);
+ Item_func_hybrid_field_type_get_date(thd, this, res, fuzzydate);
}
/**
@@ -600,6 +784,16 @@ public:
@return The result of the operation.
*/
virtual longlong int_op()= 0;
+ Longlong_null to_longlong_null_op()
+ {
+ longlong nr= int_op();
+ /*
+ C++ does not guarantee the order of parameter evaluation,
+ so to make sure "null_value" is passed to the constructor
+ after the int_op() call, int_op() is caled on a separate line.
+ */
+ return Longlong_null(nr, null_value);
+ }
/**
@brief Performs the operation that this functions implements when the
@@ -634,14 +828,14 @@ public:
field type is DATETIME or DATE.
@return The result of the operation.
*/
- virtual bool date_op(MYSQL_TIME *res, ulonglong fuzzy_date)= 0;
+ virtual bool date_op(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)= 0;
/**
@brief Performs the operation that this functions implements when
field type is TIME.
@return The result of the operation.
*/
- virtual bool time_op(MYSQL_TIME *res)= 0;
+ virtual bool time_op(THD *thd, MYSQL_TIME *res)= 0;
};
@@ -700,12 +894,12 @@ public:
Item_func_hybrid_field_type(thd, list)
{ }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
}
- bool time_op(MYSQL_TIME *ltime)
+ bool time_op(THD *thd, MYSQL_TIME *ltime)
{
DBUG_ASSERT(0);
return true;
@@ -791,8 +985,8 @@ public:
{ collation.set_numeric(); }
double val_real();
String *val_str(String*str);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const= 0;
bool fix_length_and_dec() { return FALSE; }
};
@@ -982,12 +1176,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); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return VDec(this).to_datetime_with_warn(thd, ltime, fuzzydate, this); }
const Type_handler *type_handler() const { return &type_handler_newdecimal; }
void fix_length_and_dec_generic() {}
bool fix_length_and_dec()
@@ -1541,8 +1735,8 @@ public:
double val_real_native();
longlong val_int_native();
my_decimal *val_decimal_native(my_decimal *);
- bool get_date_native(MYSQL_TIME *res, ulonglong fuzzydate);
- bool get_time_native(MYSQL_TIME *res);
+ bool get_date_native(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
+ bool get_time_native(THD *thd, MYSQL_TIME *res);
double val_real()
{
@@ -1568,11 +1762,11 @@ public:
return Item_func_min_max::type_handler()->
Item_func_min_max_val_decimal(this, dec);
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed);
return Item_func_min_max::type_handler()->
- Item_func_min_max_get_date(this, res, fuzzy_date);
+ Item_func_min_max_get_date(thd, this, res, fuzzydate);
}
void aggregate_attributes_real(Item **items, uint nitems)
{
@@ -1639,8 +1833,8 @@ public:
String *val_str(String *str) { return val_str_from_item(args[0], str); }
my_decimal *val_decimal(my_decimal *dec)
{ return val_decimal_from_item(args[0], dec); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_item(args[0], ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_item(thd, args[0], ltime, fuzzydate); }
const char *func_name() const { return "rollup_const"; }
bool const_item() const { return 0; }
const Type_handler *type_handler() const { return args[0]->type_handler(); }
@@ -2007,6 +2201,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) {}
@@ -2084,9 +2290,9 @@ public:
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
};
@@ -2147,10 +2353,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)
@@ -2381,13 +2596,13 @@ 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);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return type_handler()->Item_get_date(this, ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return type_handler()->Item_get_date(thd, this, ltime, fuzzydate); }
};
@@ -2515,14 +2730,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;
@@ -2557,12 +2772,18 @@ 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);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */
bool fix_fields(THD *thd, Item **ref);
@@ -2609,9 +2830,9 @@ public:
String* val_str(String*);
my_decimal *val_decimal(my_decimal *dec_buf)
{ return val_decimal_from_real(dec_buf); }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
/* TODO: fix to support views */
const char *func_name() const { return "get_system_var"; }
@@ -2870,6 +3091,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 ?
@@ -2899,7 +3122,7 @@ public:
return sp_result_field->val_decimal(dec_buf);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (execute())
return true;
@@ -3053,7 +3276,7 @@ public:
longlong val_int();
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec();
const char *func_name() const { return "last_value"; }
const Type_handler *type_handler() const { return last_value->type_handler(); }
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 230d954aa77..4ec481cf439 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..4f60a33ab9f 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 *)
@@ -82,7 +91,7 @@ public:
illegal_method_call((const char*)"val_decimal");
return 0;
};
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
illegal_method_call((const char*)"get_date");
return true;
@@ -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 fda7f59b128..6c82c580858 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);
@@ -4547,11 +4543,11 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
break;
case DYN_COL_DATETIME:
case DYN_COL_DATE:
- args[valpos]->get_date(&vals[i].x.time_value,
+ args[valpos]->get_date(thd, &vals[i].x.time_value,
sql_mode_for_dates(thd));
break;
case DYN_COL_TIME:
- args[valpos]->get_time(&vals[i].x.time_value);
+ args[valpos]->get_time(thd, &vals[i].x.time_value);
break;
default:
DBUG_ASSERT(0);
@@ -5117,7 +5113,7 @@ null:
}
-bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_dyncol_get::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DYNAMIC_COLUMN_VALUE val;
char buff[STRING_BUFFER_USUAL_SIZE];
@@ -5138,10 +5134,8 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
if (signed_value || val.x.ulong_value <= LONGLONG_MAX)
{
longlong llval = (longlong)val.x.ulong_value;
- bool neg = llval < 0;
- if (int_to_datetime_with_warn(neg, (ulonglong)(neg ? -llval :
- llval),
- ltime, fuzzy_date, 0 /* TODO */))
+ if (int_to_datetime_with_warn(thd, Longlong_hybrid(llval, !signed_value),
+ ltime, fuzzydate, 0 /* TODO */))
goto null;
return 0;
}
@@ -5149,20 +5143,20 @@ bool Item_dyncol_get::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
val.x.double_value= static_cast<double>(ULONGLONG_MAX);
/* fall through */
case DYN_COL_DOUBLE:
- if (double_to_datetime_with_warn(val.x.double_value, ltime, fuzzy_date,
+ if (double_to_datetime_with_warn(thd, val.x.double_value, ltime, fuzzydate,
0 /* TODO */))
goto null;
return 0;
case DYN_COL_DECIMAL:
- if (decimal_to_datetime_with_warn((my_decimal*)&val.x.decimal.value, ltime,
- fuzzy_date, 0 /* TODO */))
+ if (decimal_to_datetime_with_warn(thd, (my_decimal*)&val.x.decimal.value,
+ ltime, fuzzydate, 0 /* TODO */))
goto null;
return 0;
case DYN_COL_STRING:
- if (str_to_datetime_with_warn(&my_charset_numeric,
+ if (str_to_datetime_with_warn(thd, &my_charset_numeric,
val.x.string.value.str,
val.x.string.value.length,
- ltime, fuzzy_date))
+ ltime, fuzzydate))
goto null;
return 0;
case DYN_COL_DATETIME:
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 29af0b43d9d..762a3c2559e 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -62,16 +62,11 @@ public:
longlong val_int();
double val_real();
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_string(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_string(thd, ltime, fuzzydate); }
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);
- }
};
@@ -1470,11 +1465,11 @@ public:
return NULL;
return res;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
if (args[0]->result_type() == STRING_RESULT)
- return Item_str_func::get_date(ltime, fuzzydate);
- bool res= args[0]->get_date(ltime, fuzzydate);
+ return Item_str_func::get_date(thd, ltime, fuzzydate);
+ bool res= args[0]->get_date(thd, ltime, fuzzydate);
if ((null_value= args[0]->null_value))
return 1;
return res;
@@ -1769,7 +1764,7 @@ public:
double val_real();
my_decimal *val_decimal(my_decimal *);
bool get_dyn_value(THD *thd, DYNAMIC_COLUMN_VALUE *val, String *tmp);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
void print(String *str, enum_query_type query_type);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_dyncol_get>(thd, this); }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 1947a45186a..9298c9998a8 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
@@ -1383,15 +1388,15 @@ bool Item_singlerow_subselect::val_bool()
}
-bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
+bool Item_singlerow_subselect::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (forced_const)
- return value->get_date(ltime, fuzzydate);
+ return value->get_date(thd, ltime, fuzzydate);
if (!exec() && !value->null_value)
{
null_value= FALSE;
- return value->get_date(ltime, fuzzydate);
+ return value->get_date(thd, ltime, fuzzydate);
}
else
{
@@ -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..443354f4900 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);
@@ -304,7 +308,7 @@ public:
String *val_str (String *);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
const Type_handler *type_handler() const;
bool fix_length_and_dec();
@@ -395,14 +399,14 @@ 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*);
my_decimal *val_decimal(my_decimal *);
bool val_bool();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
- { return get_date_from_int(ltime, fuzzydate); }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ { return get_date_from_int(thd, ltime, fuzzydate); }
bool fix_fields(THD *thd, Item **ref);
bool fix_length_and_dec();
void print(String *str, enum_query_type query_type);
@@ -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..d1865c7e771 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);
}
@@ -2309,12 +2305,12 @@ void Item_sum_hybrid::clear()
bool
-Item_sum_hybrid::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+Item_sum_hybrid::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (null_value)
return true;
- bool retval= value->get_date(ltime, fuzzydate);
+ bool retval= value->get_date(thd, ltime, fuzzydate);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == true);
return retval;
@@ -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..c88a850c241 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; }
};
@@ -735,9 +742,9 @@ public:
longlong val_int() { return val_int_from_real(); /* Real as default */ }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
void reset_field();
};
@@ -1060,7 +1067,7 @@ protected:
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
void reset_field();
String *val_str(String *);
const Type_handler *real_type_handler() const
@@ -1356,7 +1363,7 @@ public:
void update_field(){DBUG_ASSERT(0);}
void clear();
void cleanup();
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return execute() || sp_result_field->get_date(ltime, fuzzydate);
}
@@ -1384,17 +1391,21 @@ 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)
{
return mark_unsupported_function(name.str, arg, VCOL_IMPOSSIBLE);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
};
@@ -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); }
@@ -1545,9 +1565,9 @@ public:
void update_field() {};
void cleanup();
virtual void print(String *str, enum_query_type query_type);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
};
@@ -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; }
@@ -1845,9 +1874,9 @@ public:
{
return val_decimal_from_string(decimal_value);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_string(ltime, fuzzydate);
+ return get_date_from_string(thd, ltime, fuzzydate);
}
String* val_str(String* str);
Item *copy_or_same(THD* thd);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 4d17bc354d4..f12c8e12668 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -59,6 +59,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
@@ -103,12 +126,12 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0,
1 error
*/
-static bool extract_date_time(DATE_TIME_FORMAT *format,
+static bool extract_date_time(THD *thd, DATE_TIME_FORMAT *format,
const char *val, uint length, MYSQL_TIME *l_time,
timestamp_type cached_timestamp_type,
const char **sub_pattern_end,
const char *date_time_type,
- ulonglong fuzzy_date)
+ date_mode_t fuzzydate)
{
int weekday= 0, yearday= 0, daypart= 0;
int week_number= -1;
@@ -303,17 +326,17 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
We can't just set error here, as we don't want to generate two
warnings in case of errors
*/
- if (extract_date_time(&time_ampm_format, val,
+ if (extract_date_time(thd, &time_ampm_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time", fuzzy_date))
+ cached_timestamp_type, &val, "time", fuzzydate))
DBUG_RETURN(1);
break;
/* Time in 24-hour notation */
case 'T':
- if (extract_date_time(&time_24hrs_format, val,
+ if (extract_date_time(thd, &time_24hrs_format, val,
(uint)(val_end - val), l_time,
- cached_timestamp_type, &val, "time", fuzzy_date))
+ cached_timestamp_type, &val, "time", fuzzydate))
DBUG_RETURN(1);
break;
@@ -419,7 +442,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
goto err;
int was_cut;
- if (check_date(l_time, fuzzy_date | TIME_INVALID_DATES, &was_cut))
+ if (check_date(l_time, fuzzydate | TIME_INVALID_DATES, &was_cut))
goto err;
if (val != val_end)
@@ -428,10 +451,9 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
{
if (!my_isspace(&my_charset_latin1,*val))
{
- make_truncated_value_warning(current_thd,
- Sql_condition::WARN_LEVEL_WARN,
- val_begin, length,
- cached_timestamp_type, NullS);
+ ErrConvString err(val_begin, length, &my_charset_bin);
+ make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ &err, cached_timestamp_type, NullS);
break;
}
} while (++val != val_end);
@@ -440,7 +462,6 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
err:
{
- THD *thd= current_thd;
char buff[128];
strmake(buff, val_begin, MY_MIN(length, sizeof(buff)-1));
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
@@ -787,10 +808,8 @@ longlong Item_func_period_diff::val_int()
longlong Item_func_to_days::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 : d.daynr();
}
@@ -798,42 +817,26 @@ longlong Item_func_to_seconds::val_int_endpoint(bool left_endp,
bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong seconds;
- longlong days;
- int dummy; /* unused */
- if (get_arg0_date(&ltime, TIME_FUZZY_DATES))
+ Datetime dt(current_thd, args[0], TIME_FUZZY_DATES);
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
- seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
- seconds= ltime.neg ? -seconds : seconds;
- days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
- seconds+= days * 24L * 3600L;
/* Set to NULL if invalid date, but keep the value */
- null_value= check_date(&ltime,
- (ltime.year || ltime.month || ltime.day),
- (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
- &dummy);
+ null_value= dt.check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
/*
Even if the evaluation return NULL, seconds is useful for pruning
*/
- return seconds;
+ return dt.to_seconds();
}
longlong Item_func_to_seconds::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- longlong seconds;
- longlong days;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second;
- seconds=ltime.neg ? -seconds : seconds;
- days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day);
- return seconds + days * 24L * 3600L;
+ THD *thd= current_thd;
+ Datetime dt(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !dt.is_valid_datetime()) ? 0 : dt.to_seconds();
}
/*
@@ -877,19 +880,16 @@ enum_monotonicity_info Item_func_to_seconds::get_monotonicity_info() const
longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
+ Datetime dt(current_thd, args[0], date_mode_t(0));
longlong res;
- int dummy; /* unused */
- if (get_arg0_date(&ltime, 0))
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
}
- res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
+ res= (longlong) dt.daynr();
/* Set to NULL if invalid date, but keep the value */
- null_value= check_date(&ltime,
- (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE),
- &dummy);
+ null_value= dt.check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
if (null_value)
{
/*
@@ -918,8 +918,8 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15')
*/
- if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second ||
- ltime.second_part)) ||
+ const MYSQL_TIME &ltime= dt.get_mysql_time()[0];
+ if ((!left_endp && dt.hhmmssff_is_zero()) ||
(left_endp && ltime.hour == 23 && ltime.minute == 59 &&
ltime.second == 59))
/* do nothing */
@@ -933,25 +933,22 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp)
longlong Item_func_dayofyear::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE))
- return 0;
- return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day) -
- calc_daynr(ltime.year,1,1) + 1;
+ Date d(current_thd, args[0], TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 : d.dayofyear();
}
longlong Item_func_dayofmonth::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.day;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->day;
}
longlong Item_func_month::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.month;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->month;
}
@@ -973,12 +970,12 @@ String* Item_func_monthname::val_str(String* str)
DBUG_ASSERT(fixed == 1);
const char *month_name;
uint err;
- MYSQL_TIME ltime;
+ Date d(current_thd, args[0], date_mode_t(0));
- if ((null_value= (get_arg0_date(&ltime, 0) || !ltime.month)))
+ if ((null_value= (!d.is_valid_date() || !d.get_mysql_time()->month)))
return (String *) 0;
- month_name= locale->month_names->type_names[ltime.month - 1];
+ month_name= locale->month_names->type_names[d.get_mysql_time()->month - 1];
str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
collation.collation, &err);
return str;
@@ -992,23 +989,21 @@ String* Item_func_monthname::val_str(String* str)
longlong Item_func_quarter::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, 0))
- return 0;
- return (longlong) ((ltime.month+2)/3);
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.quarter();
}
longlong Item_func_hour::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->hour;
}
longlong Item_func_minute::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->minute;
}
@@ -1018,7 +1013,7 @@ longlong Item_func_minute::val_int()
longlong Item_func_second::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return (null_value= !tm.is_valid_time()) ? 0 : tm.get_mysql_time()->second;
}
@@ -1065,43 +1060,34 @@ uint week_mode(uint mode)
longlong Item_func_week::val_int()
{
DBUG_ASSERT(fixed == 1);
- uint year, week_format;
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
+ uint week_format;
+ THD *thd= current_thd;
+ Date d(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !d.is_valid_date()))
return 0;
if (arg_count > 1)
week_format= (uint)args[1]->val_int();
else
- week_format= current_thd->variables.default_week_format;
- return (longlong) calc_week(&ltime, week_mode(week_format), &year);
+ week_format= thd->variables.default_week_format;
+ return d.week(week_mode(week_format));
}
longlong Item_func_yearweek::val_int()
{
DBUG_ASSERT(fixed == 1);
- uint year,week;
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
- week= calc_week(&ltime,
- (week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
- &year);
- return week+year*100;
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return (null_value= !d.is_valid_date()) ? 0 :
+ d.yearweek((week_mode((uint) args[1]->val_int()) | WEEK_YEAR));
}
longlong Item_func_weekday::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
-
- if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return 0;
-
- return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month,
- ltime.day),
- odbc_type) + MY_TEST(odbc_type);
+ Date d(current_thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ return ((null_value= !d.is_valid_date())) ? 0 :
+ calc_weekday(d.daynr(), odbc_type) + MY_TEST(odbc_type);
}
bool Item_func_dayname::fix_length_and_dec()
@@ -1137,8 +1123,8 @@ String* Item_func_dayname::val_str(String* str)
longlong Item_func_year::val_int()
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- return get_arg0_date(&ltime, 0) ? 0 : (longlong) ltime.year;
+ Date d(current_thd, args[0], date_mode_t(0));
+ return (null_value= !d.is_valid_date()) ? 0 : d.get_mysql_time()->year;
}
@@ -1169,8 +1155,8 @@ enum_monotonicity_info Item_func_year::get_monotonicity_info() const
longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
{
DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, 0))
+ Datetime dt(current_thd, args[0], date_mode_t(0));
+ if ((null_value= !dt.is_valid_datetime()))
{
/* got NULL, leave the incl_endp intact */
return LONGLONG_MIN;
@@ -1187,8 +1173,9 @@ longlong Item_func_year::val_int_endpoint(bool left_endp, bool *incl_endp)
col < '2007-09-15 23:00:00' -> YEAR(col) <= 2007
*/
+ const MYSQL_TIME &ltime= dt.get_mysql_time()[0];
if (!left_endp && ltime.day == 1 && ltime.month == 1 &&
- !(ltime.hour || ltime.minute || ltime.second || ltime.second_part))
+ dt.hhmmssff_is_zero())
; /* do nothing */
else
*incl_endp= TRUE;
@@ -1212,13 +1199,14 @@ bool Item_func_unix_timestamp::get_timestamp_value(my_time_t *seconds,
}
}
- MYSQL_TIME ltime;
- if (get_arg0_date(&ltime, TIME_NO_ZERO_IN_DATE))
- return 1;
+ THD *thd= current_thd;
+ Datetime dt(thd, args[0], TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !dt.is_valid_datetime()))
+ return true;
uint error_code;
- *seconds= TIME_to_timestamp(current_thd, &ltime, &error_code);
- *second_part= ltime.second_part;
+ *seconds= TIME_to_timestamp(thd, dt.get_mysql_time(), &error_code);
+ *second_part= dt.get_mysql_time()->second_part;
return (null_value= (error_code == ER_WARN_DATA_OUT_OF_RANGE));
}
@@ -1276,7 +1264,7 @@ longlong Item_func_unix_timestamp::val_int_endpoint(bool left_endp, bool *incl_e
longlong Item_func_time_to_sec::int_op()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return ((null_value= !tm.is_valid_time())) ? 0 : tm.to_seconds();
}
@@ -1284,7 +1272,7 @@ longlong Item_func_time_to_sec::int_op()
my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
if ((null_value= !tm.is_valid_time()))
return 0;
const MYSQL_TIME *ltime= tm.get_mysql_time();
@@ -1299,7 +1287,8 @@ my_decimal *Item_func_time_to_sec::decimal_op(my_decimal* buf)
To make code easy, allow interval objects without separators.
*/
-bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval)
+bool get_interval_value(THD *thd, Item *args,
+ interval_type int_type, INTERVAL *interval)
{
ulonglong array[5];
longlong UNINIT_VAR(value);
@@ -1312,25 +1301,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());
+ 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)
@@ -1476,90 +1459,11 @@ 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)
+bool Item_func_from_days::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
longlong value=args[0]->val_int();
if ((null_value= (args[0]->null_value ||
- ((fuzzy_date & TIME_NO_ZERO_DATE) && value == 0))))
+ ((fuzzydate & TIME_NO_ZERO_DATE) && value == 0))))
return true;
bzero(ltime, sizeof(MYSQL_TIME));
if (get_date_from_daynr((long) value, &ltime->year, &ltime->month,
@@ -1596,10 +1500,9 @@ void Item_func_curdate_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_curdate::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_curdate::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1626,10 +1529,9 @@ bool Item_func_curtime::fix_fields(THD *thd, Item **items)
return Item_timefunc::fix_fields(thd, items);
}
-bool Item_func_curtime::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_curtime::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1700,7 +1602,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)
@@ -1727,7 +1629,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);
}
@@ -1758,10 +1660,9 @@ void Item_func_now_utc::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_now::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_now::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- THD *thd= current_thd;
query_id_t query_id= thd->query_id;
/* Cache value for this query */
if (last_query_id != query_id)
@@ -1787,62 +1688,22 @@ void Item_func_sysdate_local::store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)
}
-bool Item_func_sysdate_local::get_date(MYSQL_TIME *res,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_sysdate_local::get_date(THD *thd, MYSQL_TIME *res,
+ date_mode_t fuzzydate __attribute__((unused)))
{
- store_now_in_TIME(current_thd, res);
+ store_now_in_TIME(thd, res);
return 0;
}
-bool Item_func_sec_to_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_sec_to_time::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
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(thd, 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(thd, "seconds");
+ return false;
}
bool Item_func_date_format::fix_length_and_dec()
@@ -1998,7 +1859,9 @@ String *Item_func_date_format::val_str(String *str)
const MY_LOCALE *lc= 0;
DBUG_ASSERT(fixed == 1);
- if ((null_value= args[0]->get_date(&l_time, is_time_format ? TIME_TIME_ONLY : 0)))
+ if ((null_value= args[0]->get_date(current_thd, &l_time,
+ is_time_format ? TIME_TIME_ONLY :
+ date_mode_t(0))))
return 0;
if (!(format = args[1]->val_str(str)) || !format->length())
@@ -2049,35 +1912,30 @@ 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 Item_func_from_unixtime::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate __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(thd, 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);
}
-bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
- ulonglong fuzzy_date __attribute__((unused)))
+bool Item_func_convert_tz::get_date(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate __attribute__((unused)))
{
my_time_t my_time_tmp;
String str;
- THD *thd= current_thd;
if (!from_tz_cached)
{
@@ -2091,9 +1949,12 @@ bool Item_func_convert_tz::get_date(MYSQL_TIME *ltime,
to_tz_cached= args[2]->const_item();
}
- if (from_tz==0 || to_tz==0 ||
- get_arg0_date(ltime, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE))
- return (null_value= 1);
+ if ((null_value= (from_tz == 0 || to_tz == 0)))
+ return true;
+
+ Datetime *dt= new(ltime) Datetime(thd, args[0], TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE);
+ if ((null_value= !dt->is_valid_datetime()))
+ return true;
{
uint not_used;
@@ -2113,7 +1974,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();
}
@@ -2144,81 +2005,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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t 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);
+ // 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);
}
@@ -2274,7 +2098,7 @@ bool Item_extract::fix_length_and_dec()
case INTERVAL_QUARTER: set_date_length(2); break; // 1..4
case INTERVAL_MONTH: set_date_length(2); break; // MM
case INTERVAL_WEEK: set_date_length(2); break; // 0..52
- case INTERVAL_DAY: set_date_length(2); break; // DD
+ case INTERVAL_DAY: set_day_length(2); break; // DD
case INTERVAL_DAY_HOUR: set_time_length(4); break; // DDhh
case INTERVAL_DAY_MINUTE: set_time_length(6); break; // DDhhmm
case INTERVAL_DAY_SECOND: set_time_length(8); break; // DDhhmmss
@@ -2295,69 +2119,45 @@ bool Item_extract::fix_length_and_dec()
}
-longlong Item_extract::val_int()
+uint Extract_source::week(THD *thd) const
{
- DBUG_ASSERT(fixed == 1);
- MYSQL_TIME ltime;
+ DBUG_ASSERT(is_valid_extract_source());
uint year;
- ulong week_format;
- long neg;
- int is_time_flag = date_value ? 0 : TIME_TIME_ONLY;
-
- // Not using get_arg0_date to avoid automatic TIME to DATETIME conversion
- if ((null_value= args[0]->get_date(&ltime, is_time_flag)))
- return 0;
-
- neg= ltime.neg ? -1 : 1;
+ ulong week_format= current_thd->variables.default_week_format;
+ return calc_week(this, week_mode(week_format), &year);
+}
- DBUG_ASSERT(ltime.time_type != MYSQL_TIMESTAMP_TIME || ltime.day == 0);
- if (ltime.time_type == MYSQL_TIMESTAMP_TIME)
- time_to_daytime_interval(&ltime);
+longlong Item_extract::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ Extract_source dt(current_thd, args[0], m_date_mode);
+ if ((null_value= !dt.is_valid_extract_source()))
+ return 0;
switch (int_type) {
- case INTERVAL_YEAR: return ltime.year;
- case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month;
- case INTERVAL_QUARTER: return (ltime.month+2)/3;
- case INTERVAL_MONTH: return ltime.month;
- case INTERVAL_WEEK:
- {
- week_format= current_thd->variables.default_week_format;
- return calc_week(&ltime, week_mode(week_format), &year);
- }
- case INTERVAL_DAY: return ltime.day;
- case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
- case INTERVAL_DAY_MINUTE: return (long) (ltime.day*10000L+
- ltime.hour*100L+
- ltime.minute)*neg;
- case INTERVAL_DAY_SECOND: return ((longlong) ltime.day*1000000L+
- (longlong) (ltime.hour*10000L+
- ltime.minute*100+
- ltime.second))*neg;
- case INTERVAL_HOUR: return (long) ltime.hour*neg;
- case INTERVAL_HOUR_MINUTE: return (long) (ltime.hour*100+ltime.minute)*neg;
- case INTERVAL_HOUR_SECOND: return (long) (ltime.hour*10000+ltime.minute*100+
- ltime.second)*neg;
- case INTERVAL_MINUTE: return (long) ltime.minute*neg;
- case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg;
- case INTERVAL_SECOND: return (long) ltime.second*neg;
- case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg;
- case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L +
- (longlong)ltime.hour*10000L +
- ltime.minute*100 +
- ltime.second)*1000000L +
- ltime.second_part)*neg;
- case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L +
- ltime.minute*100 +
- ltime.second)*1000000L +
- ltime.second_part)*neg;
- case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+
- ltime.second))*1000000L+
- ltime.second_part)*neg;
- case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+
- ltime.second_part)*neg;
+ case INTERVAL_YEAR: return dt.year();
+ case INTERVAL_YEAR_MONTH: return dt.year_month();
+ case INTERVAL_QUARTER: return dt.quarter();
+ case INTERVAL_MONTH: return dt.month();
+ case INTERVAL_WEEK: return dt.week(current_thd);
+ case INTERVAL_DAY: return dt.day();
+ case INTERVAL_DAY_HOUR: return dt.day_hour();
+ case INTERVAL_DAY_MINUTE: return dt.day_minute();
+ case INTERVAL_DAY_SECOND: return dt.day_second();
+ case INTERVAL_HOUR: return dt.hour();
+ case INTERVAL_HOUR_MINUTE: return dt.hour_minute();
+ case INTERVAL_HOUR_SECOND: return dt.hour_second();
+ case INTERVAL_MINUTE: return dt.minute();
+ case INTERVAL_MINUTE_SECOND: return dt.minute_second();
+ case INTERVAL_SECOND: return dt.second();
+ case INTERVAL_MICROSECOND: return dt.microsecond();
+ case INTERVAL_DAY_MICROSECOND: return dt.day_microsecond();
+ case INTERVAL_HOUR_MICROSECOND: return dt.hour_microsecond();
+ case INTERVAL_MINUTE_MICROSECOND: return dt.minute_microsecond();
+ case INTERVAL_SECOND_MICROSECOND: return dt.second_microsecond();
case INTERVAL_LAST: DBUG_ASSERT(0); break; /* purecov: deadcode */
}
- return 0; // Impossible
+ return 0; // Impossible
}
bool Item_extract::eq(const Item *item, bool binary_cmp) const
@@ -2396,13 +2196,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('(');
@@ -2615,45 +2416,28 @@ void Item_char_typecast::fix_length_and_dec_internal(CHARSET_INFO *from_cs)
}
-bool Item_time_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_time_typecast::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- Time tm(args[0], Time::Options_for_cast());
- if ((null_value= !tm.is_valid_time()))
- return true;
- tm.copy_to_mysql_time(ltime);
- if (decimals < TIME_SECOND_PART_DIGITS)
- my_time_trunc(ltime, decimals);
- return (fuzzy_date & TIME_TIME_ONLY) ? 0 :
- (null_value= check_date_with_warn(ltime, fuzzy_date,
- MYSQL_TIMESTAMP_ERROR));
+ Time *tm= new(ltime) Time(thd, args[0], Time::Options_for_cast(),
+ MY_MIN(decimals, TIME_SECOND_PART_DIGITS));
+ return (null_value= !tm->is_valid_time());
}
-bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_date_typecast::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
- return 1;
-
- if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE))
- return (null_value= 1);
-
- return 0;
+ date_mode_t tmp= (fuzzydate | sql_mode_for_dates(thd)) & ~TIME_TIME_ONLY;
+ Date *d= new(ltime) Date(thd, args[0], tmp);
+ return (null_value= !d->is_valid_date());
}
-bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_datetime_typecast::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- fuzzy_date |= sql_mode_for_dates(current_thd);
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY))
- return 1;
-
- if (decimals < TIME_SECOND_PART_DIGITS)
- my_time_trunc(ltime, decimals);
-
- DBUG_ASSERT(ltime->time_type != MYSQL_TIMESTAMP_TIME);
- ltime->time_type= MYSQL_TIMESTAMP_DATETIME;
- return 0;
+ date_mode_t tmp= (fuzzydate | sql_mode_for_dates(thd)) & ~TIME_TIME_ONLY;
+ Datetime *dt= new(ltime) Datetime(thd, args[0], tmp,
+ MY_MIN(decimals, TIME_SECOND_PART_DIGITS));
+ return (null_value= !dt->is_valid_datetime());
}
@@ -2668,20 +2452,17 @@ bool Item_datetime_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
0099-12-31
*/
-bool Item_func_makedate::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_makedate::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
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;
@@ -2720,101 +2501,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);
- }
- 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);
- }
- 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);
+ set_func_handler(sign > 0 ? &func_handler_add_time_time_add :
+ &func_handler_add_time_time_sub);
}
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);
+ set_func_handler(sign > 0 ? &func_handler_add_time_string_add :
+ &func_handler_add_time_string_sub);
}
- 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);
}
@@ -2826,7 +2530,7 @@ bool Item_func_add_time::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
Result: Time value
*/
-bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_timediff::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
int l_sign= 1;
@@ -2834,22 +2538,22 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
ErrConvTime str(&l_time3);
/* the following may be true in, for example, date_add(timediff(...), ... */
- if (fuzzy_date & TIME_NO_ZERO_IN_DATE)
+ if (fuzzydate & TIME_NO_ZERO_IN_DATE)
return (null_value= 1);
- if (args[0]->get_time(&l_time1) ||
- args[1]->get_time(&l_time2) ||
+ if (args[0]->get_time(thd, &l_time1) ||
+ args[1]->get_time(thd, &l_time2) ||
l_time1.time_type != l_time2.time_type)
return (null_value= 1);
if (l_time1.neg != l_time2.neg)
l_sign= -l_sign;
- if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzy_date))
+ if (calc_time_diff(&l_time1, &l_time2, l_sign, &l_time3, fuzzydate))
return (null_value= 1);
*ltime= l_time3;
- return (null_value= adjust_time_range_with_warn(ltime, decimals));
+ return (null_value= adjust_time_range_with_warn(thd, ltime, decimals));
}
/**
@@ -2858,17 +2562,16 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
Result: Time value
*/
-bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_maketime::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
Longlong_hybrid hour(args[0]->val_int(), args[0]->unsigned_flag);
longlong minute= args[1]->val_int();
- ulonglong second;
- ulong microsecond;
- bool neg= args[2]->get_seconds(&second, &microsecond);
+ VSec6 sec(thd, 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));
@@ -2879,8 +2582,8 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
ltime->hour= (uint) hour.abs();
ltime->minute= (uint) minute;
- ltime->second= (uint) second;
- ltime->second_part= microsecond;
+ ltime->second= (uint) sec.sec();
+ ltime->second_part= sec.usec();
}
else
{
@@ -2890,10 +2593,10 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
check_time_range(ltime, decimals, &unused);
char buf[28];
char *ptr= longlong10_to_str(hour.value(), buf, hour.is_unsigned() ? 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);
+ thd->push_warning_truncated_wrong_value("time", err.ptr());
}
return (null_value= 0);
@@ -2911,7 +2614,7 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
longlong Item_func_microsecond::val_int()
{
DBUG_ASSERT(fixed == 1);
- Time tm(args[0], Time::Options_for_cast());
+ Time tm(current_thd, args[0], Time::Options_for_cast());
return ((null_value= !tm.is_valid_time())) ?
0 : tm.get_mysql_time()->second_part;
}
@@ -2920,12 +2623,12 @@ 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;
- ulonglong fuzzydate= TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE;
+ date_mode_t fuzzydate= TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE;
null_value= 0;
@@ -3000,21 +2703,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;
}
@@ -3144,15 +2847,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";
@@ -3179,21 +2877,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;
}
@@ -3213,56 +2911,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(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
+ 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);
@@ -3271,29 +2940,19 @@ 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",
- fuzzy_date | sql_mode_for_dates(current_thd)))
+ if (extract_date_time(thd, &date_time_format, val->ptr(), val->length(),
+ ltime, tstype, 0, "datetime",
+ fuzzydate | sql_mode_for_dates(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);
}
-bool Item_func_last_day::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
+bool Item_func_last_day::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY) ||
- (ltime->month == 0))
- return (null_value=1);
+ Date *d= new(ltime) Date(thd, args[0], fuzzydate & ~TIME_TIME_ONLY);
+ if ((null_value= (!d->is_valid_date() || ltime->month == 0)))
+ return true;
uint month_idx= ltime->month-1;
ltime->day= days_in_month[month_idx];
if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366)
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 7aacdec85e0..de5ba8df2fe 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -25,13 +25,9 @@
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);
+bool get_interval_value(THD *thd, Item *args,
+ interval_type int_type, INTERVAL *interval);
class Item_long_func_date_field: public Item_long_func
@@ -186,9 +182,9 @@ public:
str->set(nr, collation.collation);
return str;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return get_date_from_int(ltime, fuzzydate);
+ return get_date_from_int(thd, ltime, fuzzydate);
}
const char *func_name() const { return "month"; }
const Type_handler *type_handler() const { return &type_handler_long; }
@@ -459,9 +455,9 @@ public:
{
return (odbc_type ? "dayofweek" : "weekday");
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
const Type_handler *type_handler() const { return &type_handler_long; }
bool fix_length_and_dec()
@@ -516,7 +512,7 @@ public:
}
double real_op() { DBUG_ASSERT(0); return 0; }
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
- bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(0);
return true;
@@ -552,7 +548,8 @@ public:
}
bool fix_length_and_dec()
{
- fix_length_and_dec_generic(arg_count ? args[0]->datetime_precision() : 0);
+ fix_length_and_dec_generic(arg_count ?
+ args[0]->datetime_precision(current_thd) : 0);
return FALSE;
}
longlong int_op();
@@ -576,7 +573,7 @@ public:
}
bool fix_length_and_dec()
{
- fix_length_and_dec_generic(args[0]->time_precision());
+ fix_length_and_dec_generic(args[0]->time_precision(current_thd));
return FALSE;
}
longlong int_op();
@@ -586,66 +583,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 +603,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); }
};
@@ -689,7 +645,7 @@ public:
{ decimals= dec; }
bool fix_fields(THD *, Item **);
bool fix_length_and_dec() { fix_attributes_time(decimals); return FALSE; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
/*
Abstract method that defines which time zone is used for conversion.
Converts time current time in my_time_t representation to broken-down
@@ -734,7 +690,7 @@ class Item_func_curdate :public Item_datefunc
MYSQL_TIME ltime;
public:
Item_func_curdate(THD *thd): Item_datefunc(thd), last_query_id(0) {}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg)
{
@@ -777,7 +733,7 @@ public:
bool fix_fields(THD *, Item **);
bool fix_length_and_dec()
{ fix_attributes_datetime(decimals); return FALSE;}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0;
bool check_vcol_func_processor(void *arg)
{
@@ -832,7 +788,7 @@ public:
bool const_item() const { return 0; }
const char *func_name() const { return "sysdate"; }
void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time);
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
table_map used_tables() const { return RAND_TABLE_BIT; }
bool check_vcol_func_processor(void *arg)
{
@@ -852,7 +808,7 @@ class Item_func_from_days :public Item_datefunc
public:
Item_func_from_days(THD *thd, Item *a): Item_datefunc(thd, a) {}
const char *func_name() const { return "from_days"; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
bool check_partition_func_processor(void *int_arg) {return FALSE;}
bool check_vcol_func_processor(void *arg) { return FALSE;}
bool check_valid_arguments_processor(void *int_arg)
@@ -917,7 +873,7 @@ class Item_func_from_unixtime :public Item_datetimefunc
Item_func_from_unixtime(THD *thd, Item *a): Item_datetimefunc(thd, a) {}
const char *func_name() const { return "from_unixtime"; }
bool fix_length_and_dec();
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_from_unixtime>(thd, this); }
};
@@ -958,11 +914,11 @@ class Item_func_convert_tz :public Item_datetimefunc
const char *func_name() const { return "convert_tz"; }
bool fix_length_and_dec()
{
- fix_attributes_datetime(args[0]->datetime_precision());
+ fix_attributes_datetime(args[0]->datetime_precision(current_thd));
maybe_null= true;
return FALSE;
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
void cleanup();
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_convert_tz>(thd, this); }
@@ -975,7 +931,7 @@ class Item_func_sec_to_time :public Item_timefunc
{ return args[0]->check_type_can_return_decimal(func_name()); }
public:
Item_func_sec_to_time(THD *thd, Item *item): Item_timefunc(thd, item) {}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
fix_attributes_time(args[0]->decimals);
@@ -988,18 +944,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; }
@@ -1009,9 +964,17 @@ public:
};
-class Item_extract :public Item_int_func
+class Item_extract :public Item_int_func,
+ public Type_handler_hybrid_field_type
{
- bool date_value;
+ date_mode_t m_date_mode;
+ const Type_handler_int_result *handler_by_length(uint32 length,
+ uint32 threashold)
+ {
+ if (length >= threashold)
+ return &type_handler_longlong;
+ return &type_handler_long;
+ }
void set_date_length(uint32 length)
{
/*
@@ -1020,48 +983,34 @@ class Item_extract :public Item_int_func
because all around the code we assume that max_length is sign inclusive.
Another options is to set unsigned_flag to "true".
*/
- max_length= length; //QQ: see above
- date_value= true;
+ set_handler(handler_by_length(max_length= length, 10)); // QQ: see above
+ m_date_mode= date_mode_t(0);
+ }
+ void set_day_length(uint32 length)
+ {
+ /*
+ Units starting with DAY can be negative:
+ EXTRACT(DAY FROM '-24:00:00') -> -1
+ */
+ set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
+ m_date_mode= date_mode_t(0);
}
void set_time_length(uint32 length)
{
- max_length= length + 1/*sign*/;
- date_value= false;
+ set_handler(handler_by_length(max_length= length + 1/*sign*/, 11));
+ m_date_mode= TIME_TIME_ONLY;
}
public:
const interval_type int_type; // keep it public
Item_extract(THD *thd, interval_type type_arg, Item *a):
- Item_int_func(thd, a), int_type(type_arg) {}
+ Item_int_func(thd, a),
+ Type_handler_hybrid_field_type(&type_handler_longlong),
+ m_date_mode(date_mode_t(0)),
+ int_type(type_arg)
+ { }
const Type_handler *type_handler() const
{
- switch (int_type) {
- case INTERVAL_YEAR:
- case INTERVAL_YEAR_MONTH:
- case INTERVAL_QUARTER:
- case INTERVAL_MONTH:
- case INTERVAL_WEEK:
- case INTERVAL_DAY:
- case INTERVAL_DAY_HOUR:
- case INTERVAL_DAY_MINUTE:
- case INTERVAL_DAY_SECOND:
- case INTERVAL_HOUR:
- case INTERVAL_HOUR_MINUTE:
- case INTERVAL_HOUR_SECOND:
- case INTERVAL_MINUTE:
- case INTERVAL_MINUTE_SECOND:
- case INTERVAL_SECOND:
- case INTERVAL_MICROSECOND:
- case INTERVAL_SECOND_MICROSECOND:
- return &type_handler_long;
- case INTERVAL_DAY_MICROSECOND:
- case INTERVAL_HOUR_MICROSECOND:
- case INTERVAL_MINUTE_MICROSECOND:
- return &type_handler_longlong;
- case INTERVAL_LAST:
- break;
- }
- DBUG_ASSERT(0);
- return &type_handler_longlong;
+ return Type_handler_hybrid_field_type::type_handler();
}
longlong val_int();
enum Functype functype() const { return EXTRACT_FUNC; }
@@ -1157,22 +1106,16 @@ public:
};
-class Item_temporal_typecast: public Item_temporal_func
+class Item_date_typecast :public Item_datefunc
{
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
-{
-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"; }
- 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; }
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this);
@@ -1182,15 +1125,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"; }
- 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; }
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->
@@ -1201,15 +1146,17 @@ 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; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ void print(String *str, enum_query_type query_type)
+ {
+ print_cast_temporal(str, query_type);
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool fix_length_and_dec()
{
return args[0]->type_handler()->
@@ -1228,31 +1175,73 @@ public:
Item_func_makedate(THD *thd, Item *a, Item *b):
Item_datefunc(thd, a, b) {}
const char *func_name() const { return "makedate"; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_makedate>(thd, this); }
};
-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()
+ {
+ THD *thd= current_thd;
+ uint dec0= args[0]->datetime_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, args[1]);
+ fix_attributes_datetime(MY_MAX(dec0, dec1));
+ maybe_null= true;
+ return false;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return is_date ? "timestamp" : sign > 0 ? "addtime" : "subtime";
+ Datetime dt(thd, args[0], date_mode_t(0));
+ if (!dt.is_valid_datetime())
+ return null_value= true;
+ Interval_DDhhmmssff it(thd, args[1]);
+ if (!it.is_valid_interval_DDhhmmssff())
+ return null_value= true;
+ return (null_value= Sec6_add(dt.get_mysql_time(), it.get_mysql_time(), 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
@@ -1262,12 +1251,14 @@ public:
const char *func_name() const { return "timediff"; }
bool fix_length_and_dec()
{
- uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision());
+ THD *thd= current_thd;
+ uint dec= MY_MAX(args[0]->time_precision(thd),
+ args[1]->time_precision(thd));
fix_attributes_time(dec);
maybe_null= true;
return FALSE;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_timediff>(thd, this); }
};
@@ -1290,7 +1281,7 @@ public:
return FALSE;
}
const char *func_name() const { return "maketime"; }
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_maketime>(thd, this); }
};
@@ -1369,19 +1360,19 @@ 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(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate,
+ timestamp_type);
const char *func_name() const { return "str_to_date"; }
bool fix_length_and_dec();
Item *get_copy(THD *thd)
@@ -1396,9 +1387,358 @@ class Item_func_last_day :public Item_datefunc
public:
Item_func_last_day(THD *thd, Item *a): Item_datefunc(thd, a) {}
const char *func_name() const { return "last_day"; }
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ 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(THD *thd, Item *item, interval_type type, bool sub, MYSQL_TIME *to) const
+ {
+ INTERVAL interval;
+ if (get_interval_value(thd, item, type, &interval))
+ return true;
+ if (sub)
+ interval.neg = !interval.neg;
+ return date_add_interval(thd, 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(current_thd),
+ interval_dec(item->arguments()[1], int_type(item)));
+ item->fix_attributes_datetime(dec);
+ return false;
+ }
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ Datetime dt(thd, item->arguments()[0], date_mode_t(0));
+ if (!dt.is_valid_datetime() ||
+ dt.check_date_with_warn(thd, 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(thd, 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ Date d(thd, item->arguments()[0], date_mode_t(0));
+ if (!d.is_valid_date() ||
+ d.check_date_with_warn(thd, 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(thd, 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(current_thd),
+ interval_dec(item->arguments()[1], int_type(item)));
+ item->fix_attributes_time(dec);
+ return false;
+ }
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ Time t(thd, item->arguments()[0]);
+ if (!t.is_valid_time())
+ return (item->null_value= true);
+ t.copy_to_mysql_time(to);
+ return (item->null_value= add(thd, 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(current_thd),
+ 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ if (item->arguments()[0]->get_date(thd, to, date_mode_t(0)) ||
+ (to->time_type != MYSQL_TIMESTAMP_TIME &&
+ check_date_with_warn(thd, to, TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE,
+ MYSQL_TIMESTAMP_ERROR)))
+ return (item->null_value= true);
+ return (item->null_value= add(thd, 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
+ {
+ THD *thd= current_thd;
+ uint dec0= item->arguments()[0]->datetime_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]);
+ item->fix_attributes_datetime(MY_MAX(dec0, dec1));
+ return false;
+ }
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ Datetime dt(thd, item->arguments()[0], date_mode_t(0));
+ if (!dt.is_valid_datetime())
+ return item->null_value= true;
+ Interval_DDhhmmssff it(thd, item->arguments()[1]);
+ if (!it.is_valid_interval_DDhhmmssff())
+ return item->null_value= true;
+ return (item->null_value= (Sec6_add(dt.get_mysql_time(),
+ it.get_mysql_time(), 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
+ {
+ THD *thd= current_thd;
+ uint dec0= item->arguments()[0]->time_precision(thd);
+ uint dec1= Interval_DDhhmmssff::fsp(thd, item->arguments()[1]);
+ item->fix_attributes_time(MY_MAX(dec0, dec1));
+ return false;
+ }
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ Time t(thd, item->arguments()[0]);
+ if (!t.is_valid_time())
+ return item->null_value= true;
+ Interval_DDhhmmssff i(thd, item->arguments()[1]);
+ if (!i.is_valid_interval_DDhhmmssff())
+ return item->null_value= true;
+ return (item->null_value= (Sec6_add(t.get_mysql_time(),
+ i.get_mysql_time(), m_sign).
+ to_time(thd, 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 dec0= item->arguments()[0]->decimals;
+ uint dec1= Interval_DDhhmmssff::fsp(current_thd, item->arguments()[1]);
+ uint dec= MY_MAX(dec0, dec1);
+ 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ DBUG_ASSERT(item->is_fixed());
+ // Detect a proper timestamp type based on the argument values
+ Temporal_hybrid l_time1(thd, item->arguments()[0], TIME_TIME_ONLY);
+ if (!l_time1.is_valid_temporal())
+ return (item->null_value= true);
+ Interval_DDhhmmssff l_time2(thd, item->arguments()[1]);
+ if (!l_time2.is_valid_interval_DDhhmmssff())
+ return (item->null_value= true);
+ Sec6_add add(l_time1.get_mysql_time(), l_time2.get_mysql_time(), m_sign);
+ return (item->null_value= (l_time1.get_mysql_time()->time_type ==
+ MYSQL_TIMESTAMP_TIME ?
+ add.to_time(thd, 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(thd, 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(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATETIME);
+ }
+};
+
+
+class Func_handler_str_to_date_date: public Item_handled_func::Handler_date
+{
+public:
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ return static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(thd, to, fuzzy, MYSQL_TIMESTAMP_DATE);
+ }
+};
+
+
+class Func_handler_str_to_date_time: public Item_handled_func::Handler_time
+{
+public:
+ bool get_date(THD *thd, Item_handled_func *item,
+ MYSQL_TIME *to, date_mode_t fuzzy) const
+ {
+ if (static_cast<Item_func_str_to_date*>(item)->
+ get_date_common(thd, 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_vers.cc b/sql/item_vers.cc
index d7361f687f9..6946ae0e1e5 100644
--- a/sql/item_vers.cc
+++ b/sql/item_vers.cc
@@ -37,9 +37,8 @@ Item_func_trt_ts::Item_func_trt_ts(THD *thd, Item* a, TR_table::field_id_t _trt_
bool
-Item_func_trt_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
+Item_func_trt_ts::get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate)
{
- THD *thd= current_thd; // can it differ from constructor's?
DBUG_ASSERT(thd);
DBUG_ASSERT(args[0]);
if (args[0]->result_type() != INT_RESULT)
@@ -67,7 +66,7 @@ Item_func_trt_ts::get_date(MYSQL_TIME *res, ulonglong fuzzy_date)
return true;
}
- return trt[trt_field]->get_date(res, fuzzy_date);
+ return trt[trt_field]->get_date(res, fuzzydate);
}
@@ -143,7 +142,7 @@ Item_func_trt_id::val_int()
else
{
MYSQL_TIME commit_ts;
- if (args[0]->get_date(&commit_ts, 0))
+ if (args[0]->get_date(current_thd, &commit_ts, date_mode_t(0)))
{
null_value= true;
return 0;
diff --git a/sql/item_vers.h b/sql/item_vers.h
index 8b9c0e6056c..a42b5a033f2 100644
--- a/sql/item_vers.h
+++ b/sql/item_vers.h
@@ -35,7 +35,7 @@ public:
}
return "trt_commit_ts";
}
- bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date);
+ bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_trt_ts>(thd, this); }
bool fix_length_and_dec()
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index 2db396d3065..aa2c7756ab7 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;
@@ -440,12 +439,12 @@ Item_sum_hybrid_simple::val_str(String *str)
return retval;
}
-bool Item_sum_hybrid_simple::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+bool Item_sum_hybrid_simple::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
DBUG_ASSERT(fixed == 1);
if (null_value)
return true;
- bool retval= value->get_date(ltime, fuzzydate);
+ bool retval= value->get_date(thd, ltime, fuzzydate);
if ((null_value= value->null_value))
DBUG_ASSERT(retval == true);
return retval;
@@ -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_windowfunc.h b/sql/item_windowfunc.h
index 9ba60c3956d..4c704808fe4 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -319,7 +319,7 @@ class Item_sum_hybrid_simple : public Item_sum,
my_decimal *val_decimal(my_decimal *);
void reset_field();
String *val_str(String *);
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
void update_field();
@@ -1273,7 +1273,7 @@ public:
return res;
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
bool res;
if (force_return_blank)
@@ -1290,7 +1290,7 @@ public:
}
else
{
- res= window_func()->get_date(ltime, fuzzydate);
+ res= window_func()->get_date(thd, ltime, fuzzydate);
null_value= window_func()->null_value;
}
return res;
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 0fa65a05de3..a56117a4ac1 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 72db2717680..651fb4ce5b1 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2753,9 +2753,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);
@@ -4411,7 +4409,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() &&
@@ -7399,8 +7397,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)
{
@@ -9054,11 +9053,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..f0bb69c60c8 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -29,6 +29,8 @@
#ifndef my_decimal_h
#define my_decimal_h
+#include "sql_basic_types.h"
+
#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY)
#include "sql_string.h" /* String */
#endif
@@ -39,6 +41,7 @@ C_MODE_START
C_MODE_END
class String;
+class Field;
typedef struct st_mysql_time MYSQL_TIME;
/**
@@ -63,6 +66,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 +147,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 +169,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(THD *thd, MYSQL_TIME *to, date_mode_t 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 +244,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 +257,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 +334,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 +345,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 +357,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 6f0f517eade..9ff47dc1ff1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -117,6 +117,10 @@
#include <poll.h>
#endif
+#ifdef _WIN32
+#include <handle_connections_win.h>
+#endif
+
#include <my_service_manager.h>
#define mysqld_charset &my_charset_latin1
@@ -319,23 +323,6 @@ MY_TIMER_INFO sys_timer_info;
/* static variables */
#ifdef HAVE_PSI_INTERFACE
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !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 */
-
-#ifdef __WIN__
-static PSI_thread_key key_thread_handle_shutdown;
-#endif /* __WIN__ */
-
#ifdef HAVE_OPENSSL10
static PSI_rwlock_key key_rwlock_openssl;
#endif
@@ -371,6 +358,7 @@ static char *character_set_filesystem_name;
static char *lc_messages;
static char *lc_time_names_name;
char *my_bind_addr_str;
+int server_socket_ai_family;
static char *default_collation_name;
char *default_storage_engine, *default_tmp_storage_engine;
char *enforced_storage_engine=NULL;
@@ -744,7 +732,6 @@ mysql_mutex_t LOCK_thread_count;
other threads.
It also protects these variables:
- handler_count
in_bootstrap
select_thread_in_use
slave_init_thread_running
@@ -1098,9 +1085,6 @@ PSI_cond_key key_COND_ack_receiver;
static PSI_cond_info all_server_conds[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !defined(EMBEDDED_LIBRARY)
- { &key_COND_handler_count, "COND_handler_count", PSI_FLAG_GLOBAL},
-#endif /* _WIN32 || HAVE_SMEM && !EMBEDDED_LIBRARY */
#ifdef HAVE_MMAP
{ &key_PAGE_cond, "PAGE::cond", 0},
{ &key_COND_active, "TC_LOG_MMAP::COND_active", 0},
@@ -1161,22 +1145,6 @@ PSI_thread_key key_thread_ack_receiver;
static PSI_thread_info all_server_threads[]=
{
-#if (defined(_WIN32) || defined(HAVE_SMEM)) && !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__ */
-
{ &key_thread_bootstrap, "bootstrap", PSI_FLAG_GLOBAL},
{ &key_thread_delayed_insert, "delayed_insert", 0},
{ &key_thread_handle_manager, "manager", PSI_FLAG_GLOBAL},
@@ -1419,10 +1387,10 @@ void Buffered_logs::print()
/** Logs reported before a logger is available. */
static Buffered_logs buffered_logs;
-static MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock;
struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
#ifndef EMBEDDED_LIBRARY
+MYSQL_SOCKET unix_sock, base_ip_sock, extra_ip_sock;
/**
Error reporter that buffer log messages.
@param level log message level
@@ -1478,27 +1446,18 @@ static pthread_t select_thread;
#undef getpid
#include <process.h>
-static mysql_cond_t COND_handler_count;
-static uint handler_count;
static bool start_mode=0, use_opt_args;
static int opt_argc;
static char **opt_argv;
#if !defined(EMBEDDED_LIBRARY)
-static HANDLE hEventShutdown;
+HANDLE hEventShutdown;
static char shutdown_event_name[40];
#include "nt_servc.h"
static NTService Service; ///< Service object for WinNT
#endif /* EMBEDDED_LIBRARY */
#endif /* __WIN__ */
-#ifdef _WIN32
-#include <sddl.h> /* ConvertStringSecurityDescriptorToSecurityDescriptor */
-static char pipe_name[512];
-static SECURITY_ATTRIBUTES saPipeSecurity;
-static HANDLE hPipe = INVALID_HANDLE_VALUE;
-#endif
-
#ifndef EMBEDDED_LIBRARY
bool mysqld_embedded=0;
#else
@@ -1519,11 +1478,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,
@@ -1575,19 +1530,13 @@ extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *);
static int init_thread_environment();
static char *get_relative_path(const char *path);
static int fix_paths(void);
+#ifndef _WIN32
void handle_connections_sockets();
-#ifdef _WIN32
-pthread_handler_t handle_connections_sockets_thread(void *arg);
#endif
+
pthread_handler_t kill_server_thread(void *arg);
static void bootstrap(MYSQL_FILE *file);
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);
@@ -1622,6 +1571,7 @@ static void close_connections(void)
kill_cached_threads++;
flush_thread_cache();
+
/* kill connection thread */
#if !defined(__WIN__)
DBUG_PRINT("quit", ("waiting for select thread: %lu",
@@ -1671,30 +1621,7 @@ static void close_connections(void)
extra_ip_sock= MYSQL_INVALID_SOCKET;
}
}
-#ifdef _WIN32
- if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
- {
- HANDLE temp;
- DBUG_PRINT("quit", ("Closing named pipes") );
-
- /* Create connection to the handle named pipe handler to break the loop */
- if ((temp = CreateFile(pipe_name,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL )) != INVALID_HANDLE_VALUE)
- {
- WaitNamedPipe(pipe_name, 1000);
- DWORD dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
- SetNamedPipeHandleState(temp, &dwMode, NULL, NULL);
- CancelIo(temp);
- DisconnectNamedPipe(temp);
- CloseHandle(temp);
- }
- }
-#endif
+
#ifdef HAVE_SYS_UN_H
if (mysql_socket_getfd(unix_sock) != INVALID_SOCKET)
{
@@ -1941,12 +1868,6 @@ void kill_mysql(THD *thd)
{
DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError()));
}
- /*
- or:
- HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
- SetEvent(hEventShutdown);
- CloseHandle(hEvent);
- */
}
#endif
#elif defined(HAVE_PTHREAD_KILL)
@@ -1978,7 +1899,7 @@ void kill_mysql(THD *thd)
/**
Force server down. Kill all connections and threads and exit.
- @param sig_ptr Signal number that caused kill_server to be called.
+ @param sig Signal number that caused kill_server to be called.
@note
A signal number of 0 mean that the function was not called
@@ -1986,22 +1907,14 @@ void kill_mysql(THD *thd)
or stop, we just want to kill the server.
*/
-#if !defined(__WIN__)
-static void *kill_server(void *sig_ptr)
-#define RETURN_FROM_KILL_SERVER return 0
-#else
-static void __cdecl kill_server(int sig_ptr)
-#define RETURN_FROM_KILL_SERVER return
-#endif
+static void kill_server(int sig)
{
DBUG_ENTER("kill_server");
#ifndef EMBEDDED_LIBRARY
- int sig=(int) (long) sig_ptr; // This is passed a int
// if there is a signal during the kill in progress, ignore the other
if (kill_in_progress) // Safety
{
- DBUG_LEAVE;
- RETURN_FROM_KILL_SERVER;
+ DBUG_VOID_RETURN;
}
kill_in_progress=TRUE;
abort_loop=1; // This should be set
@@ -2018,21 +1931,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)
{
@@ -2050,20 +1948,9 @@ static void __cdecl kill_server(int sig_ptr)
else
unireg_end();
- /* purecov: begin deadcode */
- DBUG_LEAVE; // Must match DBUG_ENTER()
- my_thread_end();
- pthread_exit(0);
- /* purecov: end */
-
- RETURN_FROM_KILL_SERVER; // Avoid compiler warnings
-
-#else /* EMBEDDED_LIBRARY*/
-
- DBUG_LEAVE;
- RETURN_FROM_KILL_SERVER;
+#endif /* EMBEDDED_LIBRARY*/
-#endif /* EMBEDDED_LIBRARY */
+ DBUG_VOID_RETURN;
}
@@ -2072,11 +1959,9 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
kill_server(0);
- /* purecov: begin deadcode */
my_thread_end();
pthread_exit(0);
return 0;
- /* purecov: end */
}
#endif
@@ -2122,13 +2007,7 @@ static void clean_up_error_log_mutex()
void unireg_end(void)
{
clean_up(1);
- my_thread_end();
sd_notify(0, "STATUS=MariaDB server is down");
-#if defined(SIGNALS_DONT_BREAK_READ)
- exit(0);
-#else
- pthread_exit(0); // Exit is in main thread
-#endif
}
@@ -2623,6 +2502,7 @@ static MYSQL_SOCKET activate_tcp_port(uint port)
}
else
{
+ server_socket_ai_family= a->ai_family;
sql_print_information("Server socket created on IP: '%s'.",
(const char *) ip_addr);
break;
@@ -2749,53 +2629,16 @@ static void network_init(void)
extra_ip_sock= activate_tcp_port(mysqld_extra_port);
}
-#ifdef _WIN32
- /* create named pipe */
- if (mysqld_unix_port[0] && !opt_bootstrap &&
- opt_enable_named_pipe)
- {
-
- strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
- mysqld_unix_port, NullS);
- /*
- Create a security descriptor for pipe.
- - Use low integrity level, so that it is possible to connect
- from any process.
- - Give Everyone read/write access to pipe.
- */
- if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
- "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)",
- SDDL_REVISION_1, &saPipeSecurity.lpSecurityDescriptor, NULL))
- {
- sql_perror("Can't start server : Initialize security descriptor");
- unireg_abort(1);
- }
- saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
- saPipeSecurity.bInheritHandle = FALSE;
- if ((hPipe= CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) == INVALID_HANDLE_VALUE)
- {
- sql_perror("Create named pipe failed");
- unireg_abort(1);
- }
- }
-#endif
-
#if defined(HAVE_SYS_UN_H)
/*
** Create the UNIX socket
*/
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);
@@ -2813,14 +2656,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);
@@ -3588,7 +3443,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
sql_print_error("Can't create thread to kill server (errno= %d)",
error);
#else
- kill_server((void*) sig); // MIT THREAD has a alarm thread
+ kill_server(sig); // MIT THREAD has a alarm thread
#endif
}
break;
@@ -3650,7 +3505,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");
@@ -3659,13 +3514,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;
@@ -3678,7 +3535,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);
}
@@ -3688,7 +3545,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;
}
@@ -3702,23 +3559,6 @@ void *my_str_malloc_mysqld(size_t size)
}
-#ifdef __WIN__
-
-pthread_handler_t handle_shutdown(void *arg)
-{
- MSG msg;
- my_thread_init();
-
- /* this call should create the message queue for this thread */
- PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
-#if !defined(EMBEDDED_LIBRARY)
- if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
-#endif /* EMBEDDED_LIBRARY */
- kill_server(MYSQL_KILL_SIGNAL);
- return 0;
-}
-#endif
-
#include <mysqld_default_groups.h>
#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
@@ -5623,100 +5463,17 @@ static int init_server_components()
#ifndef EMBEDDED_LIBRARY
-
-static void create_shutdown_thread()
+#ifdef _WIN32
+static void create_shutdown_event()
{
-#ifdef __WIN__
hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
- pthread_t hThread;
- int error;
- if (unlikely((error= mysql_thread_create(key_thread_handle_shutdown,
- &hThread, &connection_attrib,
- handle_shutdown, 0))))
- sql_print_warning("Can't create thread to handle shutdown requests"
- " (errno= %d)", error);
-
// On "Stop Service" we have to do regular shutdown
Service.SetShutdownEvent(hEventShutdown);
-#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)
- {
- sql_print_error("TCP/IP, --shared-memory, or --named-pipe should be configured on NT OS");
- unireg_abort(1); // Will not return
- }
-
- mysql_mutex_lock(&LOCK_start_thread);
- mysql_cond_init(key_COND_handler_count, &COND_handler_count, NULL);
- handler_count=0;
- if (hPipe != INVALID_HANDLE_VALUE)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_namedpipes,
- &hThread, &connection_attrib,
- handle_connections_namedpipes, 0)))
- {
- sql_print_warning("Can't create thread to handle named pipes"
- " (errno= %d)", error);
- handler_count--;
- }
- }
- if (have_tcpip && !opt_disable_networking)
- {
- handler_count++;
- if ((error= mysql_thread_create(key_thread_handle_con_sockets,
- &hThread, &connection_attrib,
- handle_connections_sockets_thread, 0)))
- {
- sql_print_warning("Can't create thread to handle TCP/IP",
- " (errno= %d)", error);
- 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--;
- }
- }
+#else /*_WIN32*/
+#define create_shutdown_event()
#endif
-
- while (handler_count > 0)
- mysql_cond_wait(&COND_handler_count, &LOCK_start_thread);
- mysql_mutex_unlock(&LOCK_start_thread);
- DBUG_VOID_RETURN;
-}
-
-void decrement_handler_count()
-{
- mysql_mutex_lock(&LOCK_start_thread);
- if (--handler_count == 0)
- mysql_cond_signal(&COND_handler_count);
- mysql_mutex_unlock(&LOCK_start_thread);
- my_thread_end();
-}
-#else
-#define decrement_handler_count()
-#endif /* defined(_WIN32) || defined(HAVE_SMEM) */
-
+#endif /* EMBEDDED_LIBRARY */
#ifndef EMBEDDED_LIBRARY
@@ -6119,7 +5876,7 @@ int mysqld_main(int argc, char **argv)
}
}
- create_shutdown_thread();
+ create_shutdown_event();
start_handle_manager();
/* Copy default global rpl_filter to global_rpl_filter */
@@ -6188,11 +5945,12 @@ 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)
- handle_connections_methods();
+#ifdef _WIN32
+ handle_connections_win();
+ kill_server(0);
#else
handle_connections_sockets();
-#endif /* _WIN32 || HAVE_SMEM */
+#endif /* _WIN32 */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -6601,7 +6359,7 @@ void create_thread_to_handle_connection(CONNECT *connect)
@param[in,out] thd Thread handle of future thread.
*/
-static void create_new_thread(CONNECT *connect)
+void create_new_thread(CONNECT *connect)
{
DBUG_ENTER("create_new_thread");
@@ -6669,18 +6427,107 @@ inline void kill_broken_server()
#ifndef EMBEDDED_LIBRARY
+void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
+{
+ CONNECT *connect;
+ bool is_unix_sock;
+
+#ifdef FD_CLOEXEC
+ (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
+#endif
+
+#ifdef HAVE_LIBWRAP
+ {
+ if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
+ mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+ {
+ struct request_info req;
+ signal(SIGCHLD, SIG_DFL);
+ request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE,
+ mysql_socket_getfd(new_sock), NULL);
+ my_fromhost(&req);
+ if (!my_hosts_access(&req))
+ {
+ /*
+ This may be stupid but refuse() includes an exit(0)
+ which we surely don't want...
+ clean_exit() - same stupid thing ...
+ */
+ syslog(deny_severity, "refused connect from %s",
+ my_eval_client(&req));
+
+ /*
+ C++ sucks (the gibberish in front just translates the supplied
+ sink function pointer in the req structure from a void (*sink)();
+ to a void(*sink)(int) if you omit the cast, the C++ compiler
+ will cry...
+ */
+ if (req.sink)
+ ((void(*)(int))req.sink)(req.fd);
+
+ (void)mysql_socket_shutdown(new_sock, SHUT_RDWR);
+ (void)mysql_socket_close(new_sock);
+ /*
+ The connection was refused by TCP wrappers.
+ There are no details (by client IP) available to update the
+ host_cache.
+ */
+ statistic_increment(connection_errors_tcpwrap, &LOCK_status);
+ return;
+ }
+ }
+ }
+#endif /* HAVE_LIBWRAP */
+
+ DBUG_PRINT("info", ("Creating CONNECT for new connection"));
+
+ if ((connect= new CONNECT()))
+ {
+ is_unix_sock= (mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(unix_sock));
+
+ if (!(connect->vio=
+ mysql_socket_vio_new(new_sock,
+ is_unix_sock ? VIO_TYPE_SOCKET :
+ VIO_TYPE_TCPIP,
+ is_unix_sock ? VIO_LOCALHOST : 0)))
+ {
+ delete connect;
+ connect= 0; // Error handling below
+ }
+ }
+
+ if (!connect)
+ {
+ /* Connect failure */
+ (void)mysql_socket_close(new_sock);
+ statistic_increment(aborted_connects, &LOCK_status);
+ statistic_increment(connection_errors_internal, &LOCK_status);
+ return;
+ }
+
+ if (is_unix_sock)
+ connect->host= my_localhost;
+
+ if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+ {
+ connect->extra_port= 1;
+ connect->scheduler= extra_thread_scheduler;
+ }
+ create_new_thread(connect);
+}
+
+#ifndef _WIN32
void handle_connections_sockets()
{
MYSQL_SOCKET sock= mysql_socket_invalid();
MYSQL_SOCKET new_sock= mysql_socket_invalid();
uint error_count=0;
- CONNECT *connect;
struct sockaddr_storage cAddr;
int ip_flags __attribute__((unused))=0;
int socket_flags __attribute__((unused))= 0;
int extra_ip_flags __attribute__((unused))=0;
int flags=0,retval;
- bool is_unix_sock;
#ifdef HAVE_POLL
int socket_count= 0;
struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock
@@ -6812,10 +6659,7 @@ void handle_connections_sockets()
}
#endif
}
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
-#endif
+
if (mysql_socket_getfd(new_sock) == INVALID_SOCKET)
{
/*
@@ -6831,443 +6675,18 @@ void handle_connections_sockets()
sleep(1); // Give other threads some time
continue;
}
-#ifdef FD_CLOEXEC
- (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
#endif
-
-#ifdef HAVE_LIBWRAP
- {
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
- mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
- {
- struct request_info req;
- signal(SIGCHLD, SIG_DFL);
- request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE,
- mysql_socket_getfd(new_sock), NULL);
- my_fromhost(&req);
- if (!my_hosts_access(&req))
- {
- /*
- This may be stupid but refuse() includes an exit(0)
- which we surely don't want...
- clean_exit() - same stupid thing ...
- */
- syslog(deny_severity, "refused connect from %s",
- my_eval_client(&req));
-
- /*
- C++ sucks (the gibberish in front just translates the supplied
- sink function pointer in the req structure from a void (*sink)();
- to a void(*sink)(int) if you omit the cast, the C++ compiler
- will cry...
- */
- if (req.sink)
- ((void (*)(int))req.sink)(req.fd);
-
- (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
- (void) mysql_socket_close(new_sock);
- /*
- The connection was refused by TCP wrappers.
- There are no details (by client IP) available to update the
- host_cache.
- */
- statistic_increment(connection_errors_tcpwrap, &LOCK_status);
- continue;
- }
- }
- }
-#endif /* HAVE_LIBWRAP */
-
- DBUG_PRINT("info", ("Creating CONNECT for new connection"));
-
- if ((connect= new CONNECT()))
- {
- is_unix_sock= (mysql_socket_getfd(sock) ==
- mysql_socket_getfd(unix_sock));
-
- if (!(connect->vio=
- mysql_socket_vio_new(new_sock,
- is_unix_sock ? VIO_TYPE_SOCKET :
- VIO_TYPE_TCPIP,
- is_unix_sock ? VIO_LOCALHOST: 0)))
- {
- delete connect;
- connect= 0; // Error handling below
- }
- }
-
- if (!connect)
- {
- /* Connect failure */
- (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
- (void) mysql_socket_close(new_sock);
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- continue;
- }
-
- if (is_unix_sock)
- connect->host= my_localhost;
-
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
- {
- connect->extra_port= 1;
- connect->scheduler= extra_thread_scheduler;
- }
- create_new_thread(connect);
+ handle_accepted_socket(new_sock, sock);
}
sd_notify(0, "STOPPING=1\n"
"STATUS=Shutdown in progress\n");
DBUG_VOID_RETURN;
}
-
-#ifdef _WIN32
-pthread_handler_t handle_connections_sockets_thread(void *arg)
-{
- my_thread_init();
- handle_connections_sockets();
- decrement_handler_count();
- return 0;
-}
-
-pthread_handler_t handle_connections_namedpipes(void *arg)
-{
- HANDLE hConnectedPipe;
- OVERLAPPED connectOverlapped= {0};
- my_thread_init();
- DBUG_ENTER("handle_connections_namedpipes");
- connectOverlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!connectOverlapped.hEvent)
- {
- sql_print_error("Can't create event, last error=%u", GetLastError());
- unireg_abort(1);
- }
- DBUG_PRINT("general",("Waiting for named pipe connections."));
- while (!abort_loop)
- {
- /* wait for named pipe connection */
- BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped);
- if (!fConnected && (GetLastError() == ERROR_IO_PENDING))
- {
- /*
- ERROR_IO_PENDING says async IO has started but not yet finished.
- GetOverlappedResult will wait for completion.
- */
- DWORD bytes;
- fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE);
- }
- if (abort_loop)
- break;
- if (!fConnected)
- fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
- if (!fConnected)
- {
- CloseHandle(hPipe);
- if ((hPipe= CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.
- net_buffer_length,
- (int) global_system_variables.
- net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) ==
- INVALID_HANDLE_VALUE)
- {
- sql_perror("Can't create new named pipe!");
- break; // Abort
- }
- }
- hConnectedPipe = hPipe;
- /* create new pipe for new connection */
- if ((hPipe = CreateNamedPipe(pipe_name,
- PIPE_ACCESS_DUPLEX |
- FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE |
- PIPE_READMODE_BYTE |
- PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- (int) global_system_variables.net_buffer_length,
- (int) global_system_variables.net_buffer_length,
- NMPWAIT_USE_DEFAULT_WAIT,
- &saPipeSecurity)) ==
- INVALID_HANDLE_VALUE)
- {
- sql_perror("Can't create new named pipe!");
- hPipe=hConnectedPipe;
- continue; // We have to try again
- }
- CONNECT *connect;
- if (!(connect= new CONNECT) ||
- !(connect->vio= vio_new_win32pipe(hConnectedPipe)))
- {
- DisconnectNamedPipe(hConnectedPipe);
- CloseHandle(hConnectedPipe);
- delete connect;
- statistic_increment(aborted_connects,&LOCK_status);
- statistic_increment(connection_errors_internal, &LOCK_status);
- continue;
- }
- connect->host= my_localhost;
- create_new_thread(connect);
- }
- LocalFree(saPipeSecurity.lpSecurityDescriptor);
- CloseHandle(connectOverlapped.hEvent);
- DBUG_LEAVE;
- decrement_handler_count();
- return 0;
-}
-#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 /* _WIN32*/
#endif /* EMBEDDED_LIBRARY */
@@ -8957,7 +8376,9 @@ static int mysql_init_variables(void)
character_set_filesystem= &my_charset_bin;
opt_specialflag= SPECIAL_ENGLISH;
+#ifndef EMBEDDED_LIBRARY
unix_sock= base_ip_sock= extra_ip_sock= MYSQL_INVALID_SOCKET;
+#endif
mysql_home_ptr= mysql_home;
log_error_file_ptr= log_error_file;
protocol_version= PROTOCOL_VERSION;
@@ -9071,9 +8492,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 */
@@ -9816,10 +9234,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/mysqld.h b/sql/mysqld.h
index d5cabd790b2..75f35a6df24 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -24,6 +24,7 @@
#include "mysql_com.h" /* SERVER_VERSION_LENGTH */
#include "my_atomic.h"
#include "mysql/psi/mysql_file.h" /* MYSQL_FILE */
+#include "mysql/psi/mysql_socket.h" /* MYSQL_SOCKET */
#include "sql_list.h" /* I_List */
#include "sql_cmd.h"
#include <my_rnd.h>
@@ -92,6 +93,8 @@ void refresh_status(THD *thd);
bool is_secure_file_path(char *path);
void dec_connection_count(scheduler_functions *scheduler);
extern void init_net_server_extension(THD *thd);
+extern void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock);
+extern void create_new_thread(CONNECT *connect);
extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
@@ -152,6 +155,7 @@ extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name;
extern Time_zone *default_tz;
extern char *my_bind_addr_str;
+extern int server_socket_ai_family;
extern char *default_storage_engine, *default_tmp_storage_engine;
extern char *enforced_storage_engine;
extern char *gtid_pos_auto_engines;
@@ -760,7 +764,7 @@ enum enum_query_type
/* query_id */
extern query_id_t global_query_id;
-ATTRIBUTE_NORETURN void unireg_end(void);
+void unireg_end(void);
/* increment query_id and return it. */
inline __attribute__((warn_unused_result)) query_id_t next_query_id()
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 94cfae2664a..d6db365a8a2 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)
{
@@ -4571,7 +4682,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' */
@@ -8042,52 +8153,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
@@ -8107,76 +8278,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.
@@ -8189,66 +8370,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);
}
@@ -11378,7 +11567,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;
@@ -11392,8 +11580,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)
{
@@ -11439,8 +11626,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);
}
@@ -11471,16 +11657,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);
}
@@ -13055,7 +13238,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..c4c30c9b50d 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
+ Add new 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
*/
-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)
+{
+ 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],
+ ((Item_func *)item)->arguments()[1],
+ &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 (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;
+ }
+ (*cond_eq)->copy(new_cond_equal);
+ }
+
+ if (new_cond_equal.current_level.elements > 0)
+ {
+ 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;
+ }
+ 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 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)))
+ if (!join->is_orig_degenerated &&
+ execute_degenerate_jtbm_semi_join(thd, table, subq_pred,
+ eq_list))
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)
- {
- 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/partition_info.h b/sql/partition_info.h
index e00a2c44341..a0cde570d03 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -394,12 +394,13 @@ public:
bool has_unique_name(partition_element *element);
bool vers_init_info(THD *thd);
- bool vers_set_interval(Item *item, interval_type int_type, my_time_t start)
+ bool vers_set_interval(THD *thd, Item *item,
+ interval_type int_type, my_time_t start)
{
DBUG_ASSERT(part_type == VERSIONING_PARTITION);
vers_info->interval.type= int_type;
vers_info->interval.start= start;
- return get_interval_value(item, int_type, &vers_info->interval.step) ||
+ return get_interval_value(thd, item, int_type, &vers_info->interval.step) ||
vers_info->interval.step.neg || vers_info->interval.step.second_part ||
!(vers_info->interval.step.year || vers_info->interval.step.month ||
vers_info->interval.step.day || vers_info->interval.step.hour ||
diff --git a/sql/procedure.h b/sql/procedure.h
index 1ece31223ad..2169091c0a6 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;
@@ -59,9 +69,9 @@ public:
DBUG_ASSERT(0); // impossible
return mark_unsupported_function("proc", arg, VCOL_IMPOSSIBLE);
}
- bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
- return type_handler()->Item_get_date(this, ltime, fuzzydate);
+ return type_handler()->Item_get_date(thd, this, ltime, fuzzydate);
}
Item* get_copy(THD *thd) { return 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/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index a60ddeb3017..e73666cfb58 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6570,7 +6570,7 @@ ER_ACCESS_DENIED_NO_PASSWORD_ERROR 28000
ukr "Доступ заборонено для користувача: '%s'@'%s'"
ER_SET_PASSWORD_AUTH_PLUGIN
- eng "SET PASSWORD has no significance for users authenticating via plugins"
+ eng "SET PASSWORD is ignored for users authenticating via %s plugin"
ER_GRANT_PLUGIN_USER_EXISTS
eng "GRANT with IDENTIFIED WITH is illegal because the user %-.*s already exists"
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_acl.cc b/sql/sql_acl.cc
index 3727bf7d7ce..052c5ada3a2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -57,6 +57,8 @@
#include "sql_plugin_compat.h"
+#define MAX_SCRAMBLE_LENGTH 1024
+
bool mysql_user_table_is_in_short_password_format= false;
static LEX_CSTRING native_password_plugin_name= {
@@ -85,11 +87,19 @@ LEX_CSTRING current_role= { STRING_WITH_LEN("*current_role") };
LEX_CSTRING current_user_and_current_role= { STRING_WITH_LEN("*current_user_and_current_role") };
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static plugin_ref old_password_plugin;
-#endif
static plugin_ref native_password_plugin;
+static plugin_ref get_auth_plugin(THD *thd, const LEX_CSTRING &name, bool *locked)
+{
+ if (name.str == native_password_plugin_name.str)
+ return native_password_plugin;
+ else if (name.str == old_password_plugin_name.str)
+ return old_password_plugin;
+ *locked=true;
+ return my_plugin_lock_by_name(thd, &name, MYSQL_AUTHENTICATION_PLUGIN);
+}
+
/* Classes */
struct acl_host_and_ip
@@ -119,13 +129,10 @@ public:
char *db;
};
-class ACL_USER_BASE :public ACL_ACCESS
+class ACL_USER_BASE :public ACL_ACCESS, public Sql_alloc
{
public:
- static void *operator new(size_t size, MEM_ROOT *mem_root)
- { return (void*) alloc_root(mem_root, size); }
- static void operator delete(void *, MEM_ROOT *){}
uchar flags; // field used to store various state information
LEX_CSTRING user;
/* list to hold references to granted roles (ACL_ROLE instances) */
@@ -138,13 +145,12 @@ public:
acl_host_and_ip host;
size_t hostname_length;
USER_RESOURCES user_resource;
- uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
- uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
LEX_CSTRING plugin;
LEX_CSTRING auth_string;
LEX_CSTRING default_rolename;
+ LEX_CSTRING salt;
ACL_USER *copy(MEM_ROOT *root)
{
@@ -152,8 +158,7 @@ public:
if (!dst)
return 0;
*dst= *this;
- dst->user.str= safe_strdup_root(root, user.str);
- dst->user.length= user.length;
+ dst->user= safe_lexcstrdup_root(root, user);
dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
dst->x509_issuer= safe_strdup_root(root, x509_issuer);
dst->x509_subject= safe_strdup_root(root, x509_subject);
@@ -161,11 +166,11 @@ public:
plugin.str == old_password_plugin_name.str)
dst->plugin= plugin;
else
- dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
- dst->auth_string.str= safe_strdup_root(root, auth_string.str);
+ dst->plugin= safe_lexcstrdup_root(root, plugin);
+ dst->auth_string= safe_lexcstrdup_root(root, auth_string);
+ dst->salt= safe_lexcstrdup_root(root, salt);
dst->host.hostname= safe_strdup_root(root, host.hostname);
- dst->default_rolename.str= safe_strdup_root(root, default_rolename.str);
- dst->default_rolename.length= default_rolename.length;
+ dst->default_rolename= safe_lexcstrdup_root(root, default_rolename);
bzero(&dst->role_grants, sizeof(role_grants));
return dst;
}
@@ -174,7 +179,7 @@ public:
{
CHARSET_INFO *cs= system_charset_info;
int res;
- res= strcmp(safe_str(user.str), safe_str(user2));
+ res= strcmp(user.str, user2);
if (!res)
res= my_strcasecmp(cs, host.hostname, host2);
return res;
@@ -184,7 +189,7 @@ public:
bool wild_eq(const char *user2, const char *host2, const char *ip2)
{
- if (strcmp(safe_str(user.str), safe_str(user2)))
+ if (strcmp(user.str, user2))
return false;
return compare_hostname(&host, host2, ip2 ? ip2 : host2);
@@ -275,10 +280,9 @@ public:
const char *proxied_host_arg, const char *proxied_user_arg,
bool with_grant_arg)
{
- user= (user_arg && *user_arg) ? user_arg : NULL;
+ user= user_arg;
update_hostname (&host, (host_arg && *host_arg) ? host_arg : NULL);
- proxied_user= (proxied_user_arg && *proxied_user_arg) ?
- proxied_user_arg : NULL;
+ proxied_user= proxied_user_arg;
update_hostname (&proxied_host,
(proxied_host_arg && *proxied_host_arg) ?
proxied_host_arg : NULL);
@@ -291,11 +295,10 @@ public:
bool with_grant_arg)
{
init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
- (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
+ strdup_root (mem, user_arg),
(proxied_host_arg && *proxied_host_arg) ?
strdup_root (mem, proxied_host_arg) : NULL,
- (proxied_user_arg && *proxied_user_arg) ?
- strdup_root (mem, proxied_user_arg) : NULL,
+ strdup_root (mem, proxied_user_arg),
with_grant_arg);
}
@@ -308,7 +311,7 @@ public:
const char *get_proxied_host() { return proxied_host.hostname; }
void set_user(MEM_ROOT *mem, const char *user_arg)
{
- user= user_arg && *user_arg ? strdup_root(mem, user_arg) : NULL;
+ user= *user_arg ? strdup_root(mem, user_arg) : "";
}
void set_host(MEM_ROOT *mem, const char *host_arg)
{
@@ -323,9 +326,8 @@ public:
{
sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- safe_str(proxied_user),
- safe_str(proxied_host.hostname),
- safe_str(user),
+ proxied_user,
+ safe_str(proxied_host.hostname), user,
safe_str(host.hostname));
return TRUE;
}
@@ -345,11 +347,10 @@ public:
proxied_user_arg, proxied_user));
DBUG_RETURN(compare_hostname(&host, host_arg, ip_arg) &&
compare_hostname(&proxied_host, host_arg, ip_arg) &&
- (!user ||
+ (!*user ||
(user_arg && !wild_compare(user_arg, user, TRUE))) &&
- (!proxied_user ||
- (proxied_user && !wild_compare(proxied_user_arg,
- proxied_user, TRUE))));
+ (!*proxied_user ||
+ !wild_compare(proxied_user_arg, proxied_user, TRUE)));
}
@@ -381,8 +382,7 @@ public:
bool granted_on(const char *host_arg, const char *user_arg)
{
- return (((!user && (!user_arg || !user_arg[0])) ||
- (user && user_arg && !strcmp(user, user_arg))) &&
+ return (!strcmp(user, user_arg) &&
((!host.hostname && (!host_arg || !host_arg[0])) ||
(host.hostname && host_arg && !strcmp(host.hostname, host_arg))));
}
@@ -391,17 +391,15 @@ public:
void print_grant(String *str)
{
str->append(STRING_WITH_LEN("GRANT PROXY ON '"));
- if (proxied_user)
- str->append(proxied_user, strlen(proxied_user));
+ str->append(proxied_user);
str->append(STRING_WITH_LEN("'@'"));
if (proxied_host.hostname)
str->append(proxied_host.hostname, strlen(proxied_host.hostname));
str->append(STRING_WITH_LEN("' TO '"));
- if (user)
- str->append(user, strlen(user));
+ str->append(user);
str->append(STRING_WITH_LEN("'@'"));
if (host.hostname)
- str->append(host.hostname, strlen(host.hostname));
+ str->append(host.hostname);
str->append(STRING_WITH_LEN("'"));
if (with_grant)
str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
@@ -622,8 +620,8 @@ static ACL_USER *find_user_wild(const char *host, const char *user, const char *
static ACL_ROLE *find_acl_role(const char *user);
static ROLE_GRANT_PAIR *find_role_grant_pair(const LEX_CSTRING *u, const LEX_CSTRING *h, const LEX_CSTRING *r);
static ACL_USER_BASE *find_acl_user_base(const char *user, const char *host);
-static bool update_user_table(THD *, const User_table &, const char *, const char *, const
- char *, size_t new_password_len);
+static bool update_user_table_password(THD *, const User_table&,
+ const ACL_USER &);
static bool acl_load(THD *thd, const Grant_tables& grant_tables);
static inline void get_grantor(THD *thd, char* grantor);
static bool add_role_user_mapping(const char *uname, const char *hname, const char *rname);
@@ -1306,9 +1304,9 @@ void ACL_PROXY_USER::init(const Proxies_priv_table& proxies_priv_table,
MEM_ROOT *mem)
{
init(get_field(mem, proxies_priv_table.host()),
- get_field(mem, proxies_priv_table.user()),
+ safe_str(get_field(mem, proxies_priv_table.user())),
get_field(mem, proxies_priv_table.proxied_host()),
- get_field(mem, proxies_priv_table.proxied_user()),
+ safe_str(get_field(mem, proxies_priv_table.proxied_user())),
proxies_priv_table.with_grant()->val_int() != 0);
}
@@ -1337,8 +1335,7 @@ ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) : counter(0)
access= user->access;
/* set initial role access the same as the table row privileges */
initial_role_access= user->access;
- this->user.str= safe_strdup_root(root, user->user.str);
- this->user.length= user->user.length;
+ this->user= user->user;
bzero(&role_grants, sizeof(role_grants));
bzero(&parent_grantee, sizeof(parent_grantee));
flags= IS_ROLE;
@@ -1388,7 +1385,7 @@ static bool has_validation_plugins()
MariaDB_PASSWORD_VALIDATION_PLUGIN, NULL);
}
-struct validation_data { LEX_CSTRING *user, *password; };
+struct validation_data { const LEX_CSTRING *user, *password; };
static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
{
@@ -1399,13 +1396,13 @@ static my_bool do_validate(THD *, plugin_ref plugin, void *arg)
}
-static bool validate_password(LEX_USER *user, THD *thd)
+static bool validate_password(THD *thd, const LEX_CSTRING &user,
+ const LEX_CSTRING &pwtext, bool has_hash)
{
- if (user->pwtext.length || !user->pwhash.length)
+ if (pwtext.length || !has_hash)
{
- struct validation_data data= { &user->user,
- user->pwtext.str ? &user->pwtext :
- const_cast<LEX_CSTRING *>(&empty_clex_str) };
+ struct validation_data data= { &user,
+ pwtext.str ? &pwtext : &empty_clex_str };
if (plugin_foreach(NULL, do_validate,
MariaDB_PASSWORD_VALIDATION_PLUGIN, &data))
{
@@ -1426,45 +1423,87 @@ static bool validate_password(LEX_USER *user, THD *thd)
}
/**
- Convert scrambled password to binary form, according to scramble type,
- Binary form is stored in user.salt.
-
- @param acl_user The object where to store the salt
- @param password The password hash containing the salt
- @param password_len The length of the password hash
-
- Despite the name of the function it is used when loading ACLs from disk
- to store the password hash in the ACL_USER object.
-*/
+ Fills in ACL_USER::auth_string and ACL_USER::salt fields, as needed
-static void
-set_user_salt(ACL_USER *acl_user, const char *password, size_t password_len)
+ hashes the plain-text password (if provided) to auth_string,
+ converts auth_string to salt.
+
+ Fails if the plain-text password fails validation, if the plugin is
+ not loaded, if the auth_string is invalid.
+
+ Using NULL for a password disables validation
+ (needed for loading from mysql.user table).
+*/
+static int set_user_auth(THD *thd, ACL_USER *acl_user, const LEX_CSTRING *pwtext)
{
- if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ const char *plugin_name= acl_user->plugin.str;
+ bool unlock_plugin= false;
+ plugin_ref plugin= get_auth_plugin(thd, acl_user->plugin, &unlock_plugin);
+ int res= 1;
+
+ if (!plugin)
{
- get_salt_from_password(acl_user->salt, password);
- acl_user->salt_len= SCRAMBLE_LENGTH;
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_PLUGIN_IS_NOT_LOADED,
+ ER_THD(thd, ER_PLUGIN_IS_NOT_LOADED), plugin_name);
+ return res;
}
- else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+
+ acl_user->salt= acl_user->auth_string;
+
+ st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
+ if (auth->interface_version >= 0x0202)
{
- get_salt_from_password_323((ulong *) acl_user->salt, password);
- acl_user->salt_len= SCRAMBLE_LENGTH_323;
+ if (pwtext)
+ {
+ if (auth->hash_password &&
+ validate_password(thd, acl_user->user, *pwtext,
+ acl_user->auth_string.length))
+ goto end;
+ if (pwtext->length)
+ {
+ if (auth->hash_password)
+ {
+ char buf[MAX_SCRAMBLE_LENGTH];
+ size_t len= sizeof(buf) - 1;
+ if (auth->hash_password(pwtext->str, pwtext->length, buf, &len))
+ goto end; // OOM?
+ buf[len] = 0;
+ acl_user->auth_string.str= (char*)memdup_root(&acl_memroot, buf, len+1);
+ acl_user->auth_string.length= len;
+ }
+ else
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_SET_PASSWORD_AUTH_PLUGIN,
+ ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN),
+ acl_user->plugin.str);
+ }
+ }
+ }
+
+ if (acl_user->auth_string.length)
+ {
+ if (auth->preprocess_hash)
+ {
+ uchar buf[MAX_SCRAMBLE_LENGTH];
+ size_t len= sizeof(buf);
+ if (auth->preprocess_hash(acl_user->auth_string.str,
+ acl_user->auth_string.length, buf, &len))
+ goto end; // ER_PASSWD_LENGTH?
+ acl_user->salt.str= (char*)memdup_root(&acl_memroot, buf, len);
+ acl_user->salt.length= len;
+ }
+ else
+ acl_user->salt= acl_user->auth_string;
+ }
}
- else
- acl_user->salt_len= 0;
-}
-static const char *fix_plugin_ptr(const char *name)
-{
- if (my_strcasecmp(system_charset_info, name,
- native_password_plugin_name.str) == 0)
- return native_password_plugin_name.str;
- else
- if (my_strcasecmp(system_charset_info, name,
- old_password_plugin_name.str) == 0)
- return old_password_plugin_name.str;
- else
- return name;
+ res= 0;
+end:
+ if (unlock_plugin)
+ plugin_unlock(thd, plugin);
+ return res;
}
/**
@@ -1475,8 +1514,6 @@ static const char *fix_plugin_ptr(const char *name)
authentication, we want to be able to detect built-ins by comparing
pointers, not strings.
- Additionally - update the salt if the plugin is built-in.
-
@retval 0 the pointers were fixed
@retval 1 this ACL_USER uses a not built-in plugin
*/
@@ -1489,98 +1526,6 @@ static bool fix_user_plugin_ptr(ACL_USER *user)
user->plugin= old_password_plugin_name;
else
return true;
-
- if (user->auth_string.length)
- set_user_salt(user, user->auth_string.str, user->auth_string.length);
- return false;
-}
-
-
-/*
- Validates the password, calculates password hash, transforms
- equivalent LEX_USER representations.
-
- Upon entering this function:
-
- - if user->plugin is specified, user->auth is the plugin auth data.
- - if user->plugin is mysql_native_password or mysql_old_password,
- user->auth is the password hash, and LEX_USER is transformed
- to match the next case (that is, user->plugin is cleared).
- - if user->plugin is NOT specified, built-in auth is assumed, that is
- mysql_native_password or mysql_old_password. In that case,
- user->pwhash is the password hash. And user->pwtext is the original
- plain-text password. Either one can be set or both.
-
- Upon exiting this function:
-
- - user->pwtext is left untouched
- - user->pwhash is the password hash, as the mysql.user.password column
- - user->plugin is the plugin name, as the mysql.user.plugin column
- - user->auth is the plugin auth data, as the mysql.user.authentication_string column
-*/
-static bool fix_lex_user(THD *thd, LEX_USER *user)
-{
- size_t check_length;
-
- DBUG_ASSERT(user->plugin.length || !user->auth.length);
- DBUG_ASSERT(!(user->plugin.length && (user->pwtext.length || user->pwhash.length)));
-
- if (lex_string_eq(&user->plugin, &native_password_plugin_name))
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- else
- if (lex_string_eq(&user->plugin, &old_password_plugin_name))
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- else
- if (user->plugin.length)
- return false; // nothing else to do
- else if (thd->variables.old_passwords == 1 ||
- user->pwhash.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- else
- check_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
-
- if (user->plugin.length)
- {
- user->pwhash= user->auth;
- user->plugin= empty_clex_str;
- user->auth= empty_clex_str;
- }
-
- if (user->pwhash.length && user->pwhash.length != check_length)
- {
- my_error(ER_PASSWD_LENGTH, MYF(0), (int) check_length);
- return true;
- }
-
- if (user->pwtext.length && !user->pwhash.length)
- {
- size_t scramble_length;
- void (*make_scramble)(char *, const char *, size_t);
-
- if (thd->variables.old_passwords == 1)
- {
- scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
- make_scramble= my_make_scrambled_password_323;
- }
- else
- {
- scramble_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
- make_scramble= my_make_scrambled_password;
- }
-
- Query_arena *arena, backup;
- arena= thd->activate_stmt_arena_if_needed(&backup);
- char *buff= (char *) thd->alloc(scramble_length + 1);
- if (arena)
- thd->restore_active_arena(arena, &backup);
-
- if (buff == NULL)
- return true;
- make_scramble(buff, user->pwtext.str, user->pwtext.length);
- user->pwhash.str= buff;
- user->pwhash.length= scramble_length;
- }
-
return false;
}
@@ -1661,23 +1606,22 @@ bool acl_init(bool dont_read_acl_tables)
Choose from either native or old password plugins when assigning a password
*/
-static bool set_user_plugin (ACL_USER *user, size_t password_len)
+static LEX_CSTRING &guess_auth_plugin(THD *thd, size_t password_len)
{
- switch (password_len)
- {
- case 0: /* no password */
- case SCRAMBLED_PASSWORD_CHAR_LENGTH:
- user->plugin= native_password_plugin_name;
- return FALSE;
- case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
- user->plugin= old_password_plugin_name;
- return FALSE;
- default:
- sql_print_warning("Found invalid password for user: '%s@%s'; "
- "Ignoring user", safe_str(user->user.str),
- safe_str(user->host.hostname));
- return TRUE;
- }
+ if (thd->variables.old_passwords == 1 ||
+ password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ return old_password_plugin_name;
+ else
+ return native_password_plugin_name;
+}
+
+
+static void push_new_user(const ACL_USER &user)
+{
+ push_dynamic(&acl_users, &user);
+ if (!user.host.hostname ||
+ (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
+ allow_all_hosts=1; // Anyone can connect
}
@@ -1702,7 +1646,6 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
READ_RECORD read_record_info;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[SAFE_NAME_LEN+1];
- int password_length;
Sql_mode_save old_mode_save(thd);
DBUG_ENTER("acl_load");
@@ -1775,8 +1718,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
USERNAME_CHAR_LENGTH);
if (user_table.password()) // Password column might be missing. (MySQL 5.7.6+)
{
- password_length= user_table.password()->field_length /
- user_table.password()->charset()->mbmaxlen;
+ int password_length= user_table.password()->field_length /
+ user_table.password()->charset()->mbmaxlen;
if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
sql_print_error("Fatal error: mysql.user table is damaged or in "
@@ -1826,9 +1769,9 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
bool is_role= FALSE;
bzero(&user, sizeof(user));
update_hostname(&user.host, get_field(&acl_memroot, user_table.host()));
- char *username= get_field(&acl_memroot, user_table.user());
+ char *username= safe_str(get_field(&acl_memroot, user_table.user()));
user.user.str= username;
- user.user.length= safe_strlen(username);
+ user.user.length= strlen(username);
/*
If the user entry is a role, skip password and hostname checks
@@ -1846,188 +1789,189 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
hostname_requires_resolving(user.host.hostname))
{
sql_print_warning("'user' entry '%s@%s' "
- "ignored in --skip-name-resolve mode.",
- safe_str(user.user.str),
+ "ignored in --skip-name-resolve mode.", user.user.str,
safe_str(user.host.hostname));
continue;
}
- char *password= const_cast<char*>("");
if (user_table.password())
- password= get_field(&acl_memroot, user_table.password());
- size_t password_len= safe_strlen(password);
- user.auth_string.str= safe_str(password);
- user.auth_string.length= password_len;
- set_user_salt(&user, password, password_len);
+ {
+ const char *p= safe_str(get_field(&acl_memroot, user_table.password()));
+ user.auth_string.str= p;
+ user.auth_string.length= strlen(p);
+ }
+ else
+ user.auth_string= empty_clex_str;
- if (!is_role && set_user_plugin(&user, password_len))
- continue;
+ user.plugin= guess_auth_plugin(thd, user.auth_string.length);
- {
- user.access= user_table.get_access() & GLOBAL_ACLS;
- /*
- if it is pre 5.0.1 privilege table then map CREATE privilege on
- CREATE VIEW & SHOW VIEW privileges
- */
- if (user_table.num_fields() <= 31 && (user.access & CREATE_ACL))
- user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
+ user.access= user_table.get_access() & GLOBAL_ACLS;
+ /*
+ if it is pre 5.0.1 privilege table then map CREATE privilege on
+ CREATE VIEW & SHOW VIEW privileges
+ */
+ if (user_table.num_fields() <= 31 && (user.access & CREATE_ACL))
+ user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
- /*
- if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
- CREATE PROCEDURE & ALTER PROCEDURE privileges
- */
- if (user_table.num_fields() <= 33 && (user.access & CREATE_ACL))
- user.access|= CREATE_PROC_ACL;
- if (user_table.num_fields() <= 33 && (user.access & ALTER_ACL))
- user.access|= ALTER_PROC_ACL;
+ /*
+ if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
+ CREATE PROCEDURE & ALTER PROCEDURE privileges
+ */
+ if (user_table.num_fields() <= 33 && (user.access & CREATE_ACL))
+ user.access|= CREATE_PROC_ACL;
+ if (user_table.num_fields() <= 33 && (user.access & ALTER_ACL))
+ user.access|= ALTER_PROC_ACL;
- /*
- pre 5.0.3 did not have CREATE_USER_ACL
- */
- if (user_table.num_fields() <= 36 && (user.access & GRANT_ACL))
- user.access|= CREATE_USER_ACL;
+ /*
+ pre 5.0.3 did not have CREATE_USER_ACL
+ */
+ if (user_table.num_fields() <= 36 && (user.access & GRANT_ACL))
+ user.access|= CREATE_USER_ACL;
- /*
- if it is pre 5.1.6 privilege table then map CREATE privilege on
- CREATE|ALTER|DROP|EXECUTE EVENT
- */
- if (user_table.num_fields() <= 37 && (user.access & SUPER_ACL))
- user.access|= EVENT_ACL;
+ /*
+ if it is pre 5.1.6 privilege table then map CREATE privilege on
+ CREATE|ALTER|DROP|EXECUTE EVENT
+ */
+ if (user_table.num_fields() <= 37 && (user.access & SUPER_ACL))
+ user.access|= EVENT_ACL;
- /*
- if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
- */
- if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL))
- user.access|= TRIGGER_ACL;
+ /*
+ if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
+ */
+ if (user_table.num_fields() <= 38 && (user.access & SUPER_ACL))
+ user.access|= TRIGGER_ACL;
- if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL))
- user.access|= DELETE_HISTORY_ACL;
+ if (user_table.num_fields() <= 46 && (user.access & DELETE_ACL))
+ user.access|= DELETE_HISTORY_ACL;
- user.sort= get_sort(2, user.host.hostname, user.user.str);
- user.hostname_length= safe_strlen(user.host.hostname);
- user.user_resource.user_conn= 0;
- user.user_resource.max_statement_time= 0.0;
+ user.sort= get_sort(2, user.host.hostname, user.user.str);
+ user.hostname_length= safe_strlen(user.host.hostname);
+ user.user_resource.user_conn= 0;
+ user.user_resource.max_statement_time= 0.0;
- /* Starting from 4.0.2 we have more fields */
- if (user_table.ssl_type())
+ /* Starting from 4.0.2 we have more fields */
+ if (user_table.ssl_type())
+ {
+ char *ssl_type=get_field(thd->mem_root, user_table.ssl_type());
+ if (!ssl_type)
+ user.ssl_type=SSL_TYPE_NONE;
+ else if (!strcmp(ssl_type, "ANY"))
+ user.ssl_type=SSL_TYPE_ANY;
+ else if (!strcmp(ssl_type, "X509"))
+ user.ssl_type=SSL_TYPE_X509;
+ else /* !strcmp(ssl_type, "SPECIFIED") */
+ user.ssl_type=SSL_TYPE_SPECIFIED;
+
+ user.ssl_cipher= get_field(&acl_memroot, user_table.ssl_cipher());
+ user.x509_issuer= get_field(&acl_memroot, user_table.x509_issuer());
+ user.x509_subject= get_field(&acl_memroot, user_table.x509_subject());
+
+ char *ptr = get_field(thd->mem_root, user_table.max_questions());
+ user.user_resource.questions=ptr ? atoi(ptr) : 0;
+ ptr = get_field(thd->mem_root, user_table.max_updates());
+ user.user_resource.updates=ptr ? atoi(ptr) : 0;
+ ptr = get_field(thd->mem_root, user_table.max_connections());
+ user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
+ if (user.user_resource.questions || user.user_resource.updates ||
+ user.user_resource.conn_per_hour)
+ mqh_used=1;
+
+ if (user_table.max_user_connections())
{
- char *ssl_type=get_field(thd->mem_root, user_table.ssl_type());
- if (!ssl_type)
- user.ssl_type=SSL_TYPE_NONE;
- else if (!strcmp(ssl_type, "ANY"))
- user.ssl_type=SSL_TYPE_ANY;
- else if (!strcmp(ssl_type, "X509"))
- user.ssl_type=SSL_TYPE_X509;
- else /* !strcmp(ssl_type, "SPECIFIED") */
- user.ssl_type=SSL_TYPE_SPECIFIED;
-
- user.ssl_cipher= get_field(&acl_memroot, user_table.ssl_cipher());
- user.x509_issuer= get_field(&acl_memroot, user_table.x509_issuer());
- user.x509_subject= get_field(&acl_memroot, user_table.x509_subject());
-
- char *ptr = get_field(thd->mem_root, user_table.max_questions());
- user.user_resource.questions=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, user_table.max_updates());
- user.user_resource.updates=ptr ? atoi(ptr) : 0;
- ptr = get_field(thd->mem_root, user_table.max_connections());
- user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
- if (user.user_resource.questions || user.user_resource.updates ||
- user.user_resource.conn_per_hour)
- mqh_used=1;
-
- if (user_table.max_user_connections())
- {
- /* Starting from 5.0.3 we have max_user_connections field */
- ptr= get_field(thd->mem_root, user_table.max_user_connections());
- user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
- }
+ /* Starting from 5.0.3 we have max_user_connections field */
+ ptr= get_field(thd->mem_root, user_table.max_user_connections());
+ user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
+ }
- if (!is_role && user_table.plugin())
+ if (!is_role && user_table.plugin())
+ {
+ /* We may have plugin & auth_string fields */
+ char *tmpstr= get_field(&acl_memroot, user_table.plugin());
+ if (tmpstr)
{
- /* We may have plugin & auth_String fields */
- char *tmpstr= get_field(&acl_memroot, user_table.plugin());
- if (tmpstr)
+ LEX_CSTRING password= user.auth_string;
+ user.plugin.str= tmpstr;
+ user.plugin.length= strlen(user.plugin.str);
+ user.auth_string.str=
+ safe_str(get_field(&acl_memroot,
+ user_table.authentication_string()));
+ user.auth_string.length= strlen(user.auth_string.str);
+
+ if (password.length)
{
- user.plugin.str= tmpstr;
- user.plugin.length= strlen(user.plugin.str);
- user.auth_string.str=
- safe_str(get_field(&acl_memroot,
- user_table.authentication_string()));
- user.auth_string.length= strlen(user.auth_string.str);
-
- if (user.auth_string.length && password_len &&
- (user.auth_string.length != password_len ||
- memcmp(user.auth_string.str, password, password_len)))
+ if (user.auth_string.length &&
+ (user.auth_string.length != password.length ||
+ memcmp(user.auth_string.str, password.str, password.length)))
{
sql_print_warning("'user' entry '%s@%s' has both a password "
"and an authentication plugin specified. The "
"password will be ignored.",
- safe_str(user.user.str),
- safe_str(user.host.hostname));
+ user.user.str, safe_str(user.host.hostname));
}
-
- fix_user_plugin_ptr(&user);
+ else
+ user.auth_string= password;
}
- }
- if (user_table.max_statement_time())
- {
- /* Starting from 10.1.1 we can have max_statement_time */
- ptr= get_field(thd->mem_root,
- user_table.max_statement_time());
- user.user_resource.max_statement_time= ptr ? atof(ptr) : 0.0;
+ fix_user_plugin_ptr(&user);
}
}
- else
+
+ if (user_table.max_statement_time())
{
- user.ssl_type=SSL_TYPE_NONE;
+ /* Starting from 10.1.1 we can have max_statement_time */
+ ptr= get_field(thd->mem_root,
+ user_table.max_statement_time());
+ user.user_resource.max_statement_time= ptr ? atof(ptr) : 0.0;
+ }
+ }
+ else
+ {
+ user.ssl_type=SSL_TYPE_NONE;
#ifndef TO_BE_REMOVED
- if (user_table.num_fields() <= 13)
- { // Without grant
- if (user.access & CREATE_ACL)
- user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
- }
- /* Convert old privileges */
- user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
- if (user.access & FILE_ACL)
- user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
- if (user.access & PROCESS_ACL)
- user.access|= SUPER_ACL | EXECUTE_ACL;
-#endif
+ if (user_table.num_fields() <= 13)
+ { // Without grant
+ if (user.access & CREATE_ACL)
+ user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
+ /* Convert old privileges */
+ user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
+ if (user.access & FILE_ACL)
+ user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
+ if (user.access & PROCESS_ACL)
+ user.access|= SUPER_ACL | EXECUTE_ACL;
+#endif
+ }
- (void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_ROLE *),
- 8, 8, MYF(0));
+ my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
- /* check default role, if any */
- if (!is_role && user_table.default_role())
- {
- user.default_rolename.str=
- get_field(&acl_memroot, user_table.default_role());
- user.default_rolename.length= safe_strlen(user.default_rolename.str);
- }
+ /* check default role, if any */
+ if (!is_role && user_table.default_role())
+ {
+ user.default_rolename.str=
+ get_field(&acl_memroot, user_table.default_role());
+ user.default_rolename.length= safe_strlen(user.default_rolename.str);
+ }
- if (is_role)
- {
- DBUG_PRINT("info", ("Found role %s", user.user.str));
- ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
- entry->role_grants = user.role_grants;
- (void) my_init_dynamic_array(&entry->parent_grantee,
- sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
- my_hash_insert(&acl_roles, (uchar *)entry);
+ if (set_user_auth(thd, &user, NULL))
+ {
+ thd->clear_error(); // the warning is still issued
+ continue;
+ }
- continue;
- }
- else
- {
- DBUG_PRINT("info", ("Found user %s", user.user.str));
- (void) push_dynamic(&acl_users,(uchar*) &user);
- }
- if (!user.host.hostname ||
- (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
- allow_all_hosts=1; // Anyone can connect
+ if (is_role)
+ {
+ DBUG_PRINT("info", ("Found role %s", user.user.str));
+ ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot);
+ entry->role_grants = user.role_grants;
+ my_init_dynamic_array(&entry->parent_grantee,
+ sizeof(ACL_USER_BASE *), 0, 8, MYF(0));
+ my_hash_insert(&acl_roles, (uchar *)entry);
+
+ continue;
}
+ DBUG_PRINT("info", ("Found user %s", user.user.str));
+ push_new_user(user);
}
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
@@ -2041,7 +1985,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
{
ACL_DB db;
char *db_name;
- db.user=get_field(&acl_memroot, db_table.user());
+ db.user=safe_str(get_field(&acl_memroot, db_table.user()));
const char *hostname= get_field(&acl_memroot, db_table.host());
if (!hostname && find_acl_role(db.user))
hostname= "";
@@ -2056,7 +2000,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
{
sql_print_warning("'db' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- db.db, safe_str(db.user), safe_str(db.host.hostname));
+ db.db, db.user, safe_str(db.host.hostname));
continue;
}
db.access= db_table.get_access();
@@ -2081,7 +2025,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
"case that has been forced to lowercase because "
"lower_case_table_names is set. It will not be "
"possible to remove this privilege using REVOKE.",
- db.db, safe_str(db.user), safe_str(db.host.hostname));
+ db.db, db.user, safe_str(db.host.hostname));
}
}
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
@@ -2409,7 +2353,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
host, ip, user, db));
- sctx->user= user;
+ sctx->user= *user ? user : NULL;
sctx->host= host;
sctx->ip= ip;
sctx->host_or_ip= host ? host : (safe_str(ip));
@@ -2439,8 +2383,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!acl_db->user ||
- (user && user[0] && !strcmp(user, acl_db->user)))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host, host, ip))
{
@@ -2454,8 +2397,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
}
sctx->master_access= acl_user->access;
- if (acl_user->user.str)
- strmake_buf(sctx->priv_user, user);
+ strmake_buf(sctx->priv_user, user);
if (acl_user->host.hostname)
strmake_buf(sctx->priv_host, acl_user->host.hostname);
@@ -2470,8 +2412,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!acl_db->user ||
- (user && user[0] && !strcmp(user, acl_db->user)))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host, "", ""))
{
@@ -2485,8 +2426,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
}
sctx->master_access= acl_role->access;
- if (acl_role->user.str)
- strmake_buf(sctx->priv_role, user);
+ strmake_buf(sctx->priv_role, user);
}
}
@@ -2609,66 +2549,55 @@ static void acl_update_role(const char *rolename, ulong privileges)
}
-static void acl_update_user(const char *user, const char *host,
- const char *password, size_t password_len,
- enum SSL_type ssl_type,
- const char *ssl_cipher,
- const char *x509_issuer,
- const char *x509_subject,
- USER_RESOURCES *mqh,
- ulong privileges,
- const LEX_CSTRING *plugin,
- const LEX_CSTRING *auth)
+static int acl_user_update(THD *thd, ACL_USER *acl_user, const ACL_USER *from,
+ const LEX_USER &combo, enum SSL_type ssl_type,
+ const char *ssl_cipher, const char *x509_issuer,
+ const char *x509_subject, const USER_RESOURCES *mqh,
+ ulong privileges)
{
- mysql_mutex_assert_owner(&acl_cache->lock);
+ if (from)
+ *acl_user= *from;
+ else
+ {
+ bzero(acl_user, sizeof(*acl_user));
+ acl_user->user= safe_lexcstrdup_root(&acl_memroot, combo.user);
+ update_hostname(&acl_user->host, safe_strdup_root(&acl_memroot, combo.host.str));
+ acl_user->hostname_length= combo.host.length;
+ acl_user->sort= get_sort(2, acl_user->host.hostname, acl_user->user.str);
+ acl_user->plugin= native_password_plugin_name;
+ acl_user->salt= acl_user->auth_string= empty_clex_str;
+ my_init_dynamic_array(&acl_user->role_grants, sizeof(ACL_USER *),
+ 0, 8, MYF(0));
+ }
- for (uint i=0 ; i < acl_users.elements ; i++)
+ if (combo.plugin.length)
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (acl_user->eq(user, host))
- {
- if (plugin->str[0])
- {
- acl_user->plugin= *plugin;
- acl_user->auth_string.str= auth->str ?
- strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>("");
- acl_user->auth_string.length= auth->length;
- if (fix_user_plugin_ptr(acl_user))
- acl_user->plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
- }
- else
- if (password[0])
- {
- acl_user->auth_string.str= strmake_root(&acl_memroot, password, password_len);
- acl_user->auth_string.length= password_len;
- set_user_salt(acl_user, password, password_len);
- set_user_plugin(acl_user, password_len);
- }
- acl_user->access=privileges;
- if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- acl_user->user_resource.questions=mqh->questions;
- if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- acl_user->user_resource.updates=mqh->updates;
- if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
- if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
- acl_user->user_resource.user_conn= mqh->user_conn;
- if (mqh->specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
- acl_user->user_resource.max_statement_time= mqh->max_statement_time;
- if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
- {
- acl_user->ssl_type= ssl_type;
- acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) :
- 0);
- acl_user->x509_issuer= (x509_issuer ? strdup_root(&acl_memroot,x509_issuer) :
- 0);
- acl_user->x509_subject= (x509_subject ?
- strdup_root(&acl_memroot,x509_subject) : 0);
- }
- /* search complete: */
- break;
- }
+ acl_user->plugin= combo.plugin;
+ acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, combo.auth);
+ if (fix_user_plugin_ptr(acl_user))
+ acl_user->plugin= safe_lexcstrdup_root(&acl_memroot, combo.plugin);
+ if (set_user_auth(thd, acl_user, &combo.pwtext))
+ return 1;
+ }
+ acl_user->access= privileges;
+ if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
+ acl_user->user_resource.questions= mqh->questions;
+ if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
+ acl_user->user_resource.updates= mqh->updates;
+ if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
+ if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
+ acl_user->user_resource.user_conn= mqh->user_conn;
+ if (mqh->specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
+ acl_user->user_resource.max_statement_time= mqh->max_statement_time;
+ if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
+ {
+ acl_user->ssl_type= ssl_type;
+ acl_user->ssl_cipher= safe_strdup_root(&acl_memroot, ssl_cipher);
+ acl_user->x509_issuer= safe_strdup_root(&acl_memroot,x509_issuer);
+ acl_user->x509_subject= safe_strdup_root(&acl_memroot,x509_subject);
}
+ return 0;
}
@@ -2678,82 +2607,14 @@ static void acl_insert_role(const char *rolename, ulong privileges)
mysql_mutex_assert_owner(&acl_cache->lock);
entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot);
- (void) my_init_dynamic_array(&entry->parent_grantee,
- sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
- (void) my_init_dynamic_array(&entry->role_grants,sizeof(ACL_ROLE *),
- 8, 8, MYF(0));
+ my_init_dynamic_array(&entry->parent_grantee,
+ sizeof(ACL_USER_BASE *), 0, 8, MYF(0));
+ my_init_dynamic_array(&entry->role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry);
}
-static void acl_insert_user(const char *user, const char *host,
- const char *password, size_t password_len,
- enum SSL_type ssl_type,
- const char *ssl_cipher,
- const char *x509_issuer,
- const char *x509_subject,
- USER_RESOURCES *mqh,
- ulong privileges,
- const LEX_CSTRING *plugin,
- const LEX_CSTRING *auth)
-{
- ACL_USER acl_user;
-
- mysql_mutex_assert_owner(&acl_cache->lock);
-
- bzero(&acl_user, sizeof(acl_user));
- acl_user.user.str=*user ? strdup_root(&acl_memroot,user) : 0;
- acl_user.user.length= strlen(user);
- update_hostname(&acl_user.host, safe_strdup_root(&acl_memroot, host));
- if (plugin->str[0])
- {
- acl_user.plugin= *plugin;
- acl_user.auth_string.str= auth->str ?
- strmake_root(&acl_memroot, auth->str, auth->length) : const_cast<char*>("");
- acl_user.auth_string.length= auth->length;
- if (fix_user_plugin_ptr(&acl_user))
- acl_user.plugin.str= strmake_root(&acl_memroot, plugin->str, plugin->length);
- }
- else
- {
- acl_user.auth_string.str= strmake_root(&acl_memroot, password, password_len);
- acl_user.auth_string.length= password_len;
- set_user_salt(&acl_user, password, password_len);
- set_user_plugin(&acl_user, password_len);
- }
-
- acl_user.flags= 0;
- acl_user.access=privileges;
- acl_user.user_resource = *mqh;
- acl_user.sort=get_sort(2, acl_user.host.hostname, acl_user.user.str);
- acl_user.hostname_length=(uint) strlen(host);
- acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
- ssl_type : SSL_TYPE_NONE);
- acl_user.ssl_cipher= ssl_cipher ? strdup_root(&acl_memroot,ssl_cipher) : 0;
- acl_user.x509_issuer= x509_issuer ? strdup_root(&acl_memroot,x509_issuer) : 0;
- acl_user.x509_subject=x509_subject ? strdup_root(&acl_memroot,x509_subject) : 0;
- (void) my_init_dynamic_array(&acl_user.role_grants, sizeof(ACL_USER *),
- 8, 8, MYF(0));
-
- (void) push_dynamic(&acl_users,(uchar*) &acl_user);
- if (!acl_user.host.hostname ||
- (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
- allow_all_hosts=1; // Anyone can connect /* purecov: tested */
- my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
-
- /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
- rebuild_check_host();
-
- /*
- Rebuild every user's role_grants since 'acl_users' has been sorted
- and old pointers to ACL_USER elements are no longer valid
- */
- rebuild_role_grants();
-}
-
-
static bool acl_update_db(const char *user, const char *host, const char *db,
ulong privileges)
{
@@ -2764,13 +2625,10 @@ static bool acl_update_db(const char *user, const char *host, const char *db,
for (uint i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if ((!acl_db->user && !user[0]) ||
- (acl_db->user &&
- !strcmp(user,acl_db->user)))
+ if (!strcmp(user, acl_db->user))
{
if ((!acl_db->host.hostname && !host[0]) ||
- (acl_db->host.hostname &&
- !strcmp(host, acl_db->host.hostname)))
+ (acl_db->host.hostname && !strcmp(host, acl_db->host.hostname)))
{
if ((!acl_db->db && !db[0]) ||
(acl_db->db && !strcmp(db,acl_db->db)))
@@ -2868,7 +2726,7 @@ ulong acl_get(const char *host, const char *ip,
for (i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if (!acl_db->user || !strcmp(user,acl_db->user))
+ if (!*acl_db->user || !strcmp(user, acl_db->user))
{
if (compare_hostname(&acl_db->host,host,ip))
{
@@ -3225,8 +3083,7 @@ bool check_change_password(THD *thd, LEX_USER *user)
{
LEX_USER *real_user= get_current_user(thd, user);
- if (fix_and_copy_user(real_user, user, thd) ||
- validate_password(real_user, thd))
+ if (fix_and_copy_user(real_user, user, thd))
return true;
*user= *real_user;
@@ -3256,8 +3113,8 @@ bool change_password(THD *thd, LEX_USER *user)
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
- user->host.str, user->user.str, user->pwhash.str));
- DBUG_ASSERT(user->host.str != 0); // Ensured by parent
+ user->host.str, user->user.str, user->auth.str));
+ DBUG_ASSERT(user->host.str != 0); // Ensured by caller
/*
This statement will be replicated as a statement, even when using
@@ -3268,19 +3125,8 @@ bool change_password(THD *thd, LEX_USER *user)
*/
save_binlog_format= thd->set_current_stmt_binlog_format_stmt();
- if (mysql_bin_log.is_open() ||
- (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)))
- {
- query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
- safe_str(user->user.str), safe_str(user->host.str),
- safe_str(user->pwhash.str));
- }
-
if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
- {
- thd->set_query(buff, query_length, system_charset_info);
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, (char*)"user", NULL);
- }
if ((result= tables.open_and_lock(thd)))
DBUG_RETURN(result != 1);
@@ -3297,25 +3143,21 @@ bool change_password(THD *thd, LEX_USER *user)
goto end;
}
- /* update loaded acl entry: */
if (acl_user->plugin.str == native_password_plugin_name.str ||
acl_user->plugin.str == old_password_plugin_name.str)
{
- acl_user->auth_string.str= strmake_root(&acl_memroot, user->pwhash.str, user->pwhash.length);
- acl_user->auth_string.length= user->pwhash.length;
- set_user_salt(acl_user, user->pwhash.str, user->pwhash.length);
+ /* historical hack of auto-changing the plugin */
+ acl_user->plugin= guess_auth_plugin(thd, user->auth.length);
+ }
- set_user_plugin(acl_user, user->pwhash.length);
+ acl_user->auth_string= safe_lexcstrdup_root(&acl_memroot, user->auth);
+ if (set_user_auth(thd, acl_user, &user->pwtext))
+ {
+ mysql_mutex_unlock(&acl_cache->lock);
+ goto end;
}
- else
- push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SET_PASSWORD_AUTH_PLUGIN,
- ER_THD(thd, ER_SET_PASSWORD_AUTH_PLUGIN));
- if (update_user_table(thd, tables.user_table(),
- safe_str(acl_user->host.hostname),
- safe_str(acl_user->user.str),
- user->pwhash.str, user->pwhash.length))
+ if (update_user_table_password(thd, tables.user_table(), *acl_user))
{
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
@@ -3326,6 +3168,8 @@ bool change_password(THD *thd, LEX_USER *user)
result= 0;
if (mysql_bin_log.is_open())
{
+ query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
+ user->user.str, safe_str(user->host.str), acl_user->auth_string.str);
DBUG_ASSERT(query_length);
thd->clear_error();
result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
@@ -3335,7 +3179,7 @@ end:
close_mysql_tables(thd);
#ifdef WITH_WSREP
-WSREP_ERROR_LABEL:
+wsrep_error_label:
if (WSREP(thd) && !thd->wsrep_applier)
{
WSREP_TO_ISOLATION_END;
@@ -3364,13 +3208,12 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
ulong query_length= 0;
bool clear_role= FALSE;
char buff[512];
- enum_binlog_format save_binlog_format=
- thd->get_current_stmt_binlog_format();
+ enum_binlog_format save_binlog_format= thd->get_current_stmt_binlog_format();
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;
DBUG_ENTER("acl_set_default_role");
DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'",
- safe_str(user), safe_str(host), safe_str(rolename)));
+ user, safe_str(host), safe_str(rolename)));
if (rolename == current_role.str) {
if (!thd->security_ctx->priv_role[0])
@@ -3390,7 +3233,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
{
query_length=
sprintf(buff,"SET DEFAULT ROLE '%-.120s' FOR '%-.120s'@'%-.120s'",
- safe_str(rolename), safe_str(user), safe_str(host));
+ safe_str(rolename), user, safe_str(host));
}
/*
@@ -3498,7 +3341,7 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
}
#ifdef WITH_WSREP
-WSREP_ERROR_LABEL:
+wsrep_error_label:
if (WSREP(thd) && !thd->wsrep_applier)
{
WSREP_TO_ISOLATION_END;
@@ -3559,7 +3402,7 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha
for (uint i=0; i < acl_users.elements; i++)
{
ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
- if ((!acl_user_tmp->user.str ||
+ if ((!acl_user_tmp->user.length ||
!strcmp(user, acl_user_tmp->user.str)) &&
compare_hostname(&acl_user_tmp->host, host, ip))
{
@@ -3574,13 +3417,13 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha
/*
Find first entry that matches the specified user@host pair
*/
-static ACL_USER * find_user_exact(const char *host, const char *user)
+static ACL_USER *find_user_exact(const char *host, const char *user)
{
mysql_mutex_assert_owner(&acl_cache->lock);
for (uint i=0 ; i < acl_users.elements ; i++)
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
+ ACL_USER *acl_user=dynamic_element(&acl_users, i, ACL_USER*);
if (acl_user->eq(user, host))
return acl_user;
}
@@ -3615,7 +3458,7 @@ static ACL_ROLE *find_acl_role(const char *role)
mysql_mutex_assert_owner(&acl_cache->lock);
ACL_ROLE *r= (ACL_ROLE *)my_hash_search(&acl_roles, (uchar *)role,
- safe_strlen(role));
+ strlen(role));
DBUG_RETURN(r);
}
@@ -3767,53 +3610,24 @@ bool hostname_requires_resolving(const char *hostname)
}
-void set_authentication_plugin_from_password(const User_table& user_table,
- const char* password, size_t password_length)
-{
- if (password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH ||
- password_length == 0)
- {
- user_table.plugin()->store(native_password_plugin_name.str,
- native_password_plugin_name.length,
- system_charset_info);
- }
- else
- {
- DBUG_ASSERT(password_length == SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
- user_table.plugin()->store(old_password_plugin_name.str,
- old_password_plugin_name.length,
- system_charset_info);
- }
- user_table.authentication_string()->store(password,
- password_length,
- system_charset_info);
-}
/**
Update record for user in mysql.user privilege table with new password.
- @param thd THD
- @param table Pointer to TABLE object for open mysql.user table
- @param host Hostname
- @param user Username
- @param new_password New password hash
- @param new_password_len Length of new password hash
-
@see change_password
*/
-static bool update_user_table(THD *thd, const User_table& user_table,
- const char *host, const char *user,
- const char *new_password, size_t new_password_len)
+static bool update_user_table_password(THD *thd, const User_table& user_table,
+ const ACL_USER &user)
{
+ CHARSET_INFO *cs= system_charset_info;
char user_key[MAX_KEY_LENGTH];
int error;
- DBUG_ENTER("update_user_table");
- DBUG_PRINT("enter",("user: %s host: %s",user,host));
+ DBUG_ENTER("update_user_table_password");
TABLE *table= user_table.table();
table->use_all_columns();
- user_table.host()->store(host,(uint) strlen(host), system_charset_info);
- user_table.user()->store(user,(uint) strlen(user), system_charset_info);
+ user_table.host()->store(user.host.hostname, user.hostname_length, cs);
+ user_table.user()->store(user.user.str, user.user.length, cs);
key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -3829,13 +3643,13 @@ static bool update_user_table(THD *thd, const User_table& user_table,
if (user_table.plugin())
{
- set_authentication_plugin_from_password(user_table, new_password,
- new_password_len);
+ if (user_table.password())
+ user_table.password()->reset();
+ user_table.plugin()->store(user.plugin.str, user.plugin.length, cs);
+ user_table.authentication_string()->store(user.auth_string.str, user.auth_string.length, cs);
}
-
- if (user_table.password())
- user_table.password()->store(new_password, new_password_len, system_charset_info);
-
+ else
+ user_table.password()->store(user.auth_string.str, user.auth_string.length, cs);
if (unlikely(error= table->file->ha_update_row(table->record[1],
table->record[0])) &&
@@ -3887,7 +3701,7 @@ static bool test_if_create_new_users(THD *thd)
****************************************************************************/
static int replace_user_table(THD *thd, const User_table &user_table,
- LEX_USER &combo,
+ LEX_USER *combo,
ulong rights, bool revoke_grant,
bool can_create_user, bool no_auto_create)
{
@@ -3895,26 +3709,14 @@ static int replace_user_table(THD *thd, const User_table &user_table,
bool old_row_exists=0;
char what= (revoke_grant) ? 'N' : 'Y';
uchar user_key[MAX_KEY_LENGTH];
- bool handle_as_role= combo.is_role();
+ bool handle_as_role= combo->is_role();
LEX *lex= thd->lex;
TABLE *table= user_table.table();
+ ACL_USER new_acl_user, *old_acl_user;
DBUG_ENTER("replace_user_table");
mysql_mutex_assert_owner(&acl_cache->lock);
- if (combo.pwhash.str && combo.pwhash.str[0])
- {
- if (combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
- combo.pwhash.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
- {
- DBUG_ASSERT(0);
- my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- DBUG_RETURN(-1);
- }
- }
- else
- combo.pwhash= empty_clex_str;
-
/* if the user table is not up to date, we can't handle role updates */
if (!user_table.is_role() && handle_as_role)
{
@@ -3925,9 +3727,9 @@ static int replace_user_table(THD *thd, const User_table &user_table,
}
table->use_all_columns();
- user_table.host()->store(combo.host.str,combo.host.length,
+ user_table.host()->store(combo->host.str,combo->host.length,
system_charset_info);
- user_table.user()->store(combo.user.str,combo.user.length,
+ user_table.user()->store(combo->user.str,combo->user.length,
system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -3939,7 +3741,7 @@ static int replace_user_table(THD *thd, const User_table &user_table,
/* what == 'N' means revoke */
if (what == 'N')
{
- my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+ my_error(ER_NONEXISTING_GRANT, MYF(0), combo->user.str, combo->host.str);
goto end;
}
/*
@@ -3955,7 +3757,8 @@ static int replace_user_table(THD *thd, const User_table &user_table,
see also test_if_create_new_users()
*/
- else if (!combo.pwhash.length && !combo.plugin.length && no_auto_create)
+ else if (!combo->auth.length && !combo->plugin.length &&
+ !combo->pwtext.length && no_auto_create)
{
my_error(ER_PASSWORD_NO_MATCH, MYF(0));
goto end;
@@ -3965,32 +3768,37 @@ static int replace_user_table(THD *thd, const User_table &user_table,
my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0));
goto end;
}
- else if (combo.plugin.str[0])
+ else if (combo->plugin.length)
{
- if (!plugin_is_ready(&combo.plugin, MYSQL_AUTHENTICATION_PLUGIN))
+ if (!plugin_is_ready(&combo->plugin, MYSQL_AUTHENTICATION_PLUGIN))
{
- my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo.plugin.str);
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), combo->plugin.str);
goto end;
}
}
+ else /* combo->plugin.length == 0 */
+ {
+ combo->plugin= guess_auth_plugin(thd, combo->auth.length);
+ }
old_row_exists = 0;
restore_record(table,s->default_values);
- user_table.host()->store(combo.host.str,combo.host.length,
+ user_table.host()->store(combo->host.str,combo->host.length,
system_charset_info);
- user_table.user()->store(combo.user.str,combo.user.length,
+ user_table.user()->store(combo->user.str,combo->user.length,
system_charset_info);
}
else
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
+ if (!combo->plugin.length && (combo->auth.length || combo->pwtext.length))
+ {
+ /* GRANT ... IDENTIFIED BY */
+ combo->plugin= guess_auth_plugin(thd, combo->auth.length);
+ }
}
- if (!old_row_exists || combo.pwtext.length || combo.pwhash.length)
- if (!handle_as_role && validate_password(&combo, thd))
- goto end;
-
/* Update table columns with new privileges */
ulong priv;
@@ -4003,122 +3811,112 @@ static int replace_user_table(THD *thd, const User_table &user_table,
rights= user_table.get_access();
- DBUG_PRINT("info",("table fields: %d", user_table.num_fields()));
- /* If we don't have a password column, we'll use the authentication_string
- column later. */
- if (combo.pwhash.str[0] && user_table.password())
- user_table.password()->store(combo.pwhash.str, combo.pwhash.length,
- system_charset_info);
- /* We either have the password column, the plugin column, or both. Otherwise
- we have a corrupt user table. */
- DBUG_ASSERT(user_table.password() || user_table.plugin());
- if (user_table.ssl_type()) /* From 4.0.0 we have more fields */
- {
- /* We write down SSL related ACL stuff */
- switch (lex->ssl_type) {
- case SSL_TYPE_ANY:
- user_table.ssl_type()->store(STRING_WITH_LEN("ANY"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
- case SSL_TYPE_X509:
- user_table.ssl_type()->store(STRING_WITH_LEN("X509"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
- case SSL_TYPE_SPECIFIED:
- user_table.ssl_type()->store(STRING_WITH_LEN("SPECIFIED"),
- &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- if (lex->ssl_cipher)
- user_table.ssl_cipher()->store(lex->ssl_cipher,
- strlen(lex->ssl_cipher),
- system_charset_info);
- if (lex->x509_issuer)
- user_table.x509_issuer()->store(lex->x509_issuer,
- strlen(lex->x509_issuer),
- system_charset_info);
- if (lex->x509_subject)
- user_table.x509_subject()->store(lex->x509_subject,
- strlen(lex->x509_subject),
- system_charset_info);
- break;
- case SSL_TYPE_NOT_SPECIFIED:
- break;
- case SSL_TYPE_NONE:
- user_table.ssl_type()->store("", 0, &my_charset_latin1);
- user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
- user_table.x509_issuer()->store("", 0, &my_charset_latin1);
- user_table.x509_subject()->store("", 0, &my_charset_latin1);
- break;
+ if (handle_as_role)
+ {
+ if (old_row_exists && !user_table.check_is_role())
+ {
+ goto end;
+ }
+ user_table.is_role()->store("Y", 1, system_charset_info);
+ }
+ else
+ {
+ old_acl_user= find_user_exact(combo->host.str, combo->user.str);
+ if ((old_acl_user != NULL) != old_row_exists)
+ {
+ my_error(ER_PASSWORD_NO_MATCH, MYF(0));
+ goto end;
}
+ if (acl_user_update(thd, &new_acl_user,
+ old_row_exists ? old_acl_user : NULL,
+ *combo, lex->ssl_type, lex->ssl_cipher,
+ lex->x509_issuer, lex->x509_subject, &lex->mqh,
+ rights))
+ goto end;
- USER_RESOURCES mqh= lex->mqh;
- if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- user_table.max_questions()->store((longlong) mqh.questions, TRUE);
- if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- user_table.max_updates()->store((longlong) mqh.updates, TRUE);
- if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- user_table.max_connections()->store((longlong) mqh.conn_per_hour, TRUE);
- if (user_table.max_user_connections() &&
- (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
- user_table.max_user_connections()->store((longlong) mqh.user_conn, FALSE);
- if (user_table.plugin())
- {
- user_table.plugin()->set_notnull();
- user_table.authentication_string()->set_notnull();
- if (combo.plugin.str[0])
- {
- DBUG_ASSERT(combo.pwhash.str[0] == 0);
- if (user_table.password())
- user_table.password()->reset();
- user_table.plugin()->store(combo.plugin.str, combo.plugin.length,
- system_charset_info);
- user_table.authentication_string()->store(combo.auth.str, combo.auth.length,
- system_charset_info);
+ DBUG_PRINT("info",("table fields: %d", user_table.num_fields()));
+ /* We either have the password column, the plugin column, or both. Otherwise
+ we have a corrupt user table. */
+ DBUG_ASSERT(user_table.password() || user_table.plugin());
+ if (user_table.ssl_type()) /* From 4.0.0 we have more fields */
+ {
+ /* We write down SSL related ACL stuff */
+ switch (lex->ssl_type) {
+ case SSL_TYPE_ANY:
+ user_table.ssl_type()->store(STRING_WITH_LEN("ANY"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
+ case SSL_TYPE_X509:
+ user_table.ssl_type()->store(STRING_WITH_LEN("X509"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
+ case SSL_TYPE_SPECIFIED:
+ user_table.ssl_type()->store(STRING_WITH_LEN("SPECIFIED"),
+ &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ if (lex->ssl_cipher)
+ user_table.ssl_cipher()->store(lex->ssl_cipher,
+ strlen(lex->ssl_cipher),
+ system_charset_info);
+ if (lex->x509_issuer)
+ user_table.x509_issuer()->store(lex->x509_issuer,
+ strlen(lex->x509_issuer),
+ system_charset_info);
+ if (lex->x509_subject)
+ user_table.x509_subject()->store(lex->x509_subject,
+ strlen(lex->x509_subject),
+ system_charset_info);
+ break;
+ case SSL_TYPE_NOT_SPECIFIED:
+ break;
+ case SSL_TYPE_NONE:
+ user_table.ssl_type()->store("", 0, &my_charset_latin1);
+ user_table.ssl_cipher()->store("", 0, &my_charset_latin1);
+ user_table.x509_issuer()->store("", 0, &my_charset_latin1);
+ user_table.x509_subject()->store("", 0, &my_charset_latin1);
+ break;
}
- if (combo.pwhash.str[0])
+
+ USER_RESOURCES mqh= lex->mqh;
+ if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
+ user_table.max_questions()->store((longlong) mqh.questions, TRUE);
+ if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
+ user_table.max_updates()->store((longlong) mqh.updates, TRUE);
+ if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
+ user_table.max_connections()->store((longlong) mqh.conn_per_hour, TRUE);
+ if (user_table.max_user_connections() &&
+ (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
+ user_table.max_user_connections()->store((longlong) mqh.user_conn, FALSE);
+ if (user_table.plugin())
{
- DBUG_ASSERT(combo.plugin.str[0] == 0);
- /* We have Password column. */
- if (user_table.password())
+ user_table.plugin()->set_notnull();
+ user_table.authentication_string()->set_notnull();
+ if (new_acl_user.plugin.length)
{
- user_table.plugin()->reset();
- user_table.authentication_string()->reset();
+ if (user_table.password())
+ user_table.password()->reset();
+ user_table.plugin()->store(new_acl_user.plugin.str,
+ new_acl_user.plugin.length, system_charset_info);
+ user_table.authentication_string()->store(new_acl_user.auth_string.str,
+ new_acl_user.auth_string.length, system_charset_info);
}
- else
+
+ if (user_table.max_statement_time())
{
- /* We do not have Password column. Use PLUGIN && Authentication_string
- columns instead. */
- set_authentication_plugin_from_password(user_table,
- combo.pwhash.str,
- combo.pwhash.length);
+ if (mqh.specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
+ user_table.max_statement_time()->store(mqh.max_statement_time);
}
}
-
- if (user_table.max_statement_time())
- {
- if (mqh.specified_limits & USER_RESOURCES::MAX_STATEMENT_TIME)
- user_table.max_statement_time()->store(mqh.max_statement_time);
- }
- }
- mqh_used= (mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour ||
- mqh.user_conn || mqh.max_statement_time != 0.0);
-
- /* table format checked earlier */
- if (handle_as_role)
- {
- if (old_row_exists && !user_table.check_is_role())
- {
- goto end;
- }
- user_table.is_role()->store("Y", 1, system_charset_info);
+ mqh_used= (mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour ||
+ mqh.user_conn || mqh.max_statement_time != 0.0);
}
}
@@ -4158,37 +3956,32 @@ end:
if (likely(!error))
{
acl_cache->clear(1); // Clear privilege cache
- if (old_row_exists)
+ if (handle_as_role)
{
- if (handle_as_role)
- acl_update_role(combo.user.str, rights);
+ if (old_row_exists)
+ acl_update_role(combo->user.str, rights);
else
- acl_update_user(combo.user.str, combo.host.str,
- combo.pwhash.str, combo.pwhash.length,
- lex->ssl_type,
- lex->ssl_cipher,
- lex->x509_issuer,
- lex->x509_subject,
- &lex->mqh,
- rights,
- &combo.plugin,
- &combo.auth);
+ acl_insert_role(combo->user.str, rights);
}
else
{
- if (handle_as_role)
- acl_insert_role(combo.user.str, rights);
+ if (old_acl_user)
+ *old_acl_user= new_acl_user;
else
- acl_insert_user(combo.user.str, combo.host.str,
- combo.pwhash.str, combo.pwhash.length,
- lex->ssl_type,
- lex->ssl_cipher,
- lex->x509_issuer,
- lex->x509_subject,
- &lex->mqh,
- rights,
- &combo.plugin,
- &combo.auth);
+ {
+ push_new_user(new_acl_user);
+ my_qsort(dynamic_element(&acl_users, 0, ACL_USER*), acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
+
+ /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
+ rebuild_check_host();
+
+ /*
+ Rebuild every user's role_grants since 'acl_users' has been sorted
+ and old pointers to ACL_USER elements are no longer valid
+ */
+ rebuild_role_grants();
+ }
}
}
DBUG_RETURN(error);
@@ -6291,7 +6084,7 @@ static bool merge_one_role_privileges(ACL_ROLE *grantee)
static bool has_auth(LEX_USER *user, LEX *lex)
{
- return user->pwtext.length || user->pwhash.length || user->plugin.length || user->auth.length ||
+ return user->pwtext.length || user->plugin.length || user->auth.length ||
lex->ssl_type != SSL_TYPE_NOT_SPECIFIED || lex->ssl_cipher ||
lex->x509_issuer || lex->x509_subject ||
lex->mqh.specified_limits;
@@ -6303,14 +6096,9 @@ static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd)
{
/* preserve authentication information, if LEX_USER was reallocated */
to->pwtext= from->pwtext;
- to->pwhash= from->pwhash;
to->plugin= from->plugin;
to->auth= from->auth;
}
-
- if (fix_lex_user(thd, to))
- return true;
-
return false;
}
@@ -6474,7 +6262,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
/* Create user if needed */
error= copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
0, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER));
@@ -6653,7 +6441,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
}
/* Create user if needed */
if (copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
0, revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
@@ -6929,7 +6717,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
user_combo.user = username;
if (copy_and_check_auth(&user_combo, &user_combo, thd) ||
- replace_user_table(thd, tables.user_table(), user_combo, 0,
+ replace_user_table(thd, tables.user_table(), &user_combo, 0,
false, create_new_user,
no_auto_create_user))
{
@@ -7099,7 +6887,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
}
if (copy_and_check_auth(Str, tmp_Str, thd) ||
- replace_user_table(thd, tables.user_table(), *Str,
+ replace_user_table(thd, tables.user_table(), Str,
(!db ? rights : 0), revoke_grant, create_new_users,
MY_TEST(thd->variables.sql_mode &
MODE_NO_AUTO_CREATE_USER)))
@@ -7263,8 +7051,7 @@ static bool grant_load(THD *thd,
{
sql_print_warning("'tables_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- mem_check->tname,
- safe_str(mem_check->user),
+ mem_check->tname, mem_check->user,
safe_str(mem_check->host.hostname));
continue;
}
@@ -8349,7 +8136,6 @@ static void add_user_parameters(String *result, ACL_USER* acl_user,
{
if (acl_user->auth_string.length)
{
- DBUG_ASSERT(acl_user->salt_len);
result->append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
result->append(&acl_user->auth_string);
result->append('\'');
@@ -8869,7 +8655,7 @@ static bool show_database_privileges(THD *thd, const char *username,
const char *user, *host;
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host=acl_db->host.hostname;
/*
@@ -8955,7 +8741,7 @@ static bool show_table_and_column_privileges(THD *thd, const char *username,
GRANT_TABLE *grant_table= (GRANT_TABLE*)
my_hash_element(&column_priv_hash, index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= grant_table->host.hostname;
/*
@@ -9097,7 +8883,7 @@ static int show_routine_grants(THD* thd,
const char *user, *host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index);
- user= safe_str(grant_proc->user);
+ user= grant_proc->user;
host= grant_proc->host.hostname;
/*
@@ -9609,8 +9395,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
my_hash_delete(&acl_roles, (uchar*) acl_role);
DBUG_RETURN(1);
}
- acl_role->user.str= strdup_root(&acl_memroot, user_to->user.str);
- acl_role->user.length= user_to->user.length;
+ acl_role->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
my_hash_update(&acl_roles, (uchar*) acl_role, (uchar*) old_key,
old_key_length);
@@ -9706,8 +9491,6 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
default:
DBUG_ASSERT(0);
}
- if (! user)
- user= "";
if (! host)
host= "";
@@ -9801,8 +9584,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
{
switch ( struct_no ) {
case USER_ACL:
- acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
- acl_user->user.length= user_to->user.length;
+ acl_user->user= safe_lexcstrdup_root(&acl_memroot, user_to->user);
update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
@@ -10185,13 +9967,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
if (!user_name->host.str)
user_name->host= host_not_specified;
- if (fix_lex_user(thd, user_name))
- {
- append_user(thd, &wrong_users, user_name);
- result= TRUE;
- continue;
- }
-
/*
Search all in-memory structures and grant tables
for a mention of the new user/role name.
@@ -10234,7 +10009,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
}
}
- if (replace_user_table(thd, tables.user_table(), *user_name, 0, 0, 1, 0))
+ if (replace_user_table(thd, tables.user_table(), user_name, 0, 0, 1, 0))
{
append_user(thd, &wrong_users, user_name);
result= TRUE;
@@ -10523,10 +10298,8 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list)
while ((tmp_lex_user= users_list_iterator++))
{
LEX_USER* lex_user= get_current_user(thd, tmp_lex_user, false);
- if (!lex_user ||
- fix_lex_user(thd, lex_user) ||
- replace_user_table(thd, tables.user_table(), *lex_user, 0,
- false, false, true))
+ if (!lex_user || replace_user_table(thd, tables.user_table(), lex_user, 0,
+ false, false, true))
{
thd->clear_error();
append_user(thd, &wrong_users, tmp_lex_user);
@@ -10575,7 +10348,7 @@ mysql_revoke_sp_privs(THD *thd,
{
const char *user,*host;
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
- user= safe_str(grant_proc->user);
+ user= grant_proc->user;
host= safe_str(grant_proc->host.hostname);
if (!strcmp(lex_user->user.str, user) &&
@@ -10650,7 +10423,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
continue;
}
- if (replace_user_table(thd, tables.user_table(), *lex_user,
+ if (replace_user_table(thd, tables.user_table(), lex_user,
~(ulong)0, 1, 0, 0))
{
result= -1;
@@ -10671,7 +10444,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host= safe_str(acl_db->host.hostname);
if (!strcmp(lex_user->user.str, user) &&
@@ -10703,7 +10476,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
const char *user,*host;
GRANT_TABLE *grant_table=
(GRANT_TABLE*) my_hash_element(&column_priv_hash, counter);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (!strcmp(lex_user->user.str,user) &&
@@ -11313,7 +11086,7 @@ bool check_role_is_granted(const char *username,
ACL_USER_BASE *root;
mysql_mutex_lock(&acl_cache->lock);
if (hostname)
- root= find_user_exact(username, hostname);
+ root= find_user_exact(hostname, username);
else
root= find_acl_role(username);
@@ -11487,7 +11260,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
{
const char *user,*host, *is_grantable="YES";
acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
- user= safe_str(acl_user->user.str);
+ user= acl_user->user.str;
host= safe_str(acl_user->host.hostname);
if (no_global_access &&
@@ -11561,7 +11334,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable="YES";
acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
- user= safe_str(acl_db->user);
+ user= acl_db->user;
host= safe_str(acl_db->host.hostname);
if (no_global_access &&
@@ -11633,7 +11406,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (no_global_access &&
@@ -11715,7 +11488,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
const char *user, *host, *is_grantable= "YES";
GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
index);
- user= safe_str(grant_table->user);
+ user= grant_table->user;
host= safe_str(grant_table->host.hostname);
if (no_global_access &&
@@ -12299,8 +12072,9 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
user account, it's the plugin that the client need to use to login.
*/
bool switch_from_long_to_short_scramble=
- native_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
- client_auth_plugin == old_password_plugin_name.str;
+ client_auth_plugin == old_password_plugin_name.str &&
+ my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
+ native_password_plugin_name.str) == 0;
if (switch_from_long_to_short_scramble)
DBUG_RETURN (secure_auth(mpvio->auth_info.thd) ||
@@ -12313,8 +12087,9 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
ask an old 4.0 client to use the new 4.1 authentication protocol.
*/
bool switch_from_short_to_long_scramble=
- old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
- client_auth_plugin == native_password_plugin_name.str;
+ client_auth_plugin == native_password_plugin_name.str &&
+ my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
+ old_password_plugin_name.str) == 0;
if (switch_from_short_to_long_scramble)
{
@@ -12404,9 +12179,9 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
mpvio->auth_info.user_name= sctx->user;
mpvio->auth_info.user_name_length= (uint)strlen(sctx->user);
- mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
- mpvio->auth_info.auth_string_length= (unsigned long) mpvio->acl_user->auth_string.length;
- strmake_buf(mpvio->auth_info.authenticated_as, safe_str(mpvio->acl_user->user.str));
+ mpvio->auth_info.auth_string= mpvio->acl_user->salt.str;
+ mpvio->auth_info.auth_string_length= (unsigned long) mpvio->acl_user->salt.length;
+ strmake_buf(mpvio->auth_info.authenticated_as, mpvio->acl_user->user.str);
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
"plugin=%s",
@@ -12557,7 +12332,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
MYF(0));
DBUG_RETURN(1);
}
- client_plugin= fix_plugin_ptr(next_field);
+ client_plugin= next_field;
next_field+= strlen(next_field) + 1;
}
else
@@ -12802,7 +12577,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if ((thd->client_capabilities & CLIENT_PLUGIN_AUTH) &&
(client_plugin < (char *)net->read_pos + pkt_len))
{
- client_plugin= fix_plugin_ptr(client_plugin);
next_field+= strlen(next_field) + 1;
}
else
@@ -13141,17 +12915,7 @@ static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
{
int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
bool unlock_plugin= false;
- plugin_ref plugin= NULL;
-
- if (auth_plugin_name->str == native_password_plugin_name.str)
- plugin= native_password_plugin;
-#ifndef EMBEDDED_LIBRARY
- else if (auth_plugin_name->str == old_password_plugin_name.str)
- plugin= old_password_plugin;
- else if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
- MYSQL_AUTHENTICATION_PLUGIN)))
- unlock_plugin= true;
-#endif
+ plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
mpvio->plugin= plugin;
old_status= mpvio->status;
@@ -13339,7 +13103,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool is_proxy_user= FALSE;
- const char *auth_user = safe_str(acl_user->user.str);
+ const char *auth_user = acl_user->user.str;
ACL_PROXY_USER *proxy_user;
/* check if the user is allowed to proxy as another user */
proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip,
@@ -13385,10 +13149,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
#endif
sctx->master_access= acl_user->access;
- if (acl_user->user.str)
- strmake_buf(sctx->priv_user, acl_user->user.str);
- else
- *sctx->priv_user= 0;
+ strmake_buf(sctx->priv_user, acl_user->user.str);
if (acl_user->host.hostname)
strmake_buf(sctx->priv_host, acl_user->host.hostname);
@@ -13600,15 +13361,16 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
DBUG_EXECUTE_IF("native_password_bad_reply", { pkt_len= 12; });
if (pkt_len == 0) /* no password */
- DBUG_RETURN(mpvio->acl_user->salt_len != 0 ? CR_AUTH_USER_CREDENTIALS : CR_OK);
+ DBUG_RETURN(info->auth_string_length != 0
+ ? CR_AUTH_USER_CREDENTIALS : CR_OK);
info->password_used= PASSWORD_USED_YES;
if (pkt_len == SCRAMBLE_LENGTH)
{
- if (!mpvio->acl_user->salt_len)
+ if (!info->auth_string_length)
DBUG_RETURN(CR_AUTH_USER_CREDENTIALS);
- if (check_scramble(pkt, thd->scramble, mpvio->acl_user->salt))
+ if (check_scramble(pkt, thd->scramble, (uchar*)info->auth_string))
DBUG_RETURN(CR_AUTH_USER_CREDENTIALS);
else
DBUG_RETURN(CR_OK);
@@ -13618,6 +13380,41 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
DBUG_RETURN(CR_AUTH_HANDSHAKE);
}
+static int native_password_make_scramble(const char *password,
+ size_t password_length, char *hash, size_t *hash_length)
+{
+ DBUG_ASSERT(*hash_length >= SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ if (password_length == 0)
+ *hash_length= 0;
+ else
+ {
+ *hash_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ my_make_scrambled_password(hash, password, password_length);
+ }
+ return 0;
+}
+
+static int native_password_get_salt(const char *hash, size_t hash_length,
+ unsigned char *out, size_t *out_length)
+{
+ DBUG_ASSERT(*out_length >= SCRAMBLE_LENGTH);
+ if (hash_length == 0)
+ {
+ *out_length= 0;
+ return 0;
+ }
+
+ if (hash_length != SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ return 1;
+ }
+
+ *out_length= SCRAMBLE_LENGTH;
+ get_salt_from_password(out, hash);
+ return 0;
+}
+
static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
MYSQL_SERVER_AUTH_INFO *info)
{
@@ -13661,30 +13458,64 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (pkt_len == SCRAMBLE_LENGTH_323)
{
- if (!mpvio->acl_user->salt_len)
+ if (!info->auth_string_length)
return CR_AUTH_USER_CREDENTIALS;
- return check_scramble_323(pkt, thd->scramble,
- (ulong *) mpvio->acl_user->salt) ?
- CR_AUTH_USER_CREDENTIALS : CR_OK;
+ return check_scramble_323(pkt, thd->scramble, (ulong *) info->auth_string)
+ ? CR_AUTH_USER_CREDENTIALS : CR_OK;
}
my_error(ER_HANDSHAKE_ERROR, MYF(0));
return CR_AUTH_HANDSHAKE;
}
+static int old_password_make_scramble(const char *password,
+ size_t password_length, char *hash, size_t *hash_length)
+{
+ DBUG_ASSERT(*hash_length >= SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
+ if (password_length == 0)
+ *hash_length= 0;
+ else
+ {
+ *hash_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ my_make_scrambled_password_323(hash, password, password_length);
+ }
+ return 0;
+}
+
+#define SALT_LENGTH_323 (sizeof(ulong)*2)
+static int old_password_get_salt(const char *hash, size_t hash_length,
+ unsigned char *out, size_t *out_length)
+{
+ DBUG_ASSERT(*out_length >= SALT_LENGTH_323);
+
+ if (hash_length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ {
+ my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH_323);
+ return 1;
+ }
+
+ *out_length= SALT_LENGTH_323;
+ get_salt_from_password_323((ulong*)out, hash);
+ return 0;
+}
+
static struct st_mysql_auth native_password_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
native_password_plugin_name.str,
- native_password_authenticate
+ native_password_authenticate,
+ native_password_make_scramble,
+ native_password_get_salt
};
static struct st_mysql_auth old_password_handler=
{
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
old_password_plugin_name.str,
- old_password_authenticate
+ old_password_authenticate,
+ old_password_make_scramble,
+ old_password_get_salt
};
maria_declare_plugin(mysql_password)
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index c17567e6a89..d0d959de8f9 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,11 +1321,13 @@ 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:
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
@@ -1333,7 +1335,7 @@ WSREP_ERROR_LABEL:
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");
@@ -1346,7 +1348,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:
@@ -1357,7 +1359,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");
@@ -1379,11 +1381,13 @@ 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:
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
@@ -1391,7 +1395,7 @@ WSREP_ERROR_LABEL:
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");
@@ -1415,10 +1419,12 @@ 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:
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
DBUG_RETURN(res);
}
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 5fc9ff8209c..05a71d7785d 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;
/*
@@ -497,16 +497,17 @@ bool Sql_cmd_alter_table::execute(THD *thd)
lex->ignore);
DBUG_RETURN(result);
-
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
WSREP_WARN("ALTER TABLE isolation failure");
DBUG_RETURN(TRUE);
+#endif
}
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 52259e4b9e2..7b466bc9c74 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -598,6 +598,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 ||
@@ -608,6 +609,7 @@ static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
table->file->ha_reset();
}
}
+ DBUG_VOID_RETURN;
}
@@ -4295,7 +4297,9 @@ restart:
}
error:
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
THD_STAGE_INFO(thd, stage_after_opening_tables);
thd_proc_info(thd, 0);
@@ -5471,43 +5475,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)
@@ -7437,7 +7425,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,
@@ -7545,7 +7533,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)
{
@@ -7573,7 +7561,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)
@@ -7940,18 +7928,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;
@@ -8129,7 +8108,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;
@@ -8145,7 +8124,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))
@@ -8752,7 +8731,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.
@@ -8854,6 +8833,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);
}
@@ -8987,7 +8973,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 22247af07a8..0ebed4159ab 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -371,10 +371,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_basic_types.h b/sql/sql_basic_types.h
index 1e97262cdf0..362ab0f1259 100644
--- a/sql/sql_basic_types.h
+++ b/sql/sql_basic_types.h
@@ -22,4 +22,87 @@
typedef ulonglong sql_mode_t;
typedef int64 query_id_t;
+
+
+/*
+ "fuzzydate" with strict data type control.
+ Please keep "explicit" in constructors and conversion methods.
+*/
+class date_mode_t
+{
+public:
+ enum value_t
+ {
+ FUZZY_DATES= 1U, // C_TIME_FUZZY_DATES
+ TIME_ONLY= 4U, // C_TIME_TIME_ONLY
+ NO_ZERO_IN_DATE= (1UL << 23), // MODE_NO_ZERO_IN_DATE
+ NO_ZERO_DATE= (1UL << 24), // MODE_NO_ZERO_DATE
+ INVALID_DATES= (1UL << 25) // MODE_INVALID_DATES
+ };
+
+private:
+ value_t m_mode;
+public:
+
+ // Constructors
+ explicit date_mode_t(ulonglong fuzzydate)
+ :m_mode((value_t) fuzzydate)
+ { }
+
+ // Conversion operators
+ explicit operator ulonglong() const
+ {
+ return m_mode;
+ }
+ explicit operator bool() const
+ {
+ return m_mode != 0;
+ }
+
+ // Unary operators
+ date_mode_t operator~() const
+ {
+ return date_mode_t(~m_mode);
+ }
+
+ // Dyadic bitwise operators
+ date_mode_t operator&(const date_mode_t &other) const
+ {
+ return date_mode_t(m_mode & other.m_mode);
+ }
+
+ date_mode_t operator|(const date_mode_t &other) const
+ {
+ return date_mode_t(m_mode | other.m_mode);
+ }
+
+ // Dyadic bitwise assignment operators
+ date_mode_t &operator&=(const date_mode_t &other)
+ {
+ m_mode= value_t(m_mode & other.m_mode);
+ return *this;
+ }
+
+ date_mode_t &operator|=(const date_mode_t &other)
+ {
+ m_mode= value_t(m_mode | other.m_mode);
+ return *this;
+ }
+};
+
+
+const date_mode_t
+ TIME_FUZZY_DATES (date_mode_t::value_t::FUZZY_DATES),
+ TIME_TIME_ONLY (date_mode_t::value_t::TIME_ONLY),
+ TIME_NO_ZERO_IN_DATE (date_mode_t::value_t::NO_ZERO_IN_DATE),
+ TIME_NO_ZERO_DATE (date_mode_t::value_t::NO_ZERO_DATE),
+ TIME_INVALID_DATES (date_mode_t::value_t::INVALID_DATES);
+
+// Flags understood by str_to_datetime, str_to_time, number_to_time, check_date
+static const date_mode_t
+ TIME_MODE_FOR_XXX_TO_DATE (date_mode_t::NO_ZERO_IN_DATE |
+ date_mode_t::NO_ZERO_DATE |
+ date_mode_t::INVALID_DATES |
+ date_mode_t::TIME_ONLY);
+
#endif
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 e4f3171bd14..52ebc186b1a 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1411,7 +1411,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;
}
@@ -2570,7 +2570,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;
@@ -3225,9 +3225,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;
}
@@ -3485,7 +3485,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)
@@ -3592,18 +3592,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()
@@ -7712,7 +7709,7 @@ Query_arena_stmt::~Query_arena_stmt()
bool THD::timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
- ulong sec_part, ulonglong fuzzydate)
+ ulong sec_part, date_mode_t fuzzydate)
{
time_zone_used= 1;
if (ts == 0 && sec_part == 0)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index acd48b07900..d8f0a794222 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
@@ -3406,7 +3410,7 @@ public:
}
const Type_handler *type_handler_for_date() const;
bool timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
- ulong sec_part, ulonglong fuzzydate);
+ ulong sec_part, date_mode_t fuzzydate);
inline my_time_t query_start() { return start_time; }
inline ulong query_start_sec_part()
{ query_start_sec_part_used=1; return start_time_sec_part; }
@@ -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);
@@ -4886,10 +4953,17 @@ my_eof(THD *thd)
(A)->variables.sql_log_bin_off= 0;}
-inline sql_mode_t sql_mode_for_dates(THD *thd)
+inline date_mode_t sql_mode_for_dates(THD *thd)
{
- return thd->variables.sql_mode &
- (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES);
+ static_assert(C_TIME_FUZZY_DATES == date_mode_t::FUZZY_DATES &&
+ C_TIME_TIME_ONLY == date_mode_t::TIME_ONLY,
+ "sql_mode_t and pure C library date flags must be equal");
+ static_assert(MODE_NO_ZERO_DATE == date_mode_t::NO_ZERO_DATE &&
+ MODE_NO_ZERO_IN_DATE == date_mode_t::NO_ZERO_IN_DATE &&
+ MODE_INVALID_DATES == date_mode_t::INVALID_DATES,
+ "sql_mode_t and date_mode_t values must be equal");
+ return date_mode_t(thd->variables.sql_mode &
+ (MODE_NO_ZERO_DATE | MODE_NO_ZERO_IN_DATE | MODE_INVALID_DATES));
}
/*
@@ -6325,7 +6399,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 b05a688f40e..a1af2b6ebbb 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;
}
@@ -772,7 +780,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;
}
@@ -855,10 +863,9 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
lex->sp_chistics= old_lex->sp_chistics;
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);
((char*) &unparsed_spec.str[unparsed_spec.length])[0]= save_end;
+ with_select= lex->first_select_lex();
if (parse_status)
goto err;
@@ -1011,7 +1018,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;
}
@@ -1122,7 +1129,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 bda62271649..03c697bf746 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -292,8 +292,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
@@ -317,9 +316,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)
{ }
@@ -333,8 +331,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();
@@ -367,7 +369,6 @@ bool With_element::is_unrestricted()
}
inline
-
bool With_element::is_with_prepared_anchor()
{
return owner->with_prepared_anchor & get_elem_map();
@@ -449,11 +450,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 fc400252397..3ae113a4595 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 589d0214292..878aa715b84 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;
@@ -1242,25 +1243,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)
@@ -1300,63 +1337,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
@@ -1367,71 +1366,43 @@ 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_error.h b/sql/sql_error.h
index 822503f89d3..b783d527cb3 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -846,8 +846,8 @@ public:
class ErrConvInteger : public ErrConv, public Longlong_hybrid
{
public:
- ErrConvInteger(longlong num_arg, bool unsigned_flag= false) :
- ErrConv(), Longlong_hybrid(num_arg, unsigned_flag) {}
+ ErrConvInteger(const Longlong_hybrid &nr)
+ : ErrConv(), Longlong_hybrid(nr) { }
const char *ptr() const
{
return m_unsigned ? ullstr(m_value, err_buffer) :
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 6e2fa5767f5..127b4b10eb4 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;
}
@@ -2605,10 +2607,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;
@@ -2627,15 +2625,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,
@@ -3261,7 +3250,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;
}
@@ -3434,7 +3423,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;
}
@@ -3530,7 +3519,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");
@@ -3619,7 +3608,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) ||
@@ -3636,7 +3625,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. */
@@ -3646,7 +3635,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,
@@ -3657,15 +3646,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.
@@ -4081,9 +4070,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 11bb50a4231..ba8ed192c97 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,18 +683,19 @@ 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;
clone_spec_offset= 0;
create_view= NULL;
+ field_list.empty();
value_list.empty();
update_list.empty();
set_var_list.empty();
@@ -684,17 +709,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;
@@ -704,14 +720,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;
@@ -723,6 +732,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;
@@ -732,8 +743,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;
@@ -757,6 +768,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;
}
@@ -1273,7 +1291,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)
{
/*
@@ -1290,6 +1309,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:
/*
@@ -1338,8 +1359,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);
@@ -1353,6 +1382,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;
@@ -1689,7 +1755,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
@@ -1700,7 +1766,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();
@@ -2208,8 +2274,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;
}
@@ -2217,7 +2283,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;
@@ -2259,16 +2325,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();
@@ -2314,16 +2370,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;
@@ -2385,6 +2439,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)
@@ -2434,7 +2505,7 @@ void st_select_lex_node::fast_exclude()
// Remove slave structure
for (; slave; slave= slave->next)
slave->fast_exclude();
-
+
}
@@ -2908,8 +2979,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("''"));
@@ -3104,6 +3174,7 @@ LEX::LEX()
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
+ unit.slave= &builtin_select;
}
@@ -3130,12 +3201,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())
{
@@ -3152,12 +3223,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);
}
@@ -3510,7 +3581,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)
{
@@ -3566,12 +3637,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
@@ -3602,7 +3674,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;
@@ -3627,6 +3699,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()
@@ -3652,10 +3741,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
}
}
}
@@ -3684,19 +3773,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();
}
}
@@ -4351,7 +4440,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;
@@ -4360,8 +4449,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;
}
}
@@ -4562,7 +4649,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";
}
@@ -4757,8 +4844,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);
@@ -5089,8 +5176,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);
@@ -5101,89 +5193,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);
}
@@ -5198,7 +5456,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)
{
@@ -5648,10 +5906,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))
@@ -5758,10 +6023,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->
@@ -6682,7 +6959,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());
@@ -6713,6 +6989,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)
@@ -6735,12 +7043,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);
}
@@ -6952,12 +7259,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);
}
@@ -6990,11 +7296,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;
}
@@ -7024,11 +7328,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;
}
@@ -7048,15 +7349,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);
}
@@ -7106,6 +7412,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);
}
@@ -7399,8 +7710,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);
}
}
@@ -7431,8 +7742,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)
@@ -7445,7 +7755,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++;
@@ -7494,7 +7804,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
@@ -7570,6 +7880,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)
{
@@ -7624,10 +8068,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;
@@ -7920,6 +8364,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)
{
@@ -8186,9 +8754,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 48363fdd670..618214dbb9c 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;
@@ -2892,6 +3024,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;}
@@ -2919,6 +3057,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;
@@ -2958,6 +3098,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
@@ -3012,7 +3154,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
@@ -3211,20 +3363,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();
@@ -3262,14 +3418,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);
@@ -3278,6 +3503,7 @@ public:
{
return context_stack.head();
}
+
/*
Restore the LEX and THD in case of a parse error.
*/
@@ -3306,9 +3532,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;
@@ -3347,9 +3572,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,
@@ -3474,7 +3696,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)
@@ -3612,6 +3839,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);
@@ -3806,6 +4037,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);
@@ -3928,7 +4170,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,
@@ -3936,7 +4178,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);
@@ -3955,7 +4196,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));
@@ -3973,6 +4214,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 d6473d58821..1f9cd305847 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -109,6 +109,7 @@
#include "../storage/maria/ha_maria.h"
#endif
+#include "wsrep.h"
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
@@ -2008,10 +2009,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 +2576,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 +2632,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);
@@ -3008,7 +3011,7 @@ static int mysql_create_routine(THD *thd, LEX *lex)
if (sp_process_definer(thd))
return true;
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -3077,7 +3080,9 @@ static int mysql_create_routine(THD *thd, LEX *lex)
#endif
return false;
}
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
return true;
}
@@ -3225,7 +3230,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 */
@@ -3264,6 +3269,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 */
@@ -6296,8 +6302,10 @@ end_with_restore_list:
goto finish;
error:
-WSREP_ERROR_LABEL:
- res= TRUE;
+#ifdef WITH_WSREP
+wsrep_error_label:
+#endif
+ res= true;
finish:
@@ -7520,7 +7528,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;
@@ -7590,16 +7598,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.
@@ -7685,11 +7698,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;
}
@@ -7710,6 +7719,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)
@@ -7721,27 +7731,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);
/*
@@ -7775,15 +7777,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=
@@ -7839,9 +7839,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;
}
@@ -8157,7 +8158,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();
}
@@ -8239,6 +8240,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
@@ -8332,7 +8337,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.
@@ -8439,8 +8444,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)";
@@ -8548,7 +8551,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);
}
@@ -8740,7 +8742,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()))
@@ -8750,16 +8752,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())
{
@@ -8772,7 +8777,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);
}
@@ -8808,7 +8813,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);
}
@@ -9237,7 +9242,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)
@@ -9273,7 +9278,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)
@@ -9307,7 +9312,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");
@@ -9424,7 +9429,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");
@@ -9466,7 +9471,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);
@@ -9557,7 +9563,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
@@ -9588,7 +9594,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");
@@ -9730,8 +9736,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
@@ -10099,6 +10106,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 151b94d1187..95d14d9ab0d 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
@@ -1563,7 +1559,7 @@ static bool check_vers_constants(THD *thd, partition_info *part_info)
my_tz_OFFSET0->gmt_sec_to_TIME(&ltime, vers_info->interval.start);
while ((el= it++)->id < hist_parts)
{
- if (date_add_interval(&ltime, vers_info->interval.type,
+ if (date_add_interval(thd, &ltime, vers_info->interval.type,
vers_info->interval.step))
goto err;
uint error= 0;
@@ -2656,7 +2652,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)
@@ -6003,7 +5999,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))
@@ -8221,7 +8217,7 @@ static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
field->type() == MYSQL_TYPE_DATETIME))
{
/* Monotonic, but return NULL for dates with zeros in month/day. */
- zero_in_start_date= field->get_date(&start_date, 0);
+ zero_in_start_date= field->get_date(&start_date, date_mode_t(0));
DBUG_PRINT("info", ("zero start %u %04d-%02d-%02d",
zero_in_start_date, start_date.year,
start_date.month, start_date.day));
@@ -8245,7 +8241,7 @@ static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
!part_info->part_expr->null_value)
{
MYSQL_TIME end_date;
- bool zero_in_end_date= field->get_date(&end_date, 0);
+ bool zero_in_end_date= field->get_date(&end_date, date_mode_t(0));
/*
This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
the NULL partition for ranges that cannot include a date with 0 as
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 2d3c640b758..71ab7477391 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_plugin.cc b/sql/sql_plugin.cc
index b2ceb1627a1..d448b7b9e02 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -280,6 +280,7 @@ struct st_mysql_sys_var
MYSQL_PLUGIN_VAR_HEADER;
};
+enum install_status { INSTALL_GOOD, INSTALL_FAIL_WARN_OK, INSTALL_FAIL_NOT_OK };
/*
sys_var class for access to all plugin variables visible to the user
*/
@@ -1077,7 +1078,7 @@ static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
NOTE
Requires that a write-lock is held on LOCK_system_variables_hash
*/
-static bool plugin_add(MEM_ROOT *tmp_root,
+static enum install_status plugin_add(MEM_ROOT *tmp_root, bool if_not_exists,
const LEX_CSTRING *name, LEX_CSTRING *dl, myf MyFlags)
{
struct st_plugin_int tmp, *maybe_dupe;
@@ -1088,14 +1089,16 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
{
+ if (if_not_exists)
+ MyFlags|= ME_NOTE;
my_error(ER_PLUGIN_INSTALLED, MyFlags, name->str);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(if_not_exists ? INSTALL_FAIL_WARN_OK : INSTALL_FAIL_NOT_OK);
}
/* Clear the whole struct to catch future extensions. */
bzero((char*) &tmp, sizeof(tmp));
fix_dl_name(tmp_root, dl);
if (! (tmp.plugin_dl= plugin_dl_add(dl, MyFlags)))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
/* Find plugin by name */
for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++)
{
@@ -1121,7 +1124,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
if (plugin->name != maybe_dupe->plugin->name)
{
my_error(ER_UDF_EXISTS, MyFlags, plugin->name);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
}
dupes++;
continue; // already installed
@@ -1173,7 +1176,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
init_alloc_root(&tmp_plugin_ptr->mem_root, "plugin", 4096, 4096, MYF(0));
if (name->str)
- DBUG_RETURN(FALSE); // all done
+ DBUG_RETURN(INSTALL_GOOD); // all done
oks++;
tmp.plugin_dl->ref_count++;
@@ -1191,7 +1194,9 @@ err:
my_error(ER_CANT_FIND_DL_ENTRY, MyFlags, name->str);
plugin_dl_del(tmp.plugin_dl);
- DBUG_RETURN(errs > 0 || oks + dupes == 0);
+ if (errs > 0 || oks + dupes == 0)
+ DBUG_RETURN(INSTALL_FAIL_NOT_OK);
+ DBUG_RETURN(INSTALL_GOOD);
}
static void plugin_variables_deinit(struct st_plugin_int *plugin)
@@ -1847,7 +1852,7 @@ static void plugin_load(MEM_ROOT *tmp_root)
the mutex here to satisfy the assert
*/
mysql_mutex_lock(&LOCK_plugin);
- plugin_add(tmp_root, &name, &dl, MYF(ME_ERROR_LOG));
+ plugin_add(tmp_root, false, &name, &dl, MYF(ME_ERROR_LOG));
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_unlock(&LOCK_plugin);
}
@@ -1870,7 +1875,7 @@ end:
static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
{
char buffer[FN_REFLEN];
- LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
+ LEX_CSTRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
char *p= buffer;
DBUG_ENTER("plugin_load_list");
while (list)
@@ -1889,7 +1894,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
#ifndef __WIN__
case ':': /* can't use this as delimiter as it may be drive letter */
#endif
- str->str[str->length]= '\0';
+ p[-1]= 0;
if (str == &name) // load all plugins in named module
{
if (!name.length)
@@ -1902,16 +1907,16 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
mysql_mutex_lock(&LOCK_plugin);
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
name.str= 0; // load everything
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
else
{
free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
mysql_mutex_lock(&LOCK_plugin);
- if (plugin_add(tmp_root, (LEX_CSTRING*) &name, (LEX_CSTRING*) &dl,
- MYF(ME_ERROR_LOG)))
+ if (plugin_add(tmp_root, false, &name, &dl,
+ MYF(ME_ERROR_LOG)) != INSTALL_GOOD)
goto error;
}
mysql_mutex_unlock(&LOCK_plugin);
@@ -1923,7 +1928,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
case '#':
if (str == &name)
{
- name.str[name.length]= '\0';
+ p[-1]= 0;
str= &dl;
str->str= p;
continue;
@@ -2146,7 +2151,7 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
TABLE_LIST tables;
TABLE *table;
LEX_CSTRING dl= *dl_arg;
- bool error;
+ enum install_status error;
int argc=orig_argc;
char **argv=orig_argv;
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
@@ -2194,12 +2199,14 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
mysql_audit_acquire_plugins(thd, event_class_mask);
mysql_mutex_lock(&LOCK_plugin);
- error= plugin_add(thd->mem_root, name, &dl, MYF(0));
- if (unlikely(error))
+ error= plugin_add(thd->mem_root, thd->lex->create_info.if_not_exists(),
+ name, &dl, MYF(0));
+ if (unlikely(error != INSTALL_GOOD))
goto err;
if (name->str)
- error= finalize_install(thd, table, name, &argc, argv);
+ error= finalize_install(thd, table, name, &argc, argv)
+ ? INSTALL_FAIL_NOT_OK : INSTALL_GOOD;
else
{
st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
@@ -2207,11 +2214,12 @@ bool mysql_install_plugin(THD *thd, const LEX_CSTRING *name,
for (plugin= plugin_dl->plugins; plugin->info; plugin++)
{
LEX_CSTRING str= { plugin->name, strlen(plugin->name) };
- error|= finalize_install(thd, table, &str, &argc, argv);
+ if (finalize_install(thd, table, &str, &argc, argv))
+ error= INSTALL_FAIL_NOT_OK;
}
}
- if (unlikely(error))
+ if (unlikely(error != INSTALL_GOOD))
{
reap_needed= true;
reap_plugins();
@@ -2220,10 +2228,11 @@ err:
mysql_mutex_unlock(&LOCK_plugin);
if (argv)
free_defaults(argv);
- DBUG_RETURN(error);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(error == INSTALL_FAIL_NOT_OK);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
@@ -2235,8 +2244,9 @@ static bool do_uninstall(THD *thd, TABLE *table, const LEX_CSTRING *name)
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) ||
plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING))
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
- return 1;
+ myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "PLUGIN", name->str);
+ return !MyFlags;
}
if (!plugin->plugin_dl)
{
@@ -2299,7 +2309,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
DBUG_RETURN(TRUE);
- WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
+ WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
/* need to open before acquiring LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
@@ -2358,17 +2368,19 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_CSTRING *name,
}
else
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SONAME", dl.str);
- error= true;
+ myf MyFlags= thd->lex->if_exists() ? ME_NOTE : 0;
+ my_error(ER_SP_DOES_NOT_EXIST, MyFlags, "SONAME", dl.str);
+ error|= !MyFlags;
}
}
reap_plugins();
mysql_mutex_unlock(&LOCK_plugin);
DBUG_RETURN(error);
-
-WSREP_ERROR_LABEL:
- DBUG_RETURN(TRUE);
+#ifdef WITH_WSREP
+wsrep_error_label:
+ DBUG_RETURN(true);
+#endif
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index c4871bdcc80..09d31470a00 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1354,7 +1354,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
@@ -1410,10 +1410,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
@@ -1478,10 +1478,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);
@@ -1513,7 +1513,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)
@@ -1526,7 +1526,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;
}
@@ -1547,7 +1547,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))
@@ -1705,7 +1705,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);
@@ -1773,7 +1773,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;
@@ -2093,11 +2093,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;
}
@@ -2132,13 +2132,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);
}
@@ -2173,7 +2174,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=
@@ -2181,7 +2182,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;
}
@@ -2207,7 +2208,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
@@ -2217,7 +2218,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())
@@ -2256,7 +2257,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;
@@ -2265,10 +2266,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 */
@@ -3033,7 +3035,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)
@@ -4571,8 +4573,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;
@@ -4729,7 +4731,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;
}
/*
@@ -5309,16 +5311,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 f1230666026..1780df61e56 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -354,7 +354,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());
@@ -1051,7 +1051,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;
@@ -1219,14 +1219,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)
@@ -1396,6 +1396,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;
@@ -1413,8 +1414,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++)
@@ -1432,7 +1432,7 @@ bool JOIN::build_explain()
get_using_temporary_read_tracker();
}
}
- return 0;
+ DBUG_RETURN(0);
}
@@ -1597,7 +1597,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);
@@ -1641,7 +1641,7 @@ JOIN::optimize_inner()
if (arena)
thd->restore_active_arena(arena, &backup);
}
-
+
if (optimize_constant_subqueries())
DBUG_RETURN(1);
@@ -1652,9 +1652,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);
@@ -1685,6 +1704,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;
@@ -1991,7 +2035,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)
@@ -2130,7 +2174,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. */
@@ -2413,13 +2457,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);
@@ -3753,6 +3797,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
@@ -3779,8 +3832,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);
}
/*
@@ -3802,11 +3856,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);
}
@@ -4163,10 +4217,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
@@ -4858,7 +4912,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;
@@ -10620,7 +10674,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
}
}
@@ -10748,7 +10802,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,
@@ -12757,7 +12811,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
@@ -13049,7 +13104,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;
@@ -13140,7 +13195,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
@@ -13316,7 +13371,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)
@@ -13565,9 +13620,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;
@@ -14020,7 +14075,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++))
@@ -14127,7 +14182,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()))
@@ -14518,7 +14573,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;
@@ -14526,7 +14581,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 &&
@@ -14647,13 +14702,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
@@ -14665,10 +14720,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:
@@ -14810,7 +14865,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
@@ -14835,7 +14890,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;
}
@@ -15349,7 +15404,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
@@ -16417,9 +16472,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) */
/*
@@ -16435,7 +16489,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;
@@ -16505,7 +16559,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);
@@ -16665,60 +16719,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;
@@ -16728,6 +16728,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)
{
@@ -16759,57 +16775,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.
@@ -16847,19 +16812,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
@@ -16868,175 +16996,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;
}
/*
@@ -17052,7 +17033,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);
@@ -17317,7 +17298,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();
@@ -17347,7 +17328,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);
@@ -17397,7 +17378,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.
@@ -17411,7 +17392,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 &&
@@ -17425,8 +17406,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
@@ -18007,12 +17987,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);
}
@@ -18132,7 +18110,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++)
{
@@ -18555,7 +18533,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;
@@ -18578,7 +18556,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))
@@ -22729,7 +22707,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;
}
@@ -23004,12 +22982,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)
@@ -23123,7 +23096,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) ||
@@ -23233,7 +23206,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;
@@ -23392,7 +23365,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
@@ -23489,9 +23462,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();
}
}
}
@@ -23631,7 +23606,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;
@@ -23641,7 +23616,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++;
@@ -23895,7 +23870,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:
@@ -24102,7 +24077,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)
{
@@ -24410,7 +24385,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);
@@ -24629,7 +24604,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;
@@ -25117,7 +25092,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)
@@ -25570,8 +25546,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 */
@@ -25597,7 +25574,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 */
@@ -25620,7 +25597,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";
@@ -25643,7 +25620,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;
@@ -25787,7 +25764,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))
@@ -26226,6 +26203,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(" */ ");
}
@@ -26257,18 +26246,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 0e486c1fbec..e2c78473b1a 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1477,6 +1477,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)
@@ -1572,6 +1577,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 */
@@ -1751,6 +1757,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
@@ -1815,10 +1822,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 */
@@ -2070,12 +2073,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
@@ -2343,7 +2340,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);
}
@@ -2459,4 +2456,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 426f40d1729..b98f8aabdc1 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)
{
@@ -6713,7 +6720,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;
@@ -7366,7 +7373,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();
@@ -7728,9 +7735,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)
@@ -8224,7 +8231,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,
@@ -8261,7 +8268,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)
@@ -8321,14 +8328,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(" ("));
@@ -8361,7 +8368,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++)
{
@@ -8392,7 +8399,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++)
{
@@ -8419,7 +8426,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 cc77452ecd1..39d9438d5bf 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 23783405b19..0ae68cb3796 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -762,6 +762,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 b9fc431feb1..3e204c4945b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4248,11 +4248,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),
@@ -4877,7 +4875,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;
}
@@ -9550,8 +9548,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.
@@ -9581,7 +9577,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));
@@ -10102,19 +10097,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. */
@@ -10122,9 +10115,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;
}
@@ -10253,10 +10247,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();
@@ -10286,7 +10277,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
{
@@ -10329,8 +10324,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;
@@ -10355,6 +10350,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();
@@ -10704,7 +10704,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..630d150be77 100644
--- a/sql/sql_time.cc
+++ b/sql/sql_time.cc
@@ -175,7 +175,7 @@ int calc_weekday(long daynr,bool sunday_first_day_of_week)
next week is week 1.
*/
-uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
+uint calc_week(const MYSQL_TIME *l_time, uint week_behaviour, uint *year)
{
uint days;
ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
@@ -289,14 +289,14 @@ ulong convert_month_to_period(ulong month)
bool
-check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_mode_t fuzzydate,
timestamp_type ts_type)
{
int unused;
- if (check_date(ltime, fuzzy_date, &unused))
+ if (check_date(ltime, fuzzydate, &unused))
{
ErrConvTime str(ltime);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
&str, ts_type, 0);
return true;
}
@@ -305,7 +305,7 @@ check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
bool
-adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec)
+adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec)
{
MYSQL_TIME copy= *ltime;
ErrConvTime str(&copy);
@@ -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);
+ thd->push_warning_truncated_wrong_value("time", str.ptr());
return false;
}
@@ -352,33 +351,57 @@ to_ascii(CHARSET_INFO *cs,
}
-/* Character set-aware version of str_to_time() */
-bool
-str_to_time(CHARSET_INFO *cs, const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong fuzzydate, MYSQL_TIME_STATUS *status)
+class TemporalAsciiBuffer: public LEX_CSTRING
{
char cnv[32];
- if ((cs->state & MY_CS_NONASCII) != 0)
+public:
+ TemporalAsciiBuffer(const char *str, size_t length, CHARSET_INFO *cs)
{
- length= to_ascii(cs, str, length, cnv, sizeof(cnv));
- str= cnv;
+ if ((cs->state & MY_CS_NONASCII) != 0)
+ {
+ LEX_CSTRING::str= cnv;
+ LEX_CSTRING::length= to_ascii(cs, str, length, cnv, sizeof(cnv));
+ }
+ else
+ {
+ LEX_CSTRING::str= str;
+ LEX_CSTRING::length= length;
+ }
}
- return str_to_time(str, length, l_time, fuzzydate, status);
+};
+
+
+/* Character set-aware version of str_to_time() */
+bool Temporal::str_to_time(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t fuzzydate)
+{
+ TemporalAsciiBuffer tmp(str, length, cs);
+ return ::str_to_time(tmp.str, tmp.length, this,
+ ulonglong(fuzzydate & TIME_MODE_FOR_XXX_TO_DATE),
+ status);
}
/* Character set-aware version of str_to_datetime() */
-bool str_to_datetime(CHARSET_INFO *cs, const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong flags,
- MYSQL_TIME_STATUS *status)
+bool Temporal::str_to_datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ date_mode_t flags)
{
- char cnv[32];
- if ((cs->state & MY_CS_NONASCII) != 0)
- {
- length= to_ascii(cs, str, length, cnv, sizeof(cnv));
- str= cnv;
- }
- return str_to_datetime(str, length, l_time, flags, status);
+ TemporalAsciiBuffer tmp(str, length, cs);
+ return ::str_to_datetime(tmp.str, tmp.length, this,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ status);
+}
+
+
+/* Character set-aware version of str_to_DDhhmmssff() */
+bool Interval_DDhhmmssff::str_to_DDhhmmssff(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length,
+ CHARSET_INFO *cs, ulong max_hour)
+{
+ TemporalAsciiBuffer tmp(str, length, cs);
+ return ::str_to_DDhhmmssff(tmp.str, tmp.length, this, UINT_MAX32, status);
}
@@ -390,119 +413,73 @@ bool str_to_datetime(CHARSET_INFO *cs, const char *str, size_t length,
See description of str_to_datetime() for more information.
*/
-bool
-str_to_datetime_with_warn(CHARSET_INFO *cs,
+static bool
+str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs,
const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags)
+ date_mode_t flags, MYSQL_TIME_STATUS *status)
{
- MYSQL_TIME_STATUS status;
- THD *thd= current_thd;
- bool ret_val= str_to_datetime(cs, str, length, l_time, flags, &status);
- if (ret_val || status.warnings)
+ Temporal_hybrid *t= new(l_time) Temporal_hybrid(status, str, length, cs, flags);
+ if (!t->is_valid_temporal() || 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 ?
+ !t->is_valid_temporal() ?
+ Sql_condition::WARN_LEVEL_WARN :
+ Sql_condition::time_warn_level(status->warnings),
+ &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););
- return ret_val;
+ return !t->is_valid_temporal();
}
-/**
- 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)
+bool
+str_to_datetime_with_warn(THD *thd, CHARSET_INFO *cs,
+ const char *str, size_t length, MYSQL_TIME *l_time,
+ date_mode_t flags)
{
- 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;
+ MYSQL_TIME_STATUS status;
+ return str_to_datetime_with_warn(thd, cs, str, length, l_time, flags, &status);
}
-bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime,
+ date_mode_t 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);
+ Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, Sec6(value), fuzzydate,
+ &str, field_name);
+ return !t->is_valid_temporal();
}
-bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value,
+ MYSQL_TIME *ltime,
+ date_mode_t 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);
+ Temporal_hybrid *t= new (ltime) Temporal_hybrid(thd, Sec6(value), fuzzydate,
+ &str, field_name);
+ return !t->is_valid_temporal();
}
-bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
- ulonglong fuzzydate, const char *field_name)
+bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr,
+ MYSQL_TIME *ltime,
+ date_mode_t 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);
+ const ErrConvInteger str(nr);
+ /*
+ Note: conversion from an integer to TIME can overflow to '838:59:59.999999',
+ so the conversion result can have fractional digits.
+ */
+ Temporal_hybrid *t= new (ltime)
+ Temporal_hybrid(thd, Sec6(nr),
+ fuzzydate, &str, field_name);
+ return !t->is_valid_temporal();
}
@@ -549,7 +526,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 +909,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 +923,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);
}
@@ -975,7 +936,7 @@ void make_truncated_value_warning(THD *thd,
(X)->second_part)
#define GET_PART(X, N) X % N ## LL; X/= N ## LL
-bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
+bool date_add_interval(THD *thd, MYSQL_TIME *ltime, interval_type int_type,
const INTERVAL &interval)
{
long period, sign;
@@ -1090,7 +1051,6 @@ bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
invalid_date:
{
- THD *thd= current_thd;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATETIME_FUNCTION_OVERFLOW,
ER_THD(thd, ER_DATETIME_FUNCTION_OVERFLOW),
@@ -1130,7 +1090,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;
@@ -1157,10 +1117,10 @@ calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
}
microseconds= ((longlong)days * SECONDS_IN_24H +
- (longlong)(l_time1->hour*3600L +
+ (longlong)(l_time1->hour*3600LL +
l_time1->minute*60L +
l_time1->second) -
- l_sign*(longlong)(l_time2->hour*3600L +
+ l_sign*(longlong)(l_time2->hour*3600LL +
l_time2->minute*60L +
l_time2->second)) * 1000000LL +
(longlong)l_time1->second_part -
@@ -1172,17 +1132,17 @@ 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;
}
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int l_sign, MYSQL_TIME *l_time3, ulonglong fuzzydate)
+ int l_sign, MYSQL_TIME *l_time3, date_mode_t 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 +1161,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));
}
@@ -1258,56 +1218,6 @@ bool time_to_datetime(MYSQL_TIME *ltime)
}
-/**
- Return a valid DATE or DATETIME value from an arbitrary MYSQL_TIME.
- If ltime is TIME, it's first converted to DATETIME.
- If ts_type is DATE, hhmmss is set to zero.
- The date part of the result is checked against fuzzy_date.
-
- @param ltime The value to convert.
- @param fuzzy_date Flags to check date.
- @param ts_type The type to convert to.
- @return false on success, true of error (negative time).*/
-bool
-make_date_with_warn(MYSQL_TIME *ltime, ulonglong fuzzy_date,
- timestamp_type ts_type)
-{
- DBUG_ASSERT(ts_type == MYSQL_TIMESTAMP_DATE ||
- ts_type == MYSQL_TIMESTAMP_DATETIME);
- if (ltime->time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(ltime))
- {
- /* e.g. negative time */
- ErrConvTime str(ltime);
- make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
- &str, ts_type, 0);
- return true;
- }
- if ((ltime->time_type= ts_type) == MYSQL_TIMESTAMP_DATE)
- ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0;
- return check_date_with_warn(ltime, fuzzy_date, ts_type);
-}
-
-
-/*
- Convert a TIME value to DAY-TIME interval, e.g. for extraction:
- EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
- Moves full days from ltime->hour to ltime->day.
- Note, time_type is set to MYSQL_TIMESTAMP_NONE, to make sure that
- the structure is not used for anything else other than extraction:
- non-extraction TIME functions expect zero day value!
-*/
-void time_to_daytime_interval(MYSQL_TIME *ltime)
-{
- DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME);
- DBUG_ASSERT(ltime->year == 0);
- DBUG_ASSERT(ltime->month == 0);
- DBUG_ASSERT(ltime->day == 0);
- ltime->day= ltime->hour / 24;
- ltime->hour%= 24;
- ltime->time_type= MYSQL_TIMESTAMP_NONE;
-}
-
-
/*** Conversion from TIME to DATETIME ***/
/*
@@ -1335,8 +1245,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);
@@ -1426,7 +1336,7 @@ time_to_datetime(THD *thd, const MYSQL_TIME *from, MYSQL_TIME *to)
bool
time_to_datetime_with_warn(THD *thd,
const MYSQL_TIME *from, MYSQL_TIME *to,
- ulonglong fuzzydate)
+ date_mode_t fuzzydate)
{
int warn= 0;
DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
@@ -1442,34 +1352,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 +1400,11 @@ void unpack_time(longlong packed, MYSQL_TIME *my_time,
break;
}
}
+
+
+bool my_decimal::to_datetime_with_warn(THD *thd, MYSQL_TIME *to,
+ date_mode_t fuzzydate,
+ const char *field_name)
+{
+ return decimal_to_datetime_with_warn(thd, this, to, fuzzydate, field_name);
+}
diff --git a/sql/sql_time.h b/sql/sql_time.h
index d3607a28a76..433374e2e9a 100644
--- a/sql/sql_time.h
+++ b/sql/sql_time.h
@@ -17,6 +17,7 @@
#ifndef SQL_TIME_INCLUDED
#define SQL_TIME_INCLUDED
+#include "sql_basic_types.h"
#include "my_time.h"
#include "mysql_time.h" /* timestamp_type */
#include "sql_error.h" /* Sql_condition */
@@ -35,69 +36,28 @@ ulong convert_period_to_month(ulong period);
ulong convert_month_to_period(ulong month);
void set_current_date(THD *thd, MYSQL_TIME *to);
bool time_to_datetime(MYSQL_TIME *ltime);
-void time_to_daytime_interval(MYSQL_TIME *l_time);
bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code);
-bool str_to_datetime_with_warn(CHARSET_INFO *cs, const char *str, size_t length, MYSQL_TIME *l_time,
- ulonglong flags);
-bool double_to_datetime_with_warn(double value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool str_to_datetime_with_warn(THD *thd,
+ CHARSET_INFO *cs, const char *str, size_t length,
+ MYSQL_TIME *l_time,
+ date_mode_t flags);
+bool double_to_datetime_with_warn(THD *thd, double value, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
-bool decimal_to_datetime_with_warn(const my_decimal *value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool decimal_to_datetime_with_warn(THD *thd,
+ const my_decimal *value, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
-bool int_to_datetime_with_warn(bool neg, ulonglong value, MYSQL_TIME *ltime,
- ulonglong fuzzydate,
+bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate,
const char *name);
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);
-
+ date_mode_t fuzzydate);
inline void datetime_to_date(MYSQL_TIME *ltime)
{
@@ -120,14 +80,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);
@@ -138,10 +90,10 @@ const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
bool my_TIME_to_str(const MYSQL_TIME *ltime, String *str, uint dec);
/* MYSQL_TIME operations */
-bool date_add_interval(MYSQL_TIME *ltime, interval_type int_type,
+bool date_add_interval(THD *thd, 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);
/**
@@ -167,26 +119,17 @@ int append_interval(String *str, interval_type int_type,
@return false - otherwise
*/
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
- int lsign, MYSQL_TIME *l_time3, ulonglong fuzzydate);
+ int lsign, MYSQL_TIME *l_time3, date_mode_t fuzzydate);
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);
-uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year);
+void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds);
+uint calc_week(const MYSQL_TIME *l_time, uint week_behaviour, uint *year);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
bool parse_date_time_format(timestamp_type format_type,
const char *format, uint format_length,
DATE_TIME_FORMAT *date_time_format);
-/* Character set-aware version of str_to_time() */
-bool str_to_time(CHARSET_INFO *cs, const char *str,size_t length,
- MYSQL_TIME *l_time, ulonglong fuzzydate,
- MYSQL_TIME_STATUS *status);
-/* Character set-aware version of str_to_datetime() */
-bool str_to_datetime(CHARSET_INFO *cs,
- const char *str, size_t length,
- MYSQL_TIME *l_time, ulonglong flags,
- MYSQL_TIME_STATUS *status);
/* convenience wrapper */
inline bool parse_date_time_format(timestamp_type format_type,
@@ -223,15 +166,14 @@ non_zero_date(const MYSQL_TIME *ltime)
non_zero_hhmmssuu(ltime));
}
static inline bool
-check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut)
+check_date(const MYSQL_TIME *ltime, date_mode_t flags, int *was_cut)
{
- return check_date(ltime, non_zero_date(ltime), flags, was_cut);
+ return check_date(ltime, non_zero_date(ltime),
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), was_cut);
}
-bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date,
+bool check_date_with_warn(THD *thd, const MYSQL_TIME *ltime, date_mode_t fuzzy_date,
timestamp_type ts_type);
-bool make_date_with_warn(MYSQL_TIME *ltime,
- ulonglong fuzzy_date, timestamp_type ts_type);
-bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec);
+bool adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec);
longlong pack_time(const MYSQL_TIME *my_time);
void unpack_time(longlong packed, MYSQL_TIME *my_time,
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index dde93dc6ed6..b79c1a1adb1 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -35,16 +35,6 @@
#include "sp_cache.h" // sp_invalidate_cache
#include <mysys_err.h>
-LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str,
- const char* str, size_t length,
- MEM_ROOT *mem_root)
-{
- if (!(lex_str->str= strmake_root(mem_root, str, length)))
- return 0;
- lex_str->length= length;
- return lex_str;
-}
-
/*************************************************************************/
/**
@@ -622,9 +612,10 @@ end:
my_ok(thd);
DBUG_RETURN(result);
-
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
DBUG_RETURN(true);
+#endif
}
@@ -1502,8 +1493,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const LEX_CSTRING *db,
if (likely((name= error_handler.get_trigger_name())))
{
- if (unlikely(!(make_lex_string(&trigger->name, name->str,
- name->length, &table->mem_root))))
+ trigger->name= safe_lexcstrdup_root(&table->mem_root, *name);
+ if (unlikely(!trigger->name.str))
goto err_with_lex_cleanup;
}
trigger->definer= ((!trg_definer || !trg_definer->length) ?
@@ -2314,12 +2305,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 bab9bb5e9ac..798e929170c 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -495,7 +495,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 a5085fdfc58..0e4caae7a2f 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 */
@@ -564,7 +563,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);
@@ -583,7 +582,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;
@@ -710,7 +709,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..23fa678e7cf 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,16 +132,437 @@ 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);
+}
+
+
+date_mode_t Temporal::sql_mode_for_dates(THD *thd)
+{
+ return ::sql_mode_for_dates(thd);
+}
+
+
+bool Dec_ptr::to_datetime_with_warn(THD *thd, MYSQL_TIME *to,
+ date_mode_t fuzzydate, Item *item)
+{
+ if (to_datetime_with_warn(thd, 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, date_mode_t fuzzydate)
+{
+ if (item->get_date(thd, this, fuzzydate))
+ 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));
+ thd->push_warning_truncated_wrong_value(type_str, buff);
+}
+
+
+bool Sec6::convert_to_mysql_time(THD *thd, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate, const ErrConv *str,
+ const char *field_name) const
+{
+ int warn;
+ bool is_time= bool(fuzzydate & TIME_TIME_ONLY);
+ const char *typestr= is_time ? "time" : "datetime";
+ bool rc= is_time ? to_time(ltime, &warn) :
+ to_datetime(ltime, fuzzydate, &warn);
+ if (truncated())
+ {
+ // The value was already truncated at the constructor call time
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ !is_time, typestr,
+ str->ptr(), field_name);
+ }
+ else if (rc || MYSQL_TIME_WARN_HAVE_WARNINGS(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
+ rc, typestr, str->ptr(),
+ field_name);
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warn))
+ thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE,
+ rc, typestr, str->ptr(),
+ field_name);
+ return rc;
+}
+
+
+VSec6::VSec6(THD *thd, Item *item, const char *type_str, ulonglong limit)
+{
+ if (item->decimals == 0)
+ { // optimize for an important special case
+ Longlong_hybrid nr(item->val_int(), item->unsigned_flag);
+ make_from_int(nr);
+ m_is_null= item->null_value;
+ if (!m_is_null && m_sec > limit)
+ {
+ m_sec= limit;
+ m_truncated= true;
+ ErrConvInteger err(nr);
+ 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);
+ 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());
+ 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(item->to_longlong_null(), item->unsigned_flag, year_precision(item))
+{ }
+
+
+VYear_op::VYear_op(Item_func_hybrid_field_type *item)
+ :Year_null(item->to_longlong_null_op(), item->unsigned_flag,
+ year_precision(item))
+{ }
+
+
+const LEX_CSTRING Interval_DDhhmmssff::m_type_name=
+ {STRING_WITH_LEN("INTERVAL DAY TO SECOND")};
+
+
+Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, MYSQL_TIME_STATUS *st,
+ bool push_warnings,
+ Item *item, ulong max_hour)
{
- if (item->get_date(this, opt.get_date_flags()))
+ my_time_status_init(st);
+ switch (item->cmp_type()) {
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ break;
+ case TIME_RESULT:
+ {
+ if (item->get_date(thd, this, TIME_TIME_ONLY))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (time_type != MYSQL_TIMESTAMP_TIME)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ push_warning_wrong_or_truncated_value(thd, ErrConvTime(this),
+ st->warnings);
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ break;
+ }
+ case INT_RESULT:
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ case STRING_RESULT:
+ {
+ StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp;
+ String *str= item->val_str(&tmp);
+ if (!str)
+ time_type= MYSQL_TIMESTAMP_NONE;
+ else if (str_to_DDhhmmssff(st, str->ptr(), str->length(), str->charset(),
+ UINT_MAX32))
+ {
+ if (push_warnings)
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str,
+ ErrConvString(str).ptr());
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ else
+ {
+ if (hour > max_hour)
+ {
+ st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ // Warn if hour or nanosecond truncation happened
+ if (push_warnings)
+ push_warning_wrong_or_truncated_value(thd, ErrConvString(str),
+ st->warnings);
+ }
+ }
+ break;
+ }
+ DBUG_ASSERT(is_valid_value_slow());
+}
+
+
+void
+Interval_DDhhmmssff::push_warning_wrong_or_truncated_value(THD *thd,
+ const ErrConv &str,
+ int warnings)
+{
+ if (warnings & MYSQL_TIME_WARN_OUT_OF_RANGE)
+ {
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_WARNINGS(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ m_type_name.str, str.ptr());
+ }
+ else if (MYSQL_TIME_WARN_HAVE_NOTES(warnings))
+ {
+ thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_NOTE,
+ m_type_name.str, str.ptr());
+ }
+}
+
+
+uint Interval_DDhhmmssff::fsp(THD *thd, Item *item)
+{
+ MYSQL_TIME_STATUS st;
+ switch (item->cmp_type()) {
+ case INT_RESULT:
+ case TIME_RESULT:
+ return item->decimals;
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ return 0;
+ case STRING_RESULT:
+ break;
+ }
+ if (!item->const_item() || item->is_expensive())
+ return TIME_SECOND_PART_DIGITS;
+ Interval_DDhhmmssff it(thd, &st, false/*no warnings*/, item, UINT_MAX32);
+ return it.is_valid_interval_DDhhmmssff() ? st.precision :
+ TIME_SECOND_PART_DIGITS;
+}
+
+
+void Time::make_from_item(THD *thd, int *warn, Item *item, const Options opt)
+{
+ *warn= 0;
+ if (item->get_date(thd, this, opt.get_date_flags()))
time_type= MYSQL_TIMESTAMP_NONE;
else
- valid_MYSQL_TIME_to_valid_value(opt);
+ valid_MYSQL_TIME_to_valid_value(thd, warn, opt);
}
-void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
+/**
+ 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());
+}
+
+
+void Temporal_with_date::make_from_item(THD *thd, Item *item, date_mode_t flags)
{
flags&= ~TIME_TIME_ONLY;
/*
@@ -144,10 +572,10 @@ void Temporal_with_date::make_from_item(THD *thd, Item *item, sql_mode_t flags)
In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
and leave it to get_date() to check date.
*/
- ulonglong time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
- !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
- TIME_TIME_ONLY : 0;
- if (item->get_date(this, flags | time_flag))
+ date_mode_t time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
+ !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
+ TIME_TIME_ONLY : date_mode_t(0);
+ if (item->get_date(thd, this, flags | time_flag))
time_type= MYSQL_TIMESTAMP_NONE;
else if (time_type == MYSQL_TIMESTAMP_TIME)
{
@@ -160,6 +588,72 @@ 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, date_mode_t flags)
+{
+ if (check_date(this, pack_time(this) != 0,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+}
+
+
+void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_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,
+ date_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,
+ date_mode_t flags)
+{
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
+ 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 +774,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 +953,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 +964,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 +987,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 +2131,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 +2598,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 +2611,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 +2623,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 +2636,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 +2648,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 +2661,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 +2674,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 +2687,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 +2709,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 +2757,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 +2769,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 +2782,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 +2794,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 +2810,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 +2822,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 +2839,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 +2851,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 +2868,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 +2880,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 +2895,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 +2907,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 +2920,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 +2933,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 +2948,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 +2961,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 +2975,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 +2988,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 +3002,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 +3018,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 +3035,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 +3108,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(current_thd, &ltime, TIME_TIME_ONLY);
+}
+
+
+void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const
+{
+ MYSQL_TIME ltime;
+ (void) item->get_date(current_thd, &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 +3355,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 +3475,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);
@@ -2933,6 +3597,106 @@ bool Type_handler::
}
+bool Type_handler_temporal_result::
+ Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const
+{
+ bool rc= Type_handler::Item_func_min_max_fix_attributes(thd, func,
+ items, nitems);
+ bool is_time= func->field_type() == MYSQL_TYPE_TIME;
+ func->decimals= 0;
+ for (uint i= 0; i < nitems; i++)
+ {
+ uint deci= is_time ? items[i]->time_precision(thd) :
+ items[i]->datetime_precision(thd);
+ set_if_bigger(func->decimals, deci);
+ }
+
+ if (rc || func->maybe_null)
+ return rc;
+ /*
+ LEAST/GREATES(non-temporal, temporal) can return NULL.
+ CAST functions Item_{time|datetime|date}_typecast always set maybe_full
+ to true. Here we try to detect nullability more thoroughly.
+ Perhaps CAST functions should also reuse this idea eventually.
+ */
+ const Type_handler *hf= func->type_handler();
+ for (uint i= 0; i < nitems; i++)
+ {
+ /*
+ If items[i] does not need conversion to the current temporal data
+ type, then we trust items[i]->maybe_null, which was already ORred
+ to func->maybe_null in the argument loop in fix_fields().
+ If items[i] requires conversion to the current temporal data type,
+ then conversion can fail and return NULL even for NOT NULL items.
+ */
+ const Type_handler *ha= items[i]->type_handler();
+ if (hf == ha)
+ continue; // No conversion.
+ if (ha->cmp_type() != TIME_RESULT)
+ {
+ func->maybe_null= true; // Conversion from non-temporal is not safe
+ break;
+ }
+ timestamp_type tf= hf->mysql_timestamp_type();
+ timestamp_type ta= ha->mysql_timestamp_type();
+ if (tf == ta ||
+ (tf == MYSQL_TIMESTAMP_DATETIME && ta == MYSQL_TIMESTAMP_DATE))
+ {
+ /*
+ If handlers have the same mysql_timestamp_type(),
+ then conversion is NULL safe. Conversion from DATE to DATETIME
+ is also safe. This branch includes data type pairs:
+ Function return type Argument type Comment
+ -------------------- ------------- -------------
+ TIMESTAMP TIMESTAMP no conversion
+ TIMESTAMP DATETIME not possible
+ TIMESTAMP DATE not possible
+ DATETIME DATETIME no conversion
+ DATETIME TIMESTAMP safe conversion
+ DATETIME DATE safe conversion
+ DATE DATE no conversion
+ TIME TIME no conversion
+
+ Note, a function cannot return TIMESTAMP if it has non-TIMESTAMP
+ arguments (it would return DATETIME in such case).
+ */
+ DBUG_ASSERT(hf->field_type() != MYSQL_TYPE_TIMESTAMP || tf == ta);
+ continue;
+ }
+ /*
+ Here we have the following data type pairs that did not match
+ the condition above:
+
+ Function return type Argument type Comment
+ -------------------- ------------- -------
+ TIMESTAMP TIME Not possible
+ DATETIME TIME depends on OLD_MODE_ZERO_DATE_TIME_CAST
+ DATE TIMESTAMP Not possible
+ DATE DATETIME Not possible
+ DATE TIME Not possible
+ TIME TIMESTAMP Not possible
+ TIME DATETIME Not possible
+ TIME DATE Not possible
+
+ Most pairs are not possible, because the function data type
+ would be DATETIME (according to LEAST/GREATEST aggregation rules).
+ Conversion to DATETIME from TIME is not safe when
+ OLD_MODE_ZERO_DATE_TIME_CAST is set:
+ - negative TIME values cannot be converted to not-NULL DATETIME values
+ - TIME values can produce DATETIME values that do not pass
+ NO_ZERO_DATE and NO_ZERO_IN_DATE tests.
+ */
+ DBUG_ASSERT(hf->field_type() == MYSQL_TYPE_DATETIME);
+ if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST))
+ continue;
+ func->maybe_null= true;
+ break;
+ }
+ return rc;
+}
+
+
bool Type_handler_real_result::
Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
Item **items, uint nitems) const
@@ -2983,6 +3747,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 +3982,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;
@@ -3233,43 +3995,42 @@ bool Type_handler_string_result::Item_val_bool(Item *item) const
/*************************************************************************/
-bool Type_handler_int_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
-{
- return item->get_date_from_int(ltime, fuzzydate);
-}
-
-
-bool Type_handler_year::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler_int_result::Item_get_date(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_year(ltime, fuzzydate);
+ return item->get_date_from_int(thd, ltime, fuzzydate);
}
-bool Type_handler_real_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler_year::Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_real(ltime, fuzzydate);
+ return item->null_value=
+ VYear(item).to_mysql_time_with_warn(thd, ltime, fuzzydate,
+ item->field_name_or_null());
}
-bool Type_handler_decimal_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler_real_result::Item_get_date(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_decimal(ltime, fuzzydate);
+ return item->get_date_from_real(thd, ltime, fuzzydate);
}
-bool Type_handler_string_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler_string_result::Item_get_date(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_string(ltime, fuzzydate);
+ return item->get_date_from_string(thd, ltime, fuzzydate);
}
-bool Type_handler_temporal_result::Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+bool Type_handler_temporal_result::Item_get_date(THD *thd, Item *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(0); // Temporal type items must implement native get_date()
item->null_value= true;
@@ -3324,12 +4085,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 +4145,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 +4154,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 +4163,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,17 +4172,30 @@ 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);
}
bool
Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
+ Item_func_hybrid_field_type *item,
+ MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+{
+ return VDec_op(item).to_datetime_with_warn(thd, ltime, fuzzydate, item);
+}
+
+
+bool
+Type_handler_year::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_decimal_op(ltime, fuzzydate);
+ return item->null_value=
+ VYear_op(item).to_mysql_time_with_warn(thd, ltime, fuzzydate, NULL);
}
@@ -3472,11 +4240,12 @@ Type_handler_int_result::Item_func_hybrid_field_type_val_decimal(
bool
Type_handler_int_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_int_op(ltime, fuzzydate);
+ return item->get_date_from_int_op(thd, ltime, fuzzydate);
}
@@ -3521,11 +4290,12 @@ Type_handler_real_result::Item_func_hybrid_field_type_val_decimal(
bool
Type_handler_real_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_real_op(ltime, fuzzydate);
+ return item->get_date_from_real_op(thd, ltime, fuzzydate);
}
@@ -3569,11 +4339,12 @@ Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal(
bool
Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->date_op(ltime, fuzzydate);
+ return item->date_op(thd, ltime, fuzzydate);
}
@@ -3617,11 +4388,12 @@ Type_handler_time_common::Item_func_hybrid_field_type_val_decimal(
bool
Type_handler_time_common::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->time_op(ltime);
+ return item->time_op(thd, ltime);
}
@@ -3665,11 +4437,12 @@ Type_handler_string_result::Item_func_hybrid_field_type_val_decimal(
bool
Type_handler_string_result::Item_func_hybrid_field_type_get_date(
+ THD *thd,
Item_func_hybrid_field_type *item,
MYSQL_TIME *ltime,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
- return item->get_date_from_str_op(ltime, fuzzydate);
+ return item->get_date_from_str_op(thd, ltime, fuzzydate);
}
/***************************************************************************/
@@ -3707,10 +4480,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_temporal();
+ 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_time();
}
longlong Type_handler_int_result::
@@ -3930,10 +4709,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 +4747,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);
}
@@ -3965,13 +4765,30 @@ double Type_handler_string_result::
}
-double Type_handler_temporal_result::
+double Type_handler_time_common::
Item_func_min_max_val_real(Item_func_min_max *func) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return TIME_to_double(&ltime);
+ return Time(current_thd, func).to_double();
+}
+
+
+double Type_handler_date_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_double();
+}
+
+
+double Type_handler_datetime_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_double();
+}
+
+double Type_handler_timestamp_common::
+ Item_func_min_max_val_real(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_double();
}
@@ -3989,13 +4806,31 @@ longlong Type_handler_string_result::
}
-longlong Type_handler_temporal_result::
+longlong Type_handler_time_common::
Item_func_min_max_val_int(Item_func_min_max *func) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return TIME_to_ulonglong(&ltime);
+ return Time(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_date_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Date(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_datetime_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_longlong();
+}
+
+
+longlong Type_handler_timestamp_common::
+ Item_func_min_max_val_int(Item_func_min_max *func) const
+{
+ return Datetime(current_thd, func).to_longlong();
}
@@ -4022,20 +4857,41 @@ my_decimal *Type_handler_numeric::
}
-my_decimal *Type_handler_temporal_result::
+my_decimal *Type_handler_time_common::
Item_func_min_max_val_decimal(Item_func_min_max *func,
my_decimal *dec) const
{
- MYSQL_TIME ltime;
- if (func->get_date(&ltime, 0))
- return 0;
- return date2my_decimal(&ltime, dec);
+ return Time(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_date_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Date(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_datetime_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Datetime(current_thd, func).to_decimal(dec);
+}
+
+
+my_decimal *Type_handler_timestamp_common::
+ Item_func_min_max_val_decimal(Item_func_min_max *func,
+ my_decimal *dec) const
+{
+ return Datetime(current_thd, func).to_decimal(dec);
}
bool Type_handler_string_result::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
/*
just like ::val_int() method of a string item can be called,
@@ -4043,30 +4899,42 @@ bool Type_handler_string_result::
::get_date() can be called for non-temporal values,
for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09"))
*/
- return func->get_date_from_string(ltime, fuzzydate);
+ return func->get_date_from_string(thd, ltime, fuzzydate);
}
bool Type_handler_numeric::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return Item_get_date(func, ltime, fuzzydate);
+ return Item_get_date(thd, func, ltime, fuzzydate);
}
bool Type_handler_temporal_result::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return func->get_date_native(ltime, fuzzydate);
+ /*
+ - If the caller specified TIME_TIME_ONLY, then it's going to convert
+ a DATETIME or DATE to TIME. So we pass the default flags for date. This is
+ exactly the same with what Item_func_min_max_val_{int|real|decimal|str} or
+ Item_send_datetime() do. We return the value in accordance with the
+ current session date flags and let the caller further convert it to TIME.
+ - If the caller did not specify TIME_TIME_ONLY, then return the value
+ according to the flags supplied by the caller.
+ */
+ return func->get_date_native(thd, ltime,
+ fuzzydate & TIME_TIME_ONLY ?
+ sql_mode_for_dates(thd) :
+ fuzzydate);
}
bool Type_handler_time_common::
- Item_func_min_max_get_date(Item_func_min_max *func,
- MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
- return func->get_time_native(ltime);
+ return func->get_time_native(thd, ltime);
}
/***************************************************************************/
@@ -4531,7 +5399,7 @@ bool Type_handler::
Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
{
uint dec= item->decimals == NOT_FIXED_DEC ?
- item->arguments()[0]->time_precision() :
+ item->arguments()[0]->time_precision(current_thd) :
item->decimals;
item->fix_attributes_temporal(MIN_TIME_WIDTH, dec);
item->maybe_null= true;
@@ -4553,7 +5421,7 @@ bool Type_handler::
const
{
uint dec= item->decimals == NOT_FIXED_DEC ?
- item->arguments()[0]->datetime_precision() :
+ item->arguments()[0]->datetime_precision(current_thd) :
item->decimals;
item->fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
item->maybe_null= true;
@@ -4873,32 +5741,34 @@ bool Type_handler_string_result::
/***************************************************************************/
-uint Type_handler::Item_time_precision(Item *item) const
+uint Type_handler::Item_time_precision(THD *thd, Item *item) const
{
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
-uint Type_handler::Item_datetime_precision(Item *item) const
+uint Type_handler::Item_datetime_precision(THD *thd, Item *item) const
{
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
-uint Type_handler_string_result::Item_temporal_precision(Item *item,
+uint Type_handler_string_result::Item_temporal_precision(THD *thd, Item *item,
bool is_time) const
{
- MYSQL_TIME ltime;
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(),
- &ltime, TIME_TIME_ONLY, &status) :
- str_to_datetime(tmp->charset(), tmp->ptr(), tmp->length(),
- &ltime, TIME_FUZZY_DATES, &status)))
+ (is_time ?
+ Time(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
+ Time::Options(TIME_TIME_ONLY,
+ Time::DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)).
+ is_valid_time() :
+ Datetime(&status, tmp->ptr(), tmp->length(), tmp->charset(),
+ TIME_FUZZY_DATES).
+ is_valid_datetime()))
return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}
@@ -5087,7 +5957,7 @@ bool Type_handler::check_null(const Item *item, st_value *value) const
bool Type_handler_null::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_NULL;
return true;
@@ -5095,7 +5965,7 @@ bool Type_handler_null::
bool Type_handler_row::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
DBUG_ASSERT(0);
value->m_type= DYN_COL_NULL;
@@ -5104,7 +5974,7 @@ bool Type_handler_row::
bool Type_handler_int_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
value->value.m_longlong= item->val_int();
@@ -5113,7 +5983,7 @@ bool Type_handler_int_result::
bool Type_handler_real_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DOUBLE;
value->value.m_double= item->val_real();
@@ -5122,7 +5992,7 @@ bool Type_handler_real_result::
bool Type_handler_decimal_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DECIMAL;
my_decimal *dec= item->val_decimal(&value->m_decimal);
@@ -5133,7 +6003,7 @@ bool Type_handler_decimal_result::
bool Type_handler_string_result::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_STRING;
String *str= item->val_str(&value->m_string);
@@ -5144,19 +6014,19 @@ bool Type_handler_string_result::
bool Type_handler_temporal_with_date::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DATETIME;
- item->get_date(&value->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(thd, &value->value.m_time, sql_mode_for_dates(thd));
return check_null(item, value);
}
bool Type_handler_time_common::
- Item_save_in_value(Item *item, st_value *value) const
+ Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
value->m_type= DYN_COL_DATETIME;
- item->get_time(&value->value.m_time);
+ item->get_time(thd, &value->value.m_time);
return check_null(item, value);
}
@@ -5340,7 +6210,8 @@ bool Type_handler::
bool Type_handler::
Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_date(&buf->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(protocol->thd, &buf->value.m_time,
+ sql_mode_for_dates(protocol->thd));
if (!item->null_value)
return protocol->store(&buf->value.m_time, item->decimals);
return protocol->store_null();
@@ -5350,7 +6221,8 @@ bool Type_handler::
bool Type_handler::
Item_send_date(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_date(&buf->value.m_time, sql_mode_for_dates(current_thd));
+ item->get_date(protocol->thd, &buf->value.m_time,
+ sql_mode_for_dates(protocol->thd));
if (!item->null_value)
return protocol->store_date(&buf->value.m_time);
return protocol->store_null();
@@ -5360,7 +6232,7 @@ bool Type_handler::
bool Type_handler::
Item_send_time(Item *item, Protocol *protocol, st_value *buf) const
{
- item->get_time(&buf->value.m_time);
+ item->get_time(protocol->thd, &buf->value.m_time);
if (!item->null_value)
return protocol->store_time(&buf->value.m_time, item->decimals);
return protocol->store_null();
@@ -5393,11 +6265,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);
}
@@ -5420,7 +6291,7 @@ Item *Type_handler_time_common::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
Item_cache_temporal *cache;
- longlong value= item->val_time_packed();
+ longlong value= item->val_time_packed(thd);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
cache= new (thd->mem_root) Item_cache_time(thd);
@@ -5434,7 +6305,7 @@ Item *Type_handler_temporal_with_date::
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
Item_cache_temporal *cache;
- longlong value= item->val_datetime_packed();
+ longlong value= item->val_datetime_packed(thd);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
cache= new (thd->mem_root) Item_cache_datetime(thd);
@@ -5787,6 +6658,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 +7200,364 @@ 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(thd);
+ longlong value1= b->val_time_packed(thd);
+ 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(thd);
+ longlong value1= b->val_datetime_packed(thd);
+ 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(thd, &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(thd, &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,
+ timestamp_type time_type,
+ 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, 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;
+ Item_literal *item= NULL;
+ Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_date_literal(thd, tmp.get_mysql_time());
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATE,
+ &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;
+ Item_literal *item= NULL;
+ Temporal_hybrid tmp(&st, str, length, cs, sql_mode_for_dates(thd));
+ if (tmp.is_valid_temporal() &&
+ tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_datetime_literal(thd, tmp.get_mysql_time(),
+ st.precision);
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_DATETIME,
+ &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;
+ Item_literal *item= NULL;
+ Time::Options opt(TIME_TIME_ONLY, Time::DATETIME_TO_TIME_DISALLOW);
+ Time tmp(thd, &st, str, length, cs, opt);
+ if (tmp.is_valid_time() &&
+ !have_important_literal_warnings(&st))
+ item= new (thd->mem_root) Item_time_literal(thd, tmp.get_mysql_time(),
+ st.precision);
+ literal_warn(thd, item, str, length, cs, MYSQL_TIMESTAMP_TIME,
+ &st, "TIME", send_error);
+ return item;
+}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 1ddcef2da61..fd86102c504 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,656 @@ 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(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate,
+ const char *field_name)
+ {
+ return m_ptr ? m_ptr->to_datetime_with_warn(thd, to, fuzzydate, field_name) :
+ true;
+ }
+ bool to_datetime_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t 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(const Longlong_hybrid &nr)
+ {
+ m_neg= nr.neg();
+ m_sec= nr.abs();
+ m_usec= 0;
+ m_truncated= false;
+ }
+ void reset()
+ {
+ m_sec= m_usec= m_neg= m_truncated= 0;
+ }
+ Sec6() { }
+public:
+ explicit Sec6(double nr)
+ {
+ make_from_double(nr);
+ }
+ explicit Sec6(const my_decimal *d)
+ {
+ make_from_decimal(d);
+ }
+ explicit Sec6(const Longlong_hybrid &nr)
+ {
+ make_from_int(nr);
+ }
+ explicit Sec6(longlong nr, bool unsigned_val)
+ {
+ make_from_int(Longlong_hybrid(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(THD *thd, MYSQL_TIME *ltime, date_mode_t 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);
+ }
+ /*
+ Convert a number in format YYYYMMDDhhmmss.ff to
+ TIMESTAMP'YYYY-MM-DD hh:mm:ss.ff'
+ */
+ bool to_datetime(MYSQL_TIME *to, date_mode_t 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,
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ warn) == -1;
+ }
+ // 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(THD *thd, 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(THD *thd, 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(thd, 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(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate,
+ const char *field_name) const
+ {
+ // Make it YYYYMMDD
+ Longlong_hybrid value(static_cast<ulonglong>(m_year) * 10000, true);
+ const ErrConvInteger str(value);
+ Sec6 sec(value);
+ return sec.convert_to_mysql_time(thd, 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, public Null_flag
+{
+public:
+ Year_null(const Longlong_null &nr, bool unsigned_flag, uint length)
+ :Year(nr.is_null() ? 0 : nr.value(), unsigned_flag, length),
+ Null_flag(nr.is_null())
+ { }
+ bool to_mysql_time_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate,
+ const char *field_name) const
+ {
+ return m_is_null ? true :
+ Year::to_mysql_time_with_warn(thd, 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
+{
+public:
+ static date_mode_t sql_mode_for_dates(THD *thd);
+ bool is_valid_temporal() const
+ {
+ DBUG_ASSERT(time_type != MYSQL_TIMESTAMP_ERROR);
+ return time_type != MYSQL_TIMESTAMP_NONE;
+ }
+protected:
+ 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;
+ }
+ bool str_to_time(MYSQL_TIME_STATUS *st, const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate);
+ bool str_to_datetime(MYSQL_TIME_STATUS *st, const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate);
+ bool has_valid_mmssff() const
+ {
+ return minute <= TIME_MAX_MINUTE &&
+ second <= TIME_MAX_SECOND &&
+ second_part <= TIME_MAX_SECOND_PART;
+ }
+ bool has_zero_YYYYMM() const
+ {
+ return year == 0 && month == 0;
+ }
+ bool has_zero_YYYYMMDD() const
+ {
+ return year == 0 && month == 0 && day == 0;
+ }
+public:
+ static void *operator new(size_t size, MYSQL_TIME *ltime) throw()
+ {
+ DBUG_ASSERT(size == sizeof(MYSQL_TIME));
+ return ltime;
+ }
+ static void operator delete(void *ptr, MYSQL_TIME *ltime) { }
+
+ 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, date_mode_t fuzzydate);
+ Temporal_hybrid(THD *thd, Item *item)
+ :Temporal_hybrid(thd, item, sql_mode_for_dates(thd))
+ { }
+ Temporal_hybrid(Item *item)
+ :Temporal_hybrid(current_thd, item)
+ { }
+ Temporal_hybrid(MYSQL_TIME_STATUS *st, const char *str, size_t length,
+ CHARSET_INFO *cs, date_mode_t fuzzydate)
+ {
+ if (str_to_datetime(st, str, length, cs, fuzzydate))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ Temporal_hybrid(THD *thd, const Sec6 &sec, date_mode_t fuzzydate,
+ const ErrConv *str, const char *field_name)
+ {
+ if (sec.convert_to_mysql_time(thd, this, fuzzydate, str, field_name))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ 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;
+ }
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_temporal());
+ return this;
+ }
+};
+
+
+/*
+ This class resembles the SQL standard <extract source>,
+ used in extract expressions, e.g: EXTRACT(DAY FROM dt)
+ <extract expression> ::=
+ EXTRACT <left paren> <extract field> FROM <extract source> <right paren>
+ <extract source> ::= <datetime value expression> | <interval value expression>
+*/
+class Extract_source: public Temporal_hybrid
+{
+ /*
+ Convert a TIME value to DAY-TIME interval, e.g. for extraction:
+ EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc.
+ Moves full days from ltime->hour to ltime->day.
+ */
+ void time_to_daytime_interval()
+ {
+ DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_TIME);
+ DBUG_ASSERT(has_zero_YYYYMMDD());
+ MYSQL_TIME::day= MYSQL_TIME::hour / 24;
+ MYSQL_TIME::hour%= 24;
+ }
+ bool is_valid_extract_source_slow() const
+ {
+ return is_valid_temporal() && MYSQL_TIME::hour < 24 &&
+ (has_zero_YYYYMM() || time_type != MYSQL_TIMESTAMP_TIME);
+ }
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_extract_source_slow();
+ }
+public:
+ Extract_source(THD *thd, Item *item, date_mode_t mode)
+ :Temporal_hybrid(thd, item, mode)
+ {
+ if (MYSQL_TIME::time_type == MYSQL_TIMESTAMP_TIME)
+ time_to_daytime_interval();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ inline const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_extract_source_slow());
+ return this;
+ }
+ bool is_valid_extract_source() const { return is_valid_temporal(); }
+ int sign() const { return get_mysql_time()->neg ? -1 : 1; }
+ uint year() const { return get_mysql_time()->year; }
+ uint month() const { return get_mysql_time()->month; }
+ int day() const { return (int) get_mysql_time()->day * sign(); }
+ int hour() const { return (int) get_mysql_time()->hour * sign(); }
+ int minute() const { return (int) get_mysql_time()->minute * sign(); }
+ int second() const { return (int) get_mysql_time()->second * sign(); }
+ int microsecond() const { return (int) get_mysql_time()->second_part * sign(); }
+
+ uint year_month() const { return year() * 100 + month(); }
+ uint quarter() const { return (month() + 2)/3; }
+ uint week(THD *thd) const;
+
+ longlong second_microsecond() const
+ {
+ return (second() * 1000000LL + microsecond());
+ }
+
+ // DAY TO XXX
+ longlong day_hour() const
+ {
+ return (longlong) day() * 100LL + hour();
+ }
+ longlong day_minute() const
+ {
+ return day_hour() * 100LL + minute();
+ }
+ longlong day_second() const
+ {
+ return day_minute() * 100LL + second();
+ }
+ longlong day_microsecond() const
+ {
+ return day_second() * 1000000LL + microsecond();
+ }
+
+ // HOUR TO XXX
+ int hour_minute() const
+ {
+ return hour() * 100 + minute();
+ }
+ int hour_second() const
+ {
+ return hour_minute() * 100 + second();
+ }
+ longlong hour_microsecond() const
+ {
+ return hour_second() * 1000000LL + microsecond();
+ }
+
+ // MINUTE TO XXX
+ int minute_second() const
+ {
+ return minute() * 100 + second();
+ }
+ longlong minute_microsecond() const
+ {
+ return minute_second() * 1000000LL + microsecond();
+ }
+};
+
+
+/*
+ This class is used for the "time_interval" argument of these SQL functions:
+ TIMESTAMP(tm,time_interval)
+ ADDTIME(tm,time_interval)
+ Features:
+ - DATE and DATETIME formats are treated as errors
+ - Preserves hours for TIME format as is, without limiting to TIME_MAX_HOUR
+*/
+class Interval_DDhhmmssff: public Temporal
+{
+ static const LEX_CSTRING m_type_name;
+ bool str_to_DDhhmmssff(MYSQL_TIME_STATUS *status,
+ const char *str, size_t length, CHARSET_INFO *cs,
+ ulong max_hour);
+ void push_warning_wrong_or_truncated_value(THD *thd,
+ const ErrConv &str,
+ int warnings);
+ bool is_valid_interval_DDhhmmssff_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_TIME &&
+ has_zero_YYYYMMDD() && has_valid_mmssff();
+ }
+ bool is_valid_value_slow() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE ||
+ is_valid_interval_DDhhmmssff_slow();
+ }
+public:
+ // Get fractional second precision from an Item
+ static uint fsp(THD *thd, Item *item);
+ /*
+ Maximum useful HOUR value:
+ TIMESTAMP'0001-01-01 00:00:00' + '87649415:59:59' = '9999-12-31 23:59:59'
+ This gives maximum possible interval values:
+ - '87649415:59:59.999999' (in 'hh:mm:ss.ff' format)
+ - '3652058 23:59:59.999999' (in 'DD hh:mm:ss.ff' format)
+ */
+ static uint max_useful_hour()
+ {
+ return 87649415;
+ }
+public:
+ Interval_DDhhmmssff(THD *thd, MYSQL_TIME_STATUS *st, bool push_warnings,
+ Item *item, ulong max_hour);
+ Interval_DDhhmmssff(THD *thd, Item *item)
+ {
+ MYSQL_TIME_STATUS st;
+ new(this) Interval_DDhhmmssff(thd, &st, true, item, max_useful_hour());
+ }
+ const MYSQL_TIME *get_mysql_time() const
+ {
+ DBUG_ASSERT(is_valid_interval_DDhhmmssff_slow());
+ return this;
+ }
+ bool is_valid_interval_DDhhmmssff() const
+ {
+ return time_type == MYSQL_TIMESTAMP_TIME;
+ }
+ bool is_valid_value() const
+ {
+ return time_type == MYSQL_TIMESTAMP_NONE || is_valid_interval_DDhhmmssff();
+ }
+};
+
/**
Class Time is designed to store valid TIME values.
@@ -93,32 +746,35 @@ 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_DISALLOW,
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
{
- sql_mode_t m_get_date_flags;
+ date_mode_t m_get_date_flags;
datetime_to_time_mode_t m_datetime_to_time_mode;
public:
Options()
:m_get_date_flags(flags_for_get_date()),
m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
{ }
- Options(sql_mode_t flags)
+ Options(date_mode_t flags)
:m_get_date_flags(flags),
m_datetime_to_time_mode(DATETIME_TO_TIME_YYYYMMDD_000000DD_MIX_TO_HOURS)
{ }
- Options(sql_mode_t flags, datetime_to_time_mode_t dtmode)
+ Options(date_mode_t flags, datetime_to_time_mode_t dtmode)
:m_get_date_flags(flags),
m_datetime_to_time_mode(dtmode)
{ }
- sql_mode_t get_date_flags() const
+ date_mode_t get_date_flags() const
{ return m_get_date_flags; }
datetime_to_time_mode_t datetime_to_time_mode() const
{ return m_datetime_to_time_mode; }
@@ -143,46 +799,79 @@ private:
bool is_valid_time_slow() const
{
return time_type == MYSQL_TIMESTAMP_TIME &&
- year == 0 && month == 0 && day == 0 &&
- minute <= TIME_MAX_MINUTE &&
- second <= TIME_MAX_SECOND &&
- second_part <= TIME_MAX_SECOND_PART;
+ has_zero_YYYYMMDD() && has_valid_mmssff();
+ }
+ 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, date_mode_t(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(THD *thd, 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(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 +881,19 @@ 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(THD *thd, 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 if (opt.datetime_to_time_mode() == DATETIME_TO_TIME_DISALLOW)
+ make_from_out_of_range(warn);
+ else
+ valid_datetime_to_valid_time(thd, warn, opt);
break;
case MYSQL_TIMESTAMP_NONE:
break;
@@ -209,14 +905,94 @@ 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(THD *thd, 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(thd, 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(THD *thd, 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); }
- static sql_mode_t flags_for_get_date()
+ Time(Item *item)
+ :Time(current_thd, item, Options())
+ { }
+ Time(THD *thd, Item *item, const Options opt)
+ {
+ int warn;
+ make_from_item(thd, &warn, item, opt);
+ }
+ Time(THD *thd, Item *item)
+ :Time(thd, item, Options())
+ { }
+ Time(int *warn, const MYSQL_TIME *from, long curdays);
+ Time(THD *thd, MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ const Options opt)
+ {
+ if (str_to_time(status, str, len, cs, opt.get_date_flags()))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ // The below call will optionally add notes to already collected warnings:
+ xxx_to_time_result_to_valid_value(thd, &status->warnings, opt);
+ }
+ Time(THD *thd, 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(thd, warn, opt);
+ }
+ Time(THD *thd, int *warn, const Sec6 &nr)
+ :Time(thd, warn, nr, Options())
+ { }
+
+ Time(THD *thd, Item *item, const Options opt, uint dec)
+ :Time(thd, item, opt)
+ {
+ trunc(dec);
+ }
+ Time(int *warn, const MYSQL_TIME *from, long curdays, uint dec)
+ :Time(warn, from, curdays)
+ {
+ trunc(dec);
+ }
+ Time(THD *thd, MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ const Options &opt, uint dec)
+ :Time(thd, status, str, len, cs, opt)
+ {
+ trunc(dec);
+ }
+ Time(THD *thd, int *warn, const Sec6 &nr, uint dec)
+ :Time(thd, warn, nr)
+ {
+ trunc(dec);
+ }
+
+ static date_mode_t flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES; }
- static sql_mode_t comparison_flags_for_get_date()
+ static date_mode_t comparison_flags_for_get_date()
{ return TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES; }
bool is_valid_time() const
{
@@ -243,8 +1019,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 +1036,42 @@ 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)
+ {
+ if (is_valid_time())
+ my_time_trunc(this, dec);
+ DBUG_ASSERT(is_valid_value_slow());
+ return *this;
+ }
};
@@ -286,14 +1098,70 @@ 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 make_from_item(THD *thd, Item *item, sql_mode_t flags);
- Temporal_with_date(THD *thd, Item *item, sql_mode_t flags)
+ void check_date_or_invalidate(int *warn, date_mode_t flags);
+ void make_from_item(THD *thd, Item *item, date_mode_t flags);
+ void make_from_item(THD *thd, Item *item);
+
+ ulong daynr() const
+ {
+ return (ulong) ::calc_daynr((uint) year, (uint) month, (uint) day);
+ }
+ ulong dayofyear() const
+ {
+ return (ulong) (daynr() - ::calc_daynr(year, 1, 1) + 1);
+ }
+ uint quarter() const
+ {
+ return (month + 2) / 3;
+ }
+ uint week(uint week_behaviour) const
+ {
+ uint year;
+ return calc_week(this, week_behaviour, &year);
+ }
+ uint yearweek(uint week_behaviour) const
+ {
+ uint year;
+ uint week= calc_week(this, week_behaviour, &year);
+ return week + year * 100;
+ }
+
+ Temporal_with_date()
+ {
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ Temporal_with_date(THD *thd, Item *item, date_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, date_mode_t flags)
+ {
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
+ if (nr.to_datetime(this, flags, warn))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+ Temporal_with_date(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t flags)
+ {
+ DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
+ if (str_to_datetime(status, str, len, cs, flags))
+ time_type= MYSQL_TIMESTAMP_NONE;
+ }
+public:
+ bool check_date_with_warn(THD *thd, date_mode_t flags)
+ {
+ return ::check_date_with_warn(thd, this, flags, MYSQL_TIMESTAMP_ERROR);
+ }
+ static date_mode_t comparison_flags_for_get_date()
+ { return TIME_INVALID_DATES | TIME_FUZZY_DATES; }
};
@@ -318,13 +1186,23 @@ class Date: public Temporal_with_date
return !check_datetime_range(this);
}
public:
- Date(THD *thd, Item *item, sql_mode_t flags)
+ Date(THD *thd, Item *item, date_mode_t flags)
:Temporal_with_date(thd, item, flags)
{
if (time_type == MYSQL_TIMESTAMP_DATETIME)
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)
+ :Date(current_thd, item)
+ { }
Date(const Temporal_with_date *d)
:Temporal_with_date(*d)
{
@@ -341,6 +1219,64 @@ 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;
+ }
+ ulong daynr() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::daynr();
+ }
+ ulong dayofyear() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::dayofyear();
+ }
+ uint quarter() const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::quarter();
+ }
+ uint week(uint week_behaviour) const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::week(week_behaviour);
+ }
+ uint yearweek(uint week_behaviour) const
+ {
+ DBUG_ASSERT(is_valid_date_slow());
+ return Temporal_with_date::yearweek(week_behaviour);
+ }
+
+ 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 +1301,75 @@ class Datetime: public Temporal_with_date
DBUG_ASSERT(time_type == MYSQL_TIMESTAMP_DATETIME);
return !check_datetime_range(this);
}
-public:
- Datetime(THD *thd, Item *item, sql_mode_t flags)
- :Temporal_with_date(thd, item, flags)
+ 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,
+ date_mode_t flags);
+ void make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_mode_t flags);
+public:
+ Datetime(THD *thd, Item *item, date_mode_t flags)
+ :Temporal_with_date(thd, item, flags)
+ {
+ 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)
+ :Datetime(current_thd, item)
+ { }
+ Datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_mode_t flags);
+ Datetime()
+ {
+ set_zero_time(this, MYSQL_TIMESTAMP_DATETIME);
+ }
+ Datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t flags)
+ :Temporal_with_date(status, str, len, cs, flags)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+ Datetime(int *warn, const Sec6 &nr, date_mode_t flags)
+ :Temporal_with_date(warn, nr, flags)
+ {
+ date_to_datetime_if_needed();
+ DBUG_ASSERT(is_valid_value_slow());
+ }
+
+ Datetime(THD *thd, Item *item, date_mode_t flags, uint dec)
+ :Datetime(thd, item, flags)
+ {
+ trunc(dec);
+ }
+ Datetime(MYSQL_TIME_STATUS *status,
+ const char *str, size_t len, CHARSET_INFO *cs,
+ date_mode_t fuzzydate, uint dec)
+ :Datetime(status, str, len, cs, fuzzydate)
+ {
+ trunc(dec);
+ }
+ Datetime(int *warn, const Sec6 &nr, date_mode_t fuzzydate, uint dec)
+ :Datetime(warn, nr, fuzzydate)
+ {
+ trunc(dec);
+ }
+ Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
+ date_mode_t fuzzydate, uint dec)
+ :Datetime(thd, warn, from, fuzzydate)
+ {
+ trunc(dec);
+ }
+
bool is_valid_datetime() const
{
/*
@@ -382,11 +1379,42 @@ public:
DBUG_ASSERT(is_valid_value_slow());
return time_type == MYSQL_TIMESTAMP_DATETIME;
}
+ bool check_date(date_mode_t flags, int *warnings) const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return ::check_date(this, (year || month || day),
+ ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE),
+ warnings);
+ }
+ bool check_date(date_mode_t flags) const
+ {
+ int dummy; /* unused */
+ return check_date(flags, &dummy);
+ }
bool hhmmssff_is_zero() const
{
DBUG_ASSERT(is_valid_datetime_slow());
return hour == 0 && minute == 0 && second == 0 && second_part == 0;
}
+ ulong daynr() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return Temporal_with_date::daynr();
+ }
+ longlong hhmmss_to_seconds_abs() const
+ {
+ DBUG_ASSERT(is_valid_datetime_slow());
+ return hour * 3600L + minute * 60 + second;
+ }
+ longlong hhmmss_to_seconds() const
+ {
+ return neg ? -hhmmss_to_seconds_abs() : hhmmss_to_seconds_abs();
+ }
+ longlong to_seconds() const
+ {
+ return hhmmss_to_seconds() + (longlong) daynr() * 24L * 3600L;
+ }
+
const MYSQL_TIME *get_mysql_time() const
{
DBUG_ASSERT(is_valid_datetime_slow());
@@ -418,8 +1446,43 @@ 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)
+ {
+ if (is_valid_datetime())
+ my_time_trunc(this, dec);
+ DBUG_ASSERT(is_valid_value_slow());
+ return *this;
+ }
};
+
/*
Flags for collation aggregation modes, used in TDCollation::agg():
@@ -445,7 +1508,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 +1896,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 +1956,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 +2091,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 +2126,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 +2160,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 +2195,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 +2252,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,9 +2284,10 @@ 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;
+ virtual uint Item_time_precision(THD *thd, Item *item) const;
+ virtual uint Item_datetime_precision(THD *thd, Item *item) const;
virtual uint Item_decimal_scale(const Item *item) const;
virtual uint Item_decimal_precision(const Item *item) const= 0;
/*
@@ -1169,7 +2331,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 +2383,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,7 +2409,8 @@ public:
virtual uint32 max_display_length(const Item *item) const= 0;
virtual uint32 calc_pack_length(uint32 length) const= 0;
- virtual bool Item_save_in_value(Item *item, st_value *value) const= 0;
+ virtual void Item_update_null_value(Item *item) const= 0;
+ virtual bool Item_save_in_value(THD *thd, 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,
uchar **pos, ulong len) const;
@@ -1295,6 +2488,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 +2521,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 *,
@@ -1319,8 +2545,8 @@ public:
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const= 0;
virtual bool Item_val_bool(Item *item) const= 0;
- virtual bool Item_get_date(Item *item, MYSQL_TIME *ltime,
- ulonglong fuzzydate) const= 0;
+ virtual bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const= 0;
virtual longlong Item_val_int_signed_typecast(Item *item) const= 0;
virtual longlong Item_val_int_unsigned_typecast(Item *item) const= 0;
@@ -1341,9 +2567,10 @@ public:
Item_func_hybrid_field_type *,
my_decimal *) const= 0;
virtual
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const= 0;
+ date_mode_t fuzzydate) const= 0;
virtual
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const= 0;
virtual
@@ -1354,8 +2581,8 @@ public:
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const= 0;
virtual
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const= 0;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const= 0;
virtual bool
Item_func_between_fix_length_and_dec(Item_func_between *func) const= 0;
virtual longlong
@@ -1447,6 +2674,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 +2701,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 +2735,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,12 +2763,14 @@ 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);
return DECIMAL_MAX_PRECISION;
}
- bool Item_save_in_value(Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
@@ -1533,6 +2780,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);
@@ -1584,7 +2832,8 @@ public:
DBUG_ASSERT(0);
return false;
}
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const
+ bool Item_get_date(THD *thd, Item *item,
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
return true;
@@ -1629,9 +2878,10 @@ public:
DBUG_ASSERT(0);
return NULL;
}
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const
+ date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
return true;
@@ -1658,8 +2908,8 @@ public:
DBUG_ASSERT(0);
return NULL;
}
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const
{
DBUG_ASSERT(0);
return true;
@@ -1743,8 +2993,8 @@ public:
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t fuzzydate) const;
virtual ~Type_handler_numeric() { }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
@@ -1764,6 +3014,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 +3025,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_save_in_value(THD *thd, 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;
@@ -1795,7 +3054,8 @@ public:
bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -1808,9 +3068,10 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -1837,6 +3098,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,8 +3114,16 @@ 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;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
bool Item_param_set_from_value(THD *thd,
@@ -1860,6 +3134,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 +3148,20 @@ 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(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const
+ {
+ return VDec(item).to_datetime_with_warn(thd, 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;
@@ -1887,9 +3172,10 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -2038,8 +3324,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 +3337,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_save_in_value(THD *thd, 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;
@@ -2068,7 +3362,8 @@ public:
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_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -2081,9 +3376,10 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
longlong Item_func_between_val_int(Item_func_between *func) const;
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
@@ -2099,6 +3395,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 +3424,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,
@@ -2138,12 +3437,15 @@ public:
Item *source_expr, Item *source_const) const;
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
+ bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
+ Item **items, uint nitems) const;
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
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_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -2156,18 +3458,13 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ 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 *,
- my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ date_mode_t fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t 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;
@@ -2185,13 +3482,14 @@ public:
class Type_handler_string_result: public Type_handler
{
- uint Item_temporal_precision(Item *item, bool is_time) const;
+ uint Item_temporal_precision(THD *thd, Item *item, bool is_time) const;
public:
Item_result result_type() const { return STRING_RESULT; }
Item_result cmp_type() const { return STRING_RESULT; }
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,16 +3509,21 @@ public:
const Schema_specification_st *schema)
const;
uint32 max_display_length(const Item *item) const;
- uint Item_time_precision(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(THD *thd, Item *item) const
{
- return Item_temporal_precision(item, true);
+ return Item_temporal_precision(thd, item, true);
}
- uint Item_datetime_precision(Item *item) const
+ uint Item_datetime_precision(THD *thd, Item *item) const
{
- return Item_temporal_precision(item, false);
+ return Item_temporal_precision(thd, item, false);
}
uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(Item *item, st_value *value) const;
+ void Item_update_null_value(Item *item) const;
+ bool Item_save_in_value(THD *thd, 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,
uchar **pos, ulong len) const;
@@ -2258,7 +3561,8 @@ public:
bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
bool Item_val_bool(Item *item) const;
- bool Item_get_date(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate) const;
+ bool Item_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
longlong Item_val_int_signed_typecast(Item *item) const;
longlong Item_val_int_unsigned_typecast(Item *item) const;
String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
@@ -2271,16 +3575,17 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
+ date_mode_t 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 *,
my_decimal *) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t 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_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
@@ -2357,6 +3662,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 +3703,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 +3744,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 +3800,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 +3852,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 +3878,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 +3889,20 @@ 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_get_date(THD *thd, Item *item, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const;
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *item,
+ MYSQL_TIME *to,
+ date_mode_t fuzzydate) const;
};
@@ -2577,6 +3943,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 +3980,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 +4019,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 +4042,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 +4058,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_save_in_value(THD *thd, 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;
@@ -2690,11 +4084,18 @@ public:
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
my_decimal *) const;
- bool Item_func_hybrid_field_type_get_date(Item_func_hybrid_field_type *,
+ bool Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
MYSQL_TIME *,
- ulonglong fuzzydate) const;
- bool Item_func_min_max_get_date(Item_func_min_max*,
- MYSQL_TIME *, ulonglong fuzzydate) const;
+ date_mode_t 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 *,
+ my_decimal *) const;
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *, date_mode_t 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 +4112,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 +4124,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 +4138,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 +4151,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 +4165,23 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
{
public:
virtual ~Type_handler_temporal_with_date() {}
- bool Item_save_in_value(Item *item, st_value *value) const;
+ 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(THD *thd, 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 +4197,23 @@ 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;
+ 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 *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2803,6 +4238,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 +4264,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 +4286,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 +4309,11 @@ 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;
+ 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 *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2872,6 +4331,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 +4343,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 +4357,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 +4370,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 +4396,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 +4413,11 @@ 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;
+ 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 *,
+ my_decimal *) const;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
@@ -2954,6 +4435,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 +4447,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 +4461,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 +4476,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 +4507,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 +4545,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,7 +4567,9 @@ 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_save_in_value(Item *item, st_value *value) const;
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const;
+ bool Item_save_in_value(THD *thd, 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,
const Field *target) const;
@@ -3079,6 +4592,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 +4635,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 +4654,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 +4705,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 +4756,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 +4769,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 +4877,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 +4902,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 +4959,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 +4984,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 +5000,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 +5016,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 +5032,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 +5139,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 +5159,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_type_int.h b/sql/sql_type_int.h
index 1eda5651df5..6c88222fed0 100644
--- a/sql/sql_type_int.h
+++ b/sql/sql_type_int.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
- Copyright (c) 2011, 2016, MariaDB
+/* Copyright (c) 2018, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,17 +17,44 @@
#define SQL_TYPE_INT_INCLUDED
-// A longlong/ulonglong hybrid. Good to store results of val_int().
-class Longlong_hybrid
+class Null_flag
+{
+protected:
+ bool m_is_null;
+public:
+ bool is_null() const { return m_is_null; }
+ Null_flag(bool is_null) :m_is_null(is_null) { }
+};
+
+
+class Longlong
{
protected:
longlong m_value;
+public:
+ longlong value() const { return m_value; }
+ Longlong(longlong nr) :m_value(nr) { }
+};
+
+
+class Longlong_null: public Longlong, public Null_flag
+{
+public:
+ Longlong_null(longlong nr, bool is_null)
+ :Longlong(nr), Null_flag(is_null)
+ { }
+};
+
+
+// A longlong/ulonglong hybrid. Good to store results of val_int().
+class Longlong_hybrid: public Longlong
+{
+protected:
bool m_unsigned;
public:
Longlong_hybrid(longlong nr, bool unsigned_flag)
- :m_value(nr), m_unsigned(unsigned_flag)
+ :Longlong(nr), m_unsigned(unsigned_flag)
{ }
- longlong value() const { return m_value; }
bool is_unsigned() const { return m_unsigned; }
bool neg() const { return m_value < 0 && !m_unsigned; }
ulonglong abs() const
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 6368ed8afd8..1910ad0f83e 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 7a496172aed..27bd6f04670 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 07230b2205b..e475a3d3719 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;
@@ -711,9 +710,10 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local);
DBUG_RETURN(0);
-
-WSREP_ERROR_LABEL:
- res= TRUE;
+#ifdef WITH_WSREP
+wsrep_error_label:
+ res= true;
+#endif
err:
lex->link_first_table_back(view, link_to_local);
@@ -995,7 +995,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 +1114,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 +1162,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 +1362,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 +1396,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 +1547,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
@@ -1573,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,
@@ -1595,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)
@@ -1678,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;
@@ -1691,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,
@@ -1731,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;
@@ -1916,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 f47bcfb5022..40caafb32e1 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 56 shift/reduce conflicts.
+ Currently there are 52 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 56
+%expect 52
/*
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
@@ -1798,7 +1730,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
@@ -1861,7 +1794,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
@@ -1981,11 +1914,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
@@ -2019,14 +1949,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
@@ -2038,11 +1973,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
@@ -2058,7 +2010,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
@@ -2079,9 +2031,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
@@ -2209,8 +2160,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;
@@ -2305,6 +2256,7 @@ statement:
| rollback
| savepoint
| select
+ | select_into
| set
| signal_stmt
| show
@@ -2340,6 +2292,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;
}
@@ -2362,7 +2316,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()))
@@ -2371,7 +2328,10 @@ execute:
Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
}
execute_using
- {}
+ {
+ if (Lex->check_main_unit_semantics())
+ MYSQL_YYABORT;
+ }
;
execute_using:
@@ -2658,17 +2618,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();
/*
@@ -2683,7 +2648,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)
{
@@ -2692,22 +2656,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;
/*
@@ -2730,8 +2696,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;
}
@@ -2744,10 +2711,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,
@@ -2757,44 +2722,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
{
@@ -2803,61 +2793,105 @@ 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
- { }
- | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
- opt_require_clause opt_resource_options
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace USER_SYM opt_if_not_exists clear_privileges
+ grant_list opt_require_clause opt_resource_options
{
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3)))
@@ -3258,7 +3292,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));
@@ -3757,7 +3791,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;
}
;
@@ -4217,7 +4251,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;
}
;
@@ -4226,6 +4260,7 @@ for_loop_bound_expr:
assignment_source_lex
{
Lex->sphead->reset_lex(thd, $1);
+ Lex->current_select->parsing_place= FOR_LOOP_BOUND;
}
expr
{
@@ -4235,6 +4270,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;
}
;
@@ -4468,7 +4504,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
@@ -4670,7 +4707,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
@@ -4693,7 +4730,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;
@@ -5173,26 +5210,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. */
@@ -5202,7 +5229,7 @@ create_body:
create_like:
LIKE table_ident { $$= $2; }
- | '(' LIKE table_ident ')' { $$= $3; }
+ | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; }
;
opt_create_select:
@@ -5211,23 +5238,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:
@@ -5310,13 +5333,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:
@@ -5927,7 +5954,7 @@ opt_versioning_rotation:
| INTERVAL_SYM expr interval opt_versioning_interval_start
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_interval($2, $3, $4)))
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4)))
{
my_error(ER_PART_WRONG_VALUE, MYF(0),
Lex->create_last_non_select_table->table_name.str,
@@ -5970,56 +5997,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 {}
@@ -6237,7 +6214,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 ')'
{
@@ -6246,8 +6223,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
@@ -6448,6 +6425,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
@@ -6742,6 +6726,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
{
@@ -6749,14 +6735,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
@@ -7673,23 +7660,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
@@ -7701,11 +7690,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
{
@@ -7715,6 +7707,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
{
@@ -7730,6 +7723,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
@@ -7738,6 +7733,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
{
@@ -7745,6 +7743,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
@@ -7753,14 +7753,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
@@ -7768,14 +7777,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
@@ -7807,6 +7824,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
{
@@ -7850,16 +7869,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
@@ -7868,6 +7888,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;
}
;
@@ -8017,16 +8040,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)
@@ -8265,9 +8289,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)) ||
@@ -8962,8 +8986,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
@@ -8984,217 +9008,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;
}
;
@@ -9202,18 +9227,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
@@ -9262,8 +9275,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);
}
@@ -9316,59 +9330,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
@@ -10023,7 +10046,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 ')'
{
@@ -10201,7 +10238,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;
}
@@ -11616,10 +11653,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);
}
;
@@ -11638,11 +11680,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;
@@ -11659,6 +11708,8 @@ join_table:
USING
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
}
'(' using_list ')'
{
@@ -11669,6 +11720,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);
}
@@ -11678,6 +11731,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;
@@ -11694,6 +11749,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 ')'
{
@@ -11704,6 +11761,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;
@@ -11714,6 +11773,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;
@@ -11731,6 +11792,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 ')'
{
@@ -11742,6 +11805,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())))
@@ -11777,238 +11842,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);
- }
- ;
-
-/* 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;
@@ -12016,86 +11887,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 {}
@@ -12226,9 +12070,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))
@@ -12324,7 +12173,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;
@@ -12341,7 +12190,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;
@@ -12401,7 +12250,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:
@@ -12525,70 +12374,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:
@@ -12598,63 +12412,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;
}
;
@@ -12717,6 +12529,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 */
| '+'
@@ -12786,14 +12669,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;
@@ -12813,6 +12693,7 @@ procedure_clause:
parameters are reduced.
*/
Lex->expr_allows_subselect= false;
+ Select->options|= OPTION_PROCEDURE_CLAUSE;
}
'(' procedure_list ')'
{
@@ -12896,6 +12777,7 @@ select_outvar:
into:
INTO into_destination
+ {}
;
into_destination:
@@ -13089,10 +12971,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;
}
;
@@ -13166,16 +13049,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:
@@ -13184,15 +13074,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:
@@ -13235,15 +13132,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;
@@ -13251,20 +13147,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:
@@ -13414,6 +13323,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;
@@ -13422,13 +13333,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;
}
/*
@@ -13438,7 +13350,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:
@@ -13485,9 +13404,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
;
@@ -13508,6 +13429,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
}
;
@@ -13531,7 +13453,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);
@@ -13542,6 +13469,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
{
@@ -13553,6 +13483,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;
}
;
@@ -13621,9 +13554,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;
}
@@ -13708,6 +13641,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();
@@ -13715,6 +13650,7 @@ show:
show_param
{
Select->parsing_place= NO_MATTER;
+ Lex->pop_select(); //main select
}
;
@@ -13730,40 +13666,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
@@ -13812,12 +13748,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;
@@ -13859,13 +13796,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;
@@ -13927,7 +13864,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;
}
@@ -13935,7 +13872,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;
}
@@ -13943,7 +13880,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;
}
@@ -14160,7 +14097,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;
@@ -14174,12 +14111,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
@@ -14200,6 +14138,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 {}
;
@@ -14242,8 +14182,7 @@ flush:
lex->type= 0;
lex->no_write_to_binlog= $2;
}
- flush_options
- {}
+ flush_options {}
;
flush_options:
@@ -14260,6 +14199,7 @@ flush_options:
opt_table_list opt_flush_lock
{}
| flush_options_list
+ {}
;
opt_flush_lock:
@@ -14464,6 +14404,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;
}
;
@@ -14524,7 +14466,7 @@ use:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CHANGE_DB;
- lex->select_lex.db= $2;
+ lex->first_select_lex()->db= $2;
}
;
@@ -14541,6 +14483,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
{
@@ -14570,7 +14515,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:
@@ -14768,11 +14717,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
@@ -14781,7 +14725,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| BIN_NUM
@@ -14794,7 +14737,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);
}
;
@@ -14930,26 +14872,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;
}
;
@@ -14965,17 +14904,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();
@@ -15004,15 +14947,14 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_tok_start subselect remember_tok_end ')'
+ AS '(' remember_tok_start query_expression remember_tok_end ')'
{
LEX *lex= thd->lex;
const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
: thd->query();
char *spec_start= $6 + 1;
- 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 (elem->set_unparsed_spec(thd, spec_start, $8,
spec_start - query_start))
@@ -15952,14 +15894,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
@@ -15969,6 +15919,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
{}
@@ -16310,14 +16263,14 @@ opt_for_user:
;
text_or_password:
- TEXT_STRING { Lex->definer->pwhash= $1;}
+ TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
- Lex->definer->pwhash.str= Item_func_password::alloc(thd,
+ Lex->definer->auth.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
- Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
@@ -16387,7 +16340,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);
@@ -16432,27 +16385,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))
@@ -16466,15 +16428,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");
@@ -16857,13 +16828,11 @@ grant_user:
{
$$= $1;
$1->pwtext= $4;
- if (unlikely(Lex->sql_command == SQLCOM_REVOKE))
- MYSQL_YYABORT;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
- $1->pwhash= $5;
+ $1->auth= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
{
@@ -16871,12 +16840,20 @@ grant_user:
$1->plugin= $4;
$1->auth= empty_clex_str;
}
- | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as TEXT_STRING_sys
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ TEXT_STRING_sys
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
}
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ PASSWORD_SYM '(' TEXT_STRING ')'
+ {
+ $$= $1;
+ $1->plugin= $4;
+ $1->pwtext= $8;
+ }
| user_or_role
{ $$= $1; }
;
@@ -17110,212 +17087,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();
- }
- ;
-
-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= "";
- }
- ;
+ { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
-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;
@@ -17323,18 +17115,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; }
;
@@ -17422,35 +17204,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; }
@@ -17549,11 +17310,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;
}
;
@@ -17745,12 +17505,15 @@ opt_migrate:
;
install:
- INSTALL_SYM PLUGIN_SYM ident SONAME_SYM TEXT_STRING_sys
+ INSTALL_SYM PLUGIN_SYM opt_if_not_exists ident SONAME_SYM TEXT_STRING_sys
{
LEX *lex= Lex;
+ lex->create_info.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_INSTALL_PLUGIN;
- lex->comment= $3;
- lex->ident= $5;
+ lex->comment= $4;
+ lex->ident= $6;
}
| INSTALL_SYM SONAME_SYM TEXT_STRING_sys
{
@@ -17762,18 +17525,24 @@ install:
;
uninstall:
- UNINSTALL_SYM PLUGIN_SYM ident
+ UNINSTALL_SYM PLUGIN_SYM opt_if_exists ident
{
LEX *lex= Lex;
+ lex->check_opt.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
- lex->comment= $3;
+ lex->comment= $4;
}
- | UNINSTALL_SYM SONAME_SYM TEXT_STRING_sys
+ | UNINSTALL_SYM SONAME_SYM opt_if_exists TEXT_STRING_sys
{
LEX *lex= Lex;
+ lex->check_opt.init();
+ if (lex->add_create_options_with_check($3))
+ MYSQL_YYABORT;
lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
lex->comment= null_clex_str;
- lex->ident= $3;
+ lex->ident= $4;
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index aaac4ba3e54..6d8f992760b 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 57 shift/reduce conflicts.
+ Currently there are 53 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 57
+%expect 53
/*
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
@@ -1195,7 +1212,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
@@ -1263,7 +1281,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
@@ -1386,11 +1404,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
@@ -1426,14 +1441,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
@@ -1445,11 +1465,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
@@ -1466,7 +1503,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
@@ -1486,9 +1523,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
@@ -1639,8 +1675,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;
@@ -1735,6 +1771,7 @@ statement:
| rollback
| savepoint
| select
+ | select_into
| set
| set_assign
| signal_stmt
@@ -2089,17 +2126,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();
/*
@@ -2114,7 +2156,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)
{
@@ -2123,22 +2164,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;
/*
@@ -2161,8 +2204,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;
}
@@ -2175,10 +2219,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,
@@ -2188,44 +2230,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
{
@@ -2234,54 +2301,96 @@ 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
- { }
- | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
- opt_require_clause opt_resource_options
+ {
+ Lex->pop_select(); //main select
+ }
+ | create_or_replace USER_SYM opt_if_not_exists clear_privileges
+ grant_list opt_require_clause opt_resource_options
{
if (unlikely(Lex->set_command_with_check(SQLCOM_CREATE_USER,
$1 | $3)))
@@ -2902,7 +3011,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));
@@ -3532,7 +3641,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;
}
;
@@ -3979,7 +4088,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:
@@ -3995,14 +4106,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;
}
;
@@ -4020,14 +4131,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;
}
;
@@ -4086,7 +4197,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;
}
;
@@ -4095,6 +4206,7 @@ for_loop_bound_expr:
assignment_source_lex
{
Lex->sphead->reset_lex(thd, $1);
+ Lex->current_select->parsing_place= FOR_LOOP_BOUND;
}
expr
{
@@ -4104,6 +4216,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;
}
;
@@ -4325,7 +4438,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
@@ -4617,7 +4731,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
@@ -4640,7 +4754,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;
@@ -5120,26 +5234,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. */
@@ -5149,7 +5253,7 @@ create_body:
create_like:
LIKE table_ident { $$= $2; }
- | '(' LIKE table_ident ')' { $$= $3; }
+ | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; }
;
opt_create_select:
@@ -5158,23 +5262,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:
@@ -5262,8 +5363,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:
@@ -5874,7 +5980,7 @@ opt_versioning_rotation:
| INTERVAL_SYM expr interval opt_versioning_interval_start
{
partition_info *part_info= Lex->part_info;
- if (unlikely(part_info->vers_set_interval($2, $3, $4)))
+ if (unlikely(part_info->vers_set_interval(thd, $2, $3, $4)))
{
my_error(ER_PART_WRONG_VALUE, MYF(0),
Lex->create_last_non_select_table->table_name.str,
@@ -5917,56 +6023,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 {}
@@ -6184,7 +6240,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 ')'
{
@@ -6193,8 +6249,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
@@ -6395,6 +6451,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
@@ -6689,6 +6752,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
{
@@ -6696,14 +6761,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
@@ -7729,23 +7795,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
@@ -7757,11 +7825,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
{
@@ -7771,6 +7842,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
{
@@ -7786,6 +7858,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
@@ -7794,6 +7868,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
{
@@ -7801,6 +7878,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
@@ -7809,14 +7888,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
@@ -7824,14 +7912,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
@@ -7863,6 +7959,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
{
@@ -7906,16 +8004,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
@@ -7924,6 +8023,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;
}
;
@@ -8073,16 +8175,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)
@@ -8321,10 +8421,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))))
@@ -9018,8 +9119,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
@@ -9042,215 +9143,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;
}
;
@@ -9258,18 +9355,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
@@ -9318,8 +9403,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);
}
@@ -9372,59 +9458,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
@@ -10127,7 +10224,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 ')'
{
@@ -10324,7 +10435,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;
}
@@ -11756,10 +11867,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);
}
;
@@ -11778,11 +11894,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;
@@ -11799,6 +11922,8 @@ join_table:
USING
{
MYSQL_YYABORT_UNLESS($1 && $3);
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
}
'(' using_list ')'
{
@@ -11809,6 +11934,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);
}
@@ -11818,6 +11945,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;
@@ -11834,6 +11963,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 ')'
{
@@ -11844,6 +11975,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;
@@ -11854,6 +11987,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;
@@ -11871,6 +12006,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 ')'
{
@@ -11882,6 +12019,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())))
@@ -11916,238 +12055,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
+nested_table_reference_list:
+ table_ref ',' table_ref
{
- if (unlikely($1))
- {
- thd->parse_error();
+ if (Select->init_nested_join(thd))
MYSQL_YYABORT;
- }
+ Select->add_joined_table($1);
+ Select->add_joined_table($3);
+ $$= $1->embedding;
}
- | select_derived union_head_non_top
+ | nested_table_reference_list ',' table_ref
{
- 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);
- }
- ;
-
-/* 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;
- }
- 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;
@@ -12155,83 +12101,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;
}
;
@@ -12365,9 +12282,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))
@@ -12463,7 +12385,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;
@@ -12480,7 +12402,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;
@@ -12540,7 +12462,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:
@@ -12664,70 +12586,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:
@@ -12737,63 +12624,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;
}
;
@@ -12856,6 +12741,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 */
| '+'
@@ -12925,14 +12881,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;
@@ -12952,6 +12905,7 @@ procedure_clause:
parameters are reduced.
*/
Lex->expr_allows_subselect= false;
+ Select->options|= OPTION_PROCEDURE_CLAUSE;
}
'(' procedure_list ')'
{
@@ -13035,6 +12989,7 @@ select_outvar:
into:
INTO into_destination
+ {}
;
into_destination:
@@ -13244,10 +13199,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;
}
;
@@ -13320,17 +13276,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:
@@ -13339,15 +13302,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:
@@ -13390,15 +13360,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;
@@ -13406,20 +13375,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:
@@ -13569,6 +13551,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;
@@ -13577,13 +13561,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;
}
/*
@@ -13593,7 +13578,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:
@@ -13640,9 +13632,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
;
@@ -13666,6 +13660,7 @@ delete_part2:
}
;
+
delete_single_table:
FROM table_ident opt_use_partition
{
@@ -13686,7 +13681,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);
@@ -13697,6 +13697,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
{
@@ -13708,9 +13711,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
@@ -13776,9 +13783,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;
}
@@ -13870,6 +13877,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();
@@ -13877,6 +13886,7 @@ show:
show_param
{
Select->parsing_place= NO_MATTER;
+ Lex->pop_select(); //main select
}
;
@@ -13892,40 +13902,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
@@ -13974,12 +13984,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;
@@ -14021,13 +14032,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;
@@ -14089,7 +14100,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;
}
@@ -14097,7 +14108,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;
}
@@ -14105,7 +14116,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;
}
@@ -14322,7 +14333,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;
@@ -14336,12 +14347,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
@@ -14362,6 +14374,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 {}
;
@@ -14404,8 +14418,7 @@ flush:
lex->type= 0;
lex->no_write_to_binlog= $2;
}
- flush_options
- {}
+ flush_options {}
;
flush_options:
@@ -14422,6 +14435,7 @@ flush_options:
opt_table_list opt_flush_lock
{}
| flush_options_list
+ {}
;
opt_flush_lock:
@@ -14677,7 +14691,7 @@ use:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CHANGE_DB;
- lex->select_lex.db= $2;
+ lex->first_select_lex()->db= $2;
}
;
@@ -14694,6 +14708,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
{
@@ -14723,7 +14739,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:
@@ -14921,11 +14941,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
@@ -14934,7 +14949,6 @@ hex_or_bin_String:
$1.length);
if (unlikely(tmp == NULL))
MYSQL_YYABORT;
- tmp->quick_fix_field();
$$= tmp->val_str((String*) 0);
}
| BIN_NUM
@@ -14947,7 +14961,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);
}
;
@@ -15095,26 +15108,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;
}
;
@@ -15130,17 +15140,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();
@@ -15169,15 +15183,14 @@ with_list_element:
MYSQL_YYABORT;
Lex->with_column_list.empty();
}
- AS '(' remember_tok_start subselect remember_tok_end ')'
+ AS '(' remember_tok_start query_expression remember_tok_end ')'
{
LEX *lex= thd->lex;
const char *query_start= lex->sphead ? lex->sphead->m_tmp_query
: thd->query();
char *spec_start= $6 + 1;
- 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 (elem->set_unparsed_spec(thd, spec_start, $8,
spec_start - query_start))
@@ -16149,14 +16162,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
@@ -16166,6 +16187,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
{}
@@ -16557,14 +16581,14 @@ opt_for_user:
;
text_or_password:
- TEXT_STRING { Lex->definer->pwhash= $1;}
+ TEXT_STRING { Lex->definer->auth= $1;}
| PASSWORD_SYM '(' TEXT_STRING ')' { Lex->definer->pwtext= $3; }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{
Lex->definer->pwtext= $3;
- Lex->definer->pwhash.str= Item_func_password::alloc(thd,
+ Lex->definer->auth.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD);
- Lex->definer->pwhash.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ Lex->definer->auth.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
;
@@ -16634,7 +16658,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);
@@ -16679,27 +16703,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))
@@ -16713,15 +16746,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");
@@ -17130,13 +17172,11 @@ grant_user:
{
$$= $1;
$1->pwtext= $4;
- if (unlikely(Lex->sql_command == SQLCOM_REVOKE))
- MYSQL_YYABORT;
}
| user IDENTIFIED_SYM BY PASSWORD_SYM TEXT_STRING
{
$$= $1;
- $1->pwhash= $5;
+ $1->auth= $5;
}
| user IDENTIFIED_SYM via_or_with ident_or_text
{
@@ -17144,12 +17184,20 @@ grant_user:
$1->plugin= $4;
$1->auth= empty_clex_str;
}
- | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as TEXT_STRING_sys
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ TEXT_STRING_sys
{
$$= $1;
$1->plugin= $4;
$1->auth= $6;
}
+ | user IDENTIFIED_SYM via_or_with ident_or_text using_or_as
+ PASSWORD_SYM '(' TEXT_STRING ')'
+ {
+ $$= $1;
+ $1->plugin= $4;
+ $1->pwtext= $8;
+ }
| user_or_role
{ $$= $1; }
;
@@ -17373,83 +17421,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; }
@@ -17457,128 +17438,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;
@@ -17587,18 +17450,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; }
;
@@ -17686,35 +17539,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; }
@@ -17815,11 +17647,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..9ff52bccb40 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -227,12 +227,11 @@ struct AUTHID
struct LEX_USER: public AUTHID
{
- LEX_CSTRING plugin, auth;
- LEX_CSTRING pwtext, pwhash;
+ LEX_CSTRING plugin, auth, pwtext;
void reset_auth()
{
- pwtext.length= pwhash.length= plugin.length= auth.length= 0;
- pwtext.str= pwhash.str= 0;
+ pwtext.length= plugin.length= auth.length= 0;
+ pwtext.str= 0;
plugin.str= auth.str= "";
}
};
@@ -758,6 +757,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 +830,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/sys_vars.ic b/sql/sys_vars.ic
index 373df354268..dbc3565e202 100644
--- a/sql/sys_vars.ic
+++ b/sql/sys_vars.ic
@@ -2659,7 +2659,7 @@ public:
if (!Sys_var_enum::do_check(thd, var))
return false;
MYSQL_TIME ltime;
- bool res= var->value->get_date(&ltime, 0);
+ bool res= var->value->get_date(thd, &ltime, date_mode_t(0));
if (!res)
{
var->save_result.ulonglong_value= SYSTEM_TIME_AS_OF;
@@ -2676,7 +2676,7 @@ private:
{
if (var->value)
{
- res= var->value->get_date(&out.ltime, 0);
+ res= var->value->get_date(current_thd, &out.ltime, date_mode_t(0));
}
else // set DEFAULT from global var
{
diff --git a/sql/table.cc b/sql/table.cc
index ccb580badf3..6c3e350f07d 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 */
@@ -344,8 +345,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);
@@ -917,6 +918,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
@@ -1147,6 +1196,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
@@ -1193,8 +1274,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;
@@ -1290,10 +1370,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;
@@ -1784,83 +1864,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)
{
@@ -1874,32 +1890,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
@@ -1913,7 +1918,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)
@@ -1921,26 +1928,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:
@@ -1948,26 +1992,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;
@@ -1975,17 +2019,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,
@@ -2016,7 +2061,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:
@@ -2038,22 +2083,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);
@@ -2077,10 +2117,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;
@@ -2103,7 +2144,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)
@@ -2695,7 +2736,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())
@@ -2884,7 +2925,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));
}
@@ -2939,7 +2980,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))
@@ -2983,7 +3024,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)
@@ -3440,17 +3481,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;
@@ -3653,7 +3683,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));
@@ -4909,7 +4939,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);
@@ -4969,13 +4999,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;
@@ -5012,7 +5042,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)
{
@@ -5054,7 +5085,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 */
@@ -5172,7 +5203,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)
{
@@ -5234,7 +5265,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;
}
@@ -5278,7 +5309,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;
}
@@ -5370,7 +5401,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))
@@ -5537,7 +5569,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);
@@ -5729,6 +5761,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);
}
@@ -5745,14 +5778,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 (;;)
{
@@ -5923,7 +5956,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");
@@ -5934,13 +5967,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))
{
@@ -5954,8 +5987,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));
@@ -6278,13 +6312,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
}
@@ -6431,13 +6464,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;
}
@@ -6516,13 +6544,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;
@@ -6719,49 +6741,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
@@ -6803,13 +6788,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;
}
}
@@ -6940,8 +6925,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);
}
@@ -7695,6 +7678,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
@@ -7758,17 +7755,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))
{
@@ -7788,7 +7785,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;
}
@@ -7797,8 +7794,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))
@@ -7832,7 +7831,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());
}
@@ -8497,200 +8498,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[]=
@@ -8778,7 +8585,7 @@ bool TR_table::update(ulonglong start_id, ulonglong end_id)
store(FLD_BEGIN_TS, thd->transaction_time());
thd->set_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);
@@ -8799,7 +8606,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);
@@ -8829,7 +8636,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);
@@ -8859,7 +8666,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
if (res > 0)
{
MYSQL_TIME commit_ts;
- if ((*this)[FLD_COMMIT_TS]->get_date(&commit_ts, 0))
+ if ((*this)[FLD_COMMIT_TS]->get_date(&commit_ts, date_mode_t(0)))
{
found= false;
break;
@@ -9078,7 +8885,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 7236fb91b0f..2b3fe1c20d4 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1155,8 +1155,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;
@@ -1377,7 +1375,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();
@@ -1399,39 +1399,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? */
@@ -2611,8 +2593,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);
void remove_join_columns()
{
diff --git a/sql/table_cache.cc b/sql/table_cache.cc
index cb9583a2440..682f9455d26 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..67a8e783208 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -70,12 +70,16 @@ static DWORD fls;
static bool skip_completion_port_on_success = false;
+PTP_CALLBACK_ENVIRON get_threadpool_win_callback_environ()
+{
+ return pool? &callback_environ: 0;
+}
+
/*
Threadpool callbacks.
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 +93,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 +121,6 @@ public:
PTP_CALLBACK_INSTANCE callback_instance;
PTP_IO io;
PTP_TIMER timer;
- PTP_WAIT shm_read;
PTP_WORK work;
bool long_callback;
@@ -139,7 +139,15 @@ struct TP_connection *new_TP_connection(CONNECT *connect)
void TP_pool_win::add(TP_connection *c)
{
- SubmitThreadpoolWork(((TP_connection_win *)c)->work);
+ if(FlsGetValue(fls))
+ {
+ /* Inside threadpool(), execute callback directly. */
+ tp_callback(c);
+ }
+ else
+ {
+ SubmitThreadpoolWork(((TP_connection_win *)c)->work);
+ }
}
@@ -149,7 +157,6 @@ TP_connection_win::TP_connection_win(CONNECT *c) :
callback_instance(0),
io(0),
timer(0),
- shm_read(0),
work(0)
{
}
@@ -170,30 +177,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)
- {
- CHECK_ALLOC_ERROR(shm_read= CreateThreadpoolWait(shm_read_callback, this, &callback_environ));
- }
- else
+
+ /* Performance tweaks (s. MSDN documentation)*/
+ UCHAR flags= FILE_SKIP_SET_EVENT_ON_HANDLE;
+ if (skip_completion_port_on_success)
{
- /* 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));
+ 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));
CHECK_ALLOC_ERROR(timer= CreateThreadpoolTimer(timer_callback, this, &callback_environ));
CHECK_ALLOC_ERROR(work= CreateThreadpoolWork(work_callback, this, &callback_environ));
return 0;
@@ -214,11 +211,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 +289,6 @@ TP_connection_win::~TP_connection_win()
if (io)
CloseThreadpoolIo(io);
- if (shm_read)
- CloseThreadpoolWait(shm_read);
-
if (work)
CloseThreadpoolWork(work);
@@ -312,14 +301,13 @@ TP_connection_win::~TP_connection_win()
void TP_connection_win::wait_begin(int type)
{
-
/*
Signal to the threadpool whenever callback can run long. Currently, binlog
waits are a good candidate, its waits are really long
*/
if (type == THD_WAIT_BINLOG)
{
- if (!long_callback)
+ if (!long_callback && callback_instance)
{
CallbackMayRunLong(callback_instance);
long_callback= true;
@@ -332,12 +320,11 @@ void TP_connection_win::wait_end()
/* Do we need to do anything ? */
}
-/*
- This function should be called first whenever a callback is invoked in the
+/*
+ This function should be called first whenever a callback is invoked in the
threadpool, does my_thread_init() if not yet done
*/
-extern ulong thread_created;
-static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
+void tp_win_callback_prolog()
{
if (FlsGetValue(fls) == NULL)
{
@@ -347,6 +334,12 @@ static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
InterlockedIncrement((volatile long *)&tp_stats.num_worker_threads);
my_thread_init();
}
+}
+
+extern ulong thread_created;
+static void pre_callback(PVOID context, PTP_CALLBACK_INSTANCE instance)
+{
+ tp_win_callback_prolog();
TP_connection_win *c = (TP_connection_win *)context;
c->callback_instance = instance;
c->long_callback = false;
@@ -420,29 +413,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 89eac6b3d00..bc52bff0de9 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1363,7 +1363,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;
@@ -1445,7 +1445,7 @@ static int wsrep_drop_table_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;
String buff;
@@ -1516,7 +1516,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)
@@ -2730,10 +2730,11 @@ bool wsrep_create_like_table(THD* thd, TABLE_LIST* table,
}
return(false);
-
-WSREP_ERROR_LABEL:
+#ifdef WITH_WSREP
+wsrep_error_label:
thd->wsrep_TOI_pre_query= NULL;
return (true);
+#endif
}