summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/debug_sync.cc1
-rw-r--r--sql/event_db_repository.cc5
-rw-r--r--sql/field.cc213
-rw-r--r--sql/field.h81
-rw-r--r--sql/filesort.cc4
-rw-r--r--sql/ha_ndbcluster.cc7
-rw-r--r--sql/ha_partition.cc33
-rw-r--r--sql/ha_partition.h3
-rw-r--r--sql/handler.cc7
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc11
-rw-r--r--sql/item_buff.cc9
-rw-r--r--sql/item_func.h9
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/keycaches.cc4
-rw-r--r--sql/log.cc221
-rw-r--r--sql/log.h57
-rw-r--r--sql/log_event.cc19
-rw-r--r--sql/log_event_old.cc36
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/mysqld.h6
-rw-r--r--sql/opt_range.cc8
-rw-r--r--sql/rpl_rli.cc3
-rw-r--r--sql/slave.cc5
-rw-r--r--sql/sp.cc1
-rw-r--r--sql/sp_head.cc7
-rw-r--r--sql/sql_acl.cc31
-rw-r--r--sql/sql_audit.h18
-rw-r--r--sql/sql_base.cc164
-rw-r--r--sql/sql_base.h13
-rw-r--r--sql/sql_class.cc38
-rw-r--r--sql/sql_class.h13
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_expression_cache.cc2
-rw-r--r--sql/sql_insert.cc160
-rw-r--r--sql/sql_lex.cc3
-rw-r--r--sql/sql_load.cc62
-rw-r--r--sql/sql_parse.cc41
-rw-r--r--sql/sql_partition.cc3
-rw-r--r--sql/sql_prepare.cc14
-rw-r--r--sql/sql_select.cc261
-rw-r--r--sql/sql_select.h20
-rw-r--r--sql/sql_show.cc77
-rw-r--r--sql/sql_string.cc18
-rw-r--r--sql/sql_string.h1
-rw-r--r--sql/sql_table.cc89
-rw-r--r--sql/sql_table.h4
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc54
-rw-r--r--sql/sql_yacc.yy15
-rw-r--r--sql/sys_vars.h15
-rw-r--r--sql/table.cc175
-rw-r--r--sql/table.h47
53 files changed, 1179 insertions, 934 deletions
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index 3ef1f22e2b8..6c8eae82a47 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -984,6 +984,7 @@ static bool debug_sync_eval_action(THD *thd, char *action_str)
DBUG_ENTER("debug_sync_eval_action");
DBUG_ASSERT(thd);
DBUG_ASSERT(action_str);
+ DBUG_PRINT("debug_sync", ("action_str='%s'", action_str));
/*
Get debug sync point name. Or a special command.
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index d77c6e3a683..12d34580d3c 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -830,9 +830,6 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
(int) table->field[ET_FIELD_ON_COMPLETION]->val_int()))
goto end;
- /* Don't update create on row update. */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
/*
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
@@ -1134,8 +1131,6 @@ update_timing_fields_for_event(THD *thd,
goto end;
store_record(table, record[1]);
- /* Don't update create on row update. */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
diff --git a/sql/field.cc b/sql/field.cc
index e0ecd6ab74f..a18c72119be 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -50,11 +50,6 @@
Instansiate templates and static variables
*****************************************************************************/
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<Create_field>;
-template class List_iterator<Create_field>;
-#endif
-
static const char *zero_timestamp="0000-00-00 00:00:00.000000";
/* number of bytes to store second_part part of the TIMESTAMP(N) */
@@ -1817,6 +1812,10 @@ Field *Field::new_field(MEM_ROOT *root, TABLE *new_table,
tmp->key_start.init(0);
tmp->part_of_key.init(0);
tmp->part_of_sortkey.init(0);
+ /*
+ TODO: it is not clear why this method needs to reset unireg_check.
+ Try not to reset it, or explain why it needs to be reset.
+ */
tmp->unireg_check= Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
@@ -4369,16 +4368,10 @@ void Field_double::sql_type(String &res) const
2038-01-01 00:00:00 UTC stored as number of seconds since Unix
Epoch in UTC.
- Up to one of timestamps columns in the table can be automatically
- set on row update and/or have NOW() as default value.
- TABLE::timestamp_field points to Field object for such timestamp with
- auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this
- field, and is used by handler code which performs updates required.
-
Actually SQL-99 says that we should allow niladic functions (like NOW())
- as defaults for any field. Current limitations (only NOW() and only
- for one TIMESTAMP field) are because of restricted binary .frm format
- and should go away in the future.
+ as defaults for any field. The current limitation (only NOW() and only
+ for TIMESTAMP and DATETIME fields) are because of restricted binary .frm
+ format and should go away in the future.
Also because of this limitation of binary .frm format we use 5 different
unireg_check values with TIMESTAMP field to distinguish various cases of
@@ -4419,10 +4412,12 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
flags|= UNSIGNED_FLAG | BINARY_FLAG;
- if (unireg_check != NONE && !share->timestamp_field)
+ if (unireg_check != NONE)
{
- /* This timestamp has auto-update */
- share->timestamp_field= this;
+ /*
+ We mark the flag with TIMESTAMP_FLAG to indicate to the client that
+ this field will be automaticly updated on insert.
+ */
flags|= TIMESTAMP_FLAG;
if (unireg_check != TIMESTAMP_DN_FIELD)
flags|= ON_UPDATE_NOW_FLAG;
@@ -4430,40 +4425,6 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
}
-/**
- Get auto-set type for TIMESTAMP field.
-
- Returns value indicating during which operations this TIMESTAMP field
- should be auto-set to current timestamp.
-*/
-timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
-{
- switch (unireg_check)
- {
- case TIMESTAMP_DN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_INSERT;
- case TIMESTAMP_UN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_UPDATE;
- case TIMESTAMP_OLD_FIELD:
- /*
- Although we can have several such columns in legacy tables this
- function should be called only for first of them (i.e. the one
- having auto-set property).
- */
- DBUG_ASSERT(table->timestamp_field == this);
- /* Fall-through */
- case TIMESTAMP_DNUN_FIELD:
- return TIMESTAMP_AUTO_SET_ON_BOTH;
- default:
- /*
- Normally this function should not be called for TIMESTAMPs without
- auto-set property.
- */
- DBUG_ASSERT(0);
- return TIMESTAMP_NO_AUTO_SET;
- }
-}
-
my_time_t Field_timestamp::get_timestamp(ulong *sec_part) const
{
ASSERT_COLUMN_MARKED_FOR_READ;
@@ -4713,6 +4674,34 @@ int Field_timestamp::set_time()
return 0;
}
+/**
+ Mark the field as having an explicit default value.
+
+ @param value if available, the value that the field is being set to
+
+ @note
+ Fields that have an explicit default value should not be updated
+ automatically via the DEFAULT or ON UPDATE functions. The functions
+ that deal with data change functionality (INSERT/UPDATE/LOAD),
+ determine if there is an explicit value for each field before performing
+ the data change, and call this method to mark the field.
+
+ For timestamp columns, the only case where a column is not marked
+ as been given a value are:
+ - It's explicitly assigned with DEFAULT
+ - We assign NULL to a timestamp field that is defined as NOT NULL.
+ This is how MySQL has worked since it's start.
+*/
+
+void Field_timestamp::set_explicit_default(Item *value)
+{
+ if (((value->type() == Item::DEFAULT_VALUE_ITEM &&
+ !((Item_default_value*)value)->arg) ||
+ (!maybe_null() && value->is_null())))
+ return;
+ set_has_explicit_value();
+}
+
void Field_timestamp_hires::sql_type(String &res) const
{
CHARSET_INFO *cs=res.charset();
@@ -5834,6 +5823,20 @@ void Field_datetime::sql_type(String &res) const
res.set_ascii(STRING_WITH_LEN("datetime"));
}
+
+int Field_datetime::set_time()
+{
+ THD *thd= table->in_use;
+ MYSQL_TIME now_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();
+ store_TIME(&now_time);
+ thd->time_zone_used= 1;
+ return 0;
+}
+
+
void Field_datetime_hires::store_TIME(MYSQL_TIME *ltime)
{
ulonglong packed= sec_part_shift(pack_time(ltime), dec);
@@ -8855,16 +8858,37 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
{
uint sign_len, allowed_type_modifier= 0;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
+ const bool on_update_is_function=
+ (fld_on_update_value != NULL &&
+ fld_on_update_value->type() == Item::FUNC_ITEM);
DBUG_ENTER("Create_field::init()");
field= 0;
field_name= fld_name;
- def= fld_default_value;
flags= fld_type_modifier;
option_list= create_opt;
- unireg_check= (fld_type_modifier & AUTO_INCREMENT_FLAG ?
- Field::NEXT_NUMBER : Field::NONE);
+
+ if (fld_default_value != NULL && fld_default_value->type() == Item::FUNC_ITEM)
+ {
+ /* There is a function default for insertions. */
+ def= NULL;
+ unireg_check= (on_update_is_function ?
+ Field::TIMESTAMP_DNUN_FIELD : // for insertions and for updates.
+ Field::TIMESTAMP_DN_FIELD); // only for insertions.
+ }
+ else
+ {
+ /* No function default for insertions. Either NULL or a constant. */
+ def= fld_default_value;
+ if (on_update_is_function)
+ unireg_check= Field::TIMESTAMP_UN_FIELD; // function default for updates
+ else
+ unireg_check= ((fld_type_modifier & AUTO_INCREMENT_FLAG) != 0 ?
+ Field::NEXT_NUMBER : // Automatic increment.
+ Field::NONE);
+ }
+
decimals= fld_decimals ? (uint)atoi(fld_decimals) : 0;
if (decimals >= NOT_FIXED_DEC)
{
@@ -9085,44 +9109,6 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
flags|= UNSIGNED_FLAG;
-
- if (fld_default_value)
- {
- /* Grammar allows only NOW() value for ON UPDATE clause */
- if (fld_default_value->type() == Item::FUNC_ITEM &&
- ((Item_func*)fld_default_value)->functype() == Item_func::NOW_FUNC)
- {
- unireg_check= (fld_on_update_value ? Field::TIMESTAMP_DNUN_FIELD:
- Field::TIMESTAMP_DN_FIELD);
- /*
- We don't need default value any longer moreover it is dangerous.
- Everything handled by unireg_check further.
- */
- def= 0;
- }
- else
- unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD:
- Field::NONE);
- }
- else
- {
- /*
- If we have default TIMESTAMP NOT NULL column without explicit DEFAULT
- or ON UPDATE values then for the sake of compatiblity we should treat
- this column as having DEFAULT NOW() ON UPDATE NOW() (when we don't
- have another TIMESTAMP column with auto-set option before this one)
- or DEFAULT 0 (in other cases).
- So here we are setting TIMESTAMP_OLD_FIELD only temporary, and will
- replace this value by TIMESTAMP_DNUN_FIELD or NONE later when
- information about all TIMESTAMP fields in table will be availiable.
-
- If we have TIMESTAMP NULL column without explicit DEFAULT value
- we treat it as having DEFAULT NULL attribute.
- */
- unireg_check= (fld_on_update_value ? Field::TIMESTAMP_UN_FIELD :
- (flags & NOT_NULL_FLAG ? Field::TIMESTAMP_OLD_FIELD :
- Field::NONE));
- }
break;
case MYSQL_TYPE_DATE:
/* We don't support creation of MYSQL_TYPE_DATE anymore */
@@ -9588,11 +9574,18 @@ Create_field::Create_field(Field *old_field,Field *orig_field)
def=0;
char_length= length;
- if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
- old_field->ptr && orig_field &&
- (sql_type != MYSQL_TYPE_TIMESTAMP || /* set def only if */
- old_field->table->timestamp_field != old_field || /* timestamp field */
- unireg_check == Field::TIMESTAMP_UN_FIELD)) /* has default val */
+ /*
+ Copy the default value from the column object orig_field, if:
+ 1) The column has a constant default value.
+ 2) The column type is not a BLOB type.
+ 3) The original column (old_field) was properly initialized with a record
+ buffer pointer.
+ 4) The original column doesn't have a default function to auto-initialize
+ the column on INSERT
+ */
+ if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && // 1) 2)
+ old_field->ptr && orig_field && // 3)
+ !old_field->has_insert_default_function()) // 4)
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff), charset);
@@ -9776,3 +9769,29 @@ key_map Field::get_possible_keys()
return (table->pos_in_table_list->is_materialized_derived() ?
part_of_key : key_start);
}
+
+
+/**
+ Mark the field as having an explicit default value.
+
+ @param value if available, the value that the field is being set to
+
+ @note
+ Fields that have an explicit default value should not be updated
+ automatically via the DEFAULT or ON UPDATE functions. The functions
+ that deal with data change functionality (INSERT/UPDATE/LOAD),
+ determine if there is an explicit value for each field before performing
+ the data change, and call this method to mark the field.
+
+ If the 'value' parameter is NULL, then the field is marked unconditionally
+ as having an explicit value. If 'value' is not NULL, then it can be further
+ analyzed to check if it really should count as a value.
+*/
+
+void Field::set_explicit_default(Item *value)
+{
+ if (value->type() == Item::DEFAULT_VALUE_ITEM &&
+ !((Item_default_value*)value)->arg)
+ return;
+ set_has_explicit_value();
+}
diff --git a/sql/field.h b/sql/field.h
index f22bab0409d..da78a7c7674 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -329,6 +329,46 @@ public:
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
(null_ptr[l_offset] & null_bit));
}
+
+ bool has_insert_default_function() const
+ {
+ return unireg_check == TIMESTAMP_DN_FIELD ||
+ unireg_check == TIMESTAMP_DNUN_FIELD;
+ }
+
+ bool has_update_default_function() const
+ {
+ return unireg_check == TIMESTAMP_UN_FIELD ||
+ unireg_check == TIMESTAMP_DNUN_FIELD;
+ }
+
+ /*
+ Mark the field as having a value supplied by the client, thus it should
+ not be auto-updated.
+ */
+ void set_has_explicit_value()
+ {
+ flags|= HAS_EXPLICIT_VALUE;
+ }
+
+ virtual void set_explicit_default(Item *value);
+
+ /**
+ Evaluates the @c INSERT default function and stores the result in the
+ field. If no such function exists for the column, or the function is not
+ valid for the column's data type, invoking this function has no effect.
+ */
+ virtual int evaluate_insert_default_function() { return 0; }
+
+
+ /**
+ Evaluates the @c UPDATE default function, if one exists, and stores the
+ result in the record buffer. If no such function exists for the column,
+ or the function is not valid for the column's data type, invoking this
+ function has no effect.
+ */
+ virtual int evaluate_update_default_function() { return 0; }
+
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
@@ -1239,12 +1279,26 @@ public:
virtual int set_time();
virtual void set_default()
{
- if (table->timestamp_field == this &&
- unireg_check != TIMESTAMP_UN_FIELD)
+ if (has_insert_default_function())
set_time();
else
Field::set_default();
}
+ virtual void set_explicit_default(Item *value);
+ virtual int evaluate_insert_default_function()
+ {
+ int res= 0;
+ if (has_insert_default_function())
+ res= set_time();
+ return res;
+ }
+ virtual int evaluate_update_default_function()
+ {
+ int res= 0;
+ if (has_update_default_function())
+ res= set_time();
+ return res;
+ }
/* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
virtual my_time_t get_timestamp(ulong *sec_part) const;
virtual void store_TIME(my_time_t timestamp, ulong sec_part)
@@ -1252,7 +1306,6 @@ public:
int4store(ptr,timestamp);
}
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
- timestamp_auto_set_type get_auto_set_type() const;
uchar *pack(uchar *to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -1503,6 +1556,28 @@ public:
void sql_type(String &str) const;
bool zero_pack() const { return 1; }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ virtual int set_time();
+ virtual void set_default()
+ {
+ if (has_insert_default_function())
+ set_time();
+ else
+ Field::set_default();
+ }
+ virtual int evaluate_insert_default_function()
+ {
+ int res= 0;
+ if (has_insert_default_function())
+ res= set_time();
+ return res;
+ }
+ virtual int evaluate_update_default_function()
+ {
+ int res= 0;
+ if (has_update_default_function())
+ res= set_time();
+ return res;
+ }
uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
{
diff --git a/sql/filesort.cc b/sql/filesort.cc
index ac67fb56395..c612d2c55cb 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -45,10 +45,6 @@
if (my_b_write((file),(uchar*) (from),param->ref_length)) \
DBUG_RETURN(1);
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class Bounded_queue<uchar, uchar>;
-#endif
-
/* functions defined in this file */
static uchar *read_buffpek_from_file(IO_CACHE *buffer_file, uint count,
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 2878f25ed14..6ba4fe46441 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -2906,8 +2906,6 @@ int ha_ndbcluster::write_row(uchar *record)
}
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
if (!(op= trans->getNdbOperation(m_table)))
ERR_RETURN(trans->getNdbError());
@@ -3146,11 +3144,6 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data)
}
ha_statistic_increment(&SSV::ha_update_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- {
- table->timestamp_field->set_time();
- bitmap_set_bit(table->write_set, table->timestamp_field->field_index);
- }
if (m_use_partition_function &&
(error= get_parts_for_update(old_data, new_data, table->record[0],
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 2804da8e7ae..a24d144c97b 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -298,13 +298,6 @@ void ha_partition::init_handler_variables()
}
-const char *ha_partition::table_type() const
-{
- // we can do this since we only support a single engine type
- return m_file[0]->table_type();
-}
-
-
/*
Destructor method
@@ -3446,8 +3439,8 @@ void ha_partition::try_semi_consistent_read(bool yes)
ADDITIONAL INFO:
- We have to set timestamp fields and auto_increment fields, because those
- may be used in determining which partition the row should be written to.
+ We have to set auto_increment fields, because those may be used in
+ determining which partition the row should be written to.
*/
int ha_partition::write_row(uchar * buf)
@@ -3458,7 +3451,6 @@ int ha_partition::write_row(uchar * buf)
bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map;
THD *thd= ha_thd();
- timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type;
ulonglong saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
#ifdef NOT_NEEDED
@@ -3467,11 +3459,6 @@ int ha_partition::write_row(uchar * buf)
DBUG_ENTER("ha_partition::write_row");
DBUG_ASSERT(buf == m_rec0);
- /* If we have a timestamp column, update it to the current time */
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
/*
If we have an auto_increment column and we are writing a changed row
or a new row, then update the auto_increment value in the record.
@@ -3547,7 +3534,6 @@ int ha_partition::write_row(uchar * buf)
exit:
thd->variables.sql_mode= saved_sql_mode;
table->auto_increment_field_not_null= saved_auto_inc_field_not_null;
- table->timestamp_field_type= saved_timestamp_type;
DBUG_RETURN(error);
}
@@ -3582,18 +3568,8 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
uint32 new_part_id, old_part_id;
int error= 0;
longlong func_value;
- timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type;
DBUG_ENTER("ha_partition::update_row");
- /*
- We need to set timestamp field once before we calculate
- the partition. Then we disable timestamp calculations
- inside m_file[*]->update_row() methods
- */
- if (orig_timestamp_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
if ((error= get_parts_for_update(old_data, new_data, table->record[0],
m_part_info, &old_part_id, &new_part_id,
&func_value)))
@@ -3667,7 +3643,6 @@ exit:
info(HA_STATUS_AUTO);
set_auto_increment_if_higher(table->found_next_number_field);
}
- table->timestamp_field_type= orig_timestamp_type;
DBUG_RETURN(error);
}
@@ -4680,8 +4655,8 @@ int ha_partition::common_index_read(uchar *buf, bool have_start_key)
bool reverse_order= FALSE;
DBUG_ENTER("ha_partition::common_index_read");
- DBUG_PRINT("info", ("m_ordered %u m_ordered_scan_ong %u have_start_key %u",
- m_ordered, m_ordered_scan_ongoing, have_start_key));
+ DBUG_PRINT("info", ("m_ordered: %u have_start_key: %u",
+ m_ordered, have_start_key));
if (have_start_key)
{
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 3a0a35fdfc0..7818e1e608f 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -637,9 +637,6 @@ public:
*/
virtual const char *index_type(uint inx);
- /* The name of the table type that will be used for display purposes */
- virtual const char *table_type() const;
-
/* The name of the row type used for the underlying tables. */
virtual enum row_type get_row_type() const;
diff --git a/sql/handler.cc b/sql/handler.cc
index 271ed73ad53..bf84b1287d5 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -5363,10 +5363,6 @@ int handler::ha_write_row(uchar *buf)
DBUG_ENTER("handler::ha_write_row");
DEBUG_SYNC_C("ha_write_row_start");
- /* If we have a timestamp column, update it to the current time */
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
-
MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_write_count);
@@ -5397,9 +5393,6 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
*/
DBUG_ASSERT(new_data == table->record[0]);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
-
MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str);
mark_trx_read_write();
increment_statistics(&SSV::ha_update_count);
diff --git a/sql/handler.h b/sql/handler.h
index f043f1b44cd..997088b1192 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2487,7 +2487,7 @@ public:
{ return; } /* prepare InnoDB for HANDLER */
virtual void free_foreign_key_create_info(char* str) {}
/** The following can be called without an open handler */
- virtual const char *table_type() const =0;
+ const char *table_type() const { return hton_name(ht)->str; }
/**
If frm_error() is called then we will use this to find out what file
extentions exist for the storage engine. This is also used by the default
diff --git a/sql/item.cc b/sql/item.cc
index 5f4b34ea552..27e6d7052d6 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -9652,14 +9652,3 @@ const char *dbug_print_item(Item *item)
#endif /*DBUG_OFF*/
-/*****************************************************************************
-** Instantiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<Item>;
-template class List_iterator<Item>;
-template class List_iterator_fast<Item>;
-template class List_iterator_fast<Item_field>;
-template class List<List_item>;
-#endif
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 86e0fd32774..ce396736d6f 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -173,12 +173,3 @@ bool Cached_item_decimal::cmp()
return FALSE;
}
-
-/*****************************************************************************
-** Instansiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<Cached_item>;
-template class List_iterator<Cached_item>;
-#endif
diff --git a/sql/item_func.h b/sql/item_func.h
index 07b246b3ccd..80fa0b5d634 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1572,6 +1572,15 @@ public:
:Item_func(b), cached_result_type(INT_RESULT),
entry(NULL), entry_thread_id(0), name(a)
{}
+ Item_func_set_user_var(Item_func_set_user_var *item)
+ :Item_func(item), cached_result_type(item->cached_result_type),
+ entry(item->entry), entry_thread_id(item->entry_thread_id),
+ value(item->value), decimal_buff(item->decimal_buff),
+ null_item(item->null_item), save_result(item->save_result),
+ name(item->name)
+ {
+ //fixed= 1;
+ }
enum Functype functype() const { return SUSERVAR_FUNC; }
double val_real();
longlong val_int();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 0b21ba92558..b04fda55736 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -2510,9 +2510,8 @@ Item_sum_hybrid::min_max_update_int_field()
void
Item_sum_hybrid::min_max_update_decimal_field()
{
- /* TODO: optimize: do not get result_field in case of args[0] is NULL */
my_decimal old_val, nr_val;
- const my_decimal *old_nr= result_field->val_decimal(&old_val);
+ const my_decimal *old_nr;
const my_decimal *nr= args[0]->val_decimal(&nr_val);
if (!args[0]->null_value)
{
@@ -2520,16 +2519,17 @@ Item_sum_hybrid::min_max_update_decimal_field()
old_nr=nr;
else
{
+ old_nr= result_field->val_decimal(&old_val);
bool res= my_decimal_cmp(old_nr, nr) > 0;
/* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
if ((cmp_sign > 0) ^ (!res))
old_nr=nr;
}
result_field->set_notnull();
+ result_field->store_decimal(old_nr);
}
else if (result_field->is_null(0))
result_field->set_null();
- result_field->store_decimal(old_nr);
}
diff --git a/sql/keycaches.cc b/sql/keycaches.cc
index 26a39808c56..84ed67d00f0 100644
--- a/sql/keycaches.cc
+++ b/sql/keycaches.cc
@@ -159,7 +159,3 @@ bool process_key_caches(process_key_cache_t func, void *param)
return res != 0;
}
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class I_List_iterator<NAMED_ILINK>;
-#endif
-
diff --git a/sql/log.cc b/sql/log.cc
index 69ff68d335f..1813120dd81 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -54,6 +54,7 @@
#include "rpl_handler.h"
#include "debug_sync.h"
#include "sql_show.h"
+#include "my_pthread.h"
/* max size of the log message */
#define MAX_LOG_BUFFER_SIZE 1024
@@ -107,6 +108,17 @@ static SHOW_VAR binlog_status_vars_detail[]=
{NullS, NullS, SHOW_LONG}
};
+/*
+ Variables for the binlog background thread.
+ Protected by the MYSQL_BIN_LOG::LOCK_binlog_background_thread mutex.
+ */
+static bool binlog_background_thread_started= false;
+static bool binlog_background_thread_stop= false;
+static MYSQL_BIN_LOG::xid_count_per_binlog *
+ binlog_background_thread_queue= NULL;
+
+static bool start_binlog_background_thread();
+
/**
purge logs, master and slave sides both, related error code
@@ -1288,12 +1300,6 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
DBUG_ASSERT(thd);
- lock_shared();
- if (!opt_log)
- {
- unlock();
- return 0;
- }
user_host_len= make_user_name(thd, user_host_buff);
current_time= my_hrtime();
@@ -1304,15 +1310,19 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
command_name[(uint) command].length,
query, query_length);
- while (*current_handler)
- error|= (*current_handler++)->
- log_general(thd, current_time, user_host_buff,
- user_host_len, thd->thread_id,
- command_name[(uint) command].str,
- command_name[(uint) command].length,
- query, query_length,
- thd->variables.character_set_client) || error;
- unlock();
+ if (opt_log && log_command(thd, command))
+ {
+ lock_shared();
+ while (*current_handler)
+ error|= (*current_handler++)->
+ log_general(thd, current_time, user_host_buff,
+ user_host_len, thd->thread_id,
+ command_name[(uint) command].str,
+ command_name[(uint) command].length,
+ query, query_length,
+ thd->variables.character_set_client) || error;
+ unlock();
+ }
return error;
}
@@ -2972,12 +2982,28 @@ void MYSQL_BIN_LOG::cleanup()
my_free(b);
}
+ /* Wait for the binlog background thread to stop. */
+ if (!is_relay_log && binlog_background_thread_started)
+ {
+ mysql_mutex_lock(&LOCK_binlog_background_thread);
+ binlog_background_thread_stop= true;
+ mysql_cond_signal(&COND_binlog_background_thread);
+ while (binlog_background_thread_stop)
+ mysql_cond_wait(&COND_binlog_background_thread_end,
+ &LOCK_binlog_background_thread);
+ mysql_mutex_unlock(&LOCK_binlog_background_thread);
+ binlog_background_thread_started= false;
+ }
+
mysql_mutex_destroy(&LOCK_log);
mysql_mutex_destroy(&LOCK_index);
mysql_mutex_destroy(&LOCK_xid_list);
+ mysql_mutex_destroy(&LOCK_binlog_background_thread);
mysql_cond_destroy(&update_cond);
mysql_cond_destroy(&COND_queue_busy);
mysql_cond_destroy(&COND_xid_list);
+ mysql_cond_destroy(&COND_binlog_background_thread);
+ mysql_cond_destroy(&COND_binlog_background_thread_end);
}
DBUG_VOID_RETURN;
}
@@ -3003,6 +3029,13 @@ void MYSQL_BIN_LOG::init_pthread_objects()
mysql_cond_init(m_key_update_cond, &update_cond, 0);
mysql_cond_init(m_key_COND_queue_busy, &COND_queue_busy, 0);
mysql_cond_init(key_BINLOG_COND_xid_list, &COND_xid_list, 0);
+
+ mysql_mutex_init(key_BINLOG_LOCK_binlog_background_thread,
+ &LOCK_binlog_background_thread, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_BINLOG_COND_binlog_background_thread,
+ &COND_binlog_background_thread, 0);
+ mysql_cond_init(key_BINLOG_COND_binlog_background_thread_end,
+ &COND_binlog_background_thread_end, 0);
}
@@ -3100,6 +3133,10 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
+ if (!is_relay_log && !binlog_background_thread_started &&
+ start_binlog_background_thread())
+ DBUG_RETURN(1);
+
if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
io_cache_type_arg))
{
@@ -5548,18 +5585,14 @@ bool general_log_write(THD *thd, enum enum_server_command command,
const char *query, uint query_length)
{
/* Write the message to the log if we want to log this king of commands */
- if (logger.log_command(thd, command))
+ if (logger.log_command(thd, command) || mysql_audit_general_enabled())
return logger.general_log_write(thd, command, query, query_length);
return FALSE;
}
-/*
- I would like to make this function static, but this causes compiler warnings
- when it is declared as friend function in log.h.
-*/
-void
+static void
binlog_checkpoint_callback(void *cookie)
{
MYSQL_BIN_LOG::xid_count_per_binlog *entry=
@@ -7398,8 +7431,9 @@ int TC_LOG_MMAP::open(const char *opt_name)
syncing= 0;
active=pages;
+ DBUG_ASSERT(npages >= 2);
pool=pages+1;
- pool_last=pages+npages-1;
+ pool_last_ptr= &((pages+npages-1)->next);
commit_ordered_queue= NULL;
commit_ordered_queue_busy= false;
@@ -7432,8 +7466,8 @@ void TC_LOG_MMAP::get_active_from_pool()
do
{
best_p= p= &pool;
- if ((*p)->waiters == 0) // can the first page be used ?
- break; // yes - take it.
+ if ((*p)->waiters == 0 && (*p)->free > 0) // can the first page be used ?
+ break; // yes - take it.
best_free=0; // no - trying second strategy
for (p=&(*p)->next; *p; p=&(*p)->next)
@@ -7450,10 +7484,10 @@ void TC_LOG_MMAP::get_active_from_pool()
mysql_mutex_assert_owner(&LOCK_active);
active=*best_p;
- if ((*best_p)->next) // unlink the page from the pool
- *best_p=(*best_p)->next;
- else
- pool_last=*best_p;
+ /* Unlink the page from the pool. */
+ if (!(*best_p)->next)
+ pool_last_ptr= best_p;
+ *best_p=(*best_p)->next;
mysql_mutex_unlock(&LOCK_pool);
mysql_mutex_lock(&active->lock);
@@ -7560,12 +7594,9 @@ int TC_LOG_MMAP::log_one_transaction(my_xid xid)
mysql_mutex_unlock(&LOCK_active);
mysql_mutex_lock(&p->lock);
p->waiters++;
- for (;;)
+ while (p->state == PS_DIRTY && syncing)
{
- int not_dirty = p->state != PS_DIRTY;
mysql_mutex_unlock(&p->lock);
- if (not_dirty || !syncing)
- break;
mysql_cond_wait(&p->cond, &LOCK_sync);
mysql_mutex_lock(&p->lock);
}
@@ -7617,8 +7648,8 @@ int TC_LOG_MMAP::sync()
/* page is synced. let's move it to the pool */
mysql_mutex_lock(&LOCK_pool);
- pool_last->next=syncing;
- pool_last=syncing;
+ (*pool_last_ptr)=syncing;
+ pool_last_ptr=&(syncing->next);
syncing->next=0;
syncing->state= err ? PS_ERROR : PS_POOL;
mysql_cond_signal(&COND_pool); // in case somebody's waiting
@@ -8148,9 +8179,129 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
void
TC_LOG_BINLOG::commit_checkpoint_notify(void *cookie)
{
- mark_xid_done(((xid_count_per_binlog *)cookie)->binlog_id, true);
+ xid_count_per_binlog *entry= static_cast<xid_count_per_binlog *>(cookie);
+ mysql_mutex_lock(&LOCK_binlog_background_thread);
+ entry->next_in_queue= binlog_background_thread_queue;
+ binlog_background_thread_queue= entry;
+ mysql_cond_signal(&COND_binlog_background_thread);
+ mysql_mutex_unlock(&LOCK_binlog_background_thread);
}
+/*
+ Binlog background thread.
+
+ This thread is used to log binlog checkpoints in the background, rather than
+ in the context of random storage engine threads that happen to call
+ commit_checkpoint_notify_ha() and may not like the delays while syncing
+ binlog to disk or may not be setup with all my_thread_init() and other
+ necessary stuff.
+
+ In the future, this thread could also be used to do log rotation in the
+ background, which could elimiate all stalls around binlog rotations.
+*/
+pthread_handler_t
+binlog_background_thread(void *arg __attribute__((unused)))
+{
+ bool stop;
+ MYSQL_BIN_LOG::xid_count_per_binlog *queue, *next;
+ THD *thd;
+
+ my_thread_init();
+ thd= new THD;
+ thd->system_thread= SYSTEM_THREAD_BINLOG_BACKGROUND;
+ thd->thread_stack= (char*) &thd; /* Set approximate stack start */
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->thread_id= thread_id++;
+ mysql_mutex_unlock(&LOCK_thread_count);
+ thd->store_globals();
+
+ for (;;)
+ {
+ /*
+ Wait until there is something in the queue to process, or we are asked
+ to shut down.
+ */
+ THD_STAGE_INFO(thd, stage_binlog_waiting_background_tasks);
+ mysql_mutex_lock(&mysql_bin_log.LOCK_binlog_background_thread);
+ for (;;)
+ {
+ stop= binlog_background_thread_stop;
+ queue= binlog_background_thread_queue;
+ if (stop || queue)
+ break;
+ mysql_cond_wait(&mysql_bin_log.COND_binlog_background_thread,
+ &mysql_bin_log.LOCK_binlog_background_thread);
+ }
+ /* Grab the queue, if any. */
+ binlog_background_thread_queue= NULL;
+ mysql_mutex_unlock(&mysql_bin_log.LOCK_binlog_background_thread);
+
+ /* Process any incoming commit_checkpoint_notify() calls. */
+ while (queue)
+ {
+ THD_STAGE_INFO(thd, stage_binlog_processing_checkpoint_notify);
+ /* Grab next pointer first, as mark_xid_done() may free the element. */
+ next= queue->next_in_queue;
+ mysql_bin_log.mark_xid_done(queue->binlog_id, true);
+ queue= next;
+
+ DBUG_EXECUTE_IF("binlog_background_checkpoint_processed",
+ DBUG_ASSERT(!debug_sync_set_action(
+ thd,
+ STRING_WITH_LEN("now SIGNAL binlog_background_checkpoint_processed")));
+ );
+ }
+
+ if (stop)
+ break;
+ }
+
+ THD_STAGE_INFO(thd, stage_binlog_stopping_background_thread);
+
+ mysql_mutex_lock(&LOCK_thread_count);
+ delete thd;
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ my_thread_end();
+
+ /* Signal that we are (almost) stopped. */
+ mysql_mutex_lock(&mysql_bin_log.LOCK_binlog_background_thread);
+ binlog_background_thread_stop= false;
+ mysql_cond_signal(&mysql_bin_log.COND_binlog_background_thread_end);
+ mysql_mutex_unlock(&mysql_bin_log.LOCK_binlog_background_thread);
+
+ return 0;
+}
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_thread_key key_thread_binlog;
+
+static PSI_thread_info all_binlog_threads[]=
+{
+ { &key_thread_binlog, "binlog_background", PSI_FLAG_GLOBAL},
+};
+#endif /* HAVE_PSI_INTERFACE */
+
+static bool
+start_binlog_background_thread()
+{
+ pthread_t th;
+
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ PSI_server->register_thread("sql", all_binlog_threads,
+ array_elements(all_binlog_threads));
+#endif
+
+ if (mysql_thread_create(key_thread_binlog, &th, NULL,
+ binlog_background_thread, NULL))
+ return 1;
+
+ binlog_background_thread_started= true;
+ return 0;
+}
+
+
int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
IO_CACHE *first_log,
Format_description_log_event *fdle)
diff --git a/sql/log.h b/sql/log.h
index 3959411d83a..80fe34b5ff2 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -145,7 +145,7 @@ class TC_LOG_MMAP: public TC_LOG
my_off_t file_length;
uint npages, inited;
uchar *data;
- struct st_page *pages, *syncing, *active, *pool, *pool_last;
+ struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr;
/*
note that, e.g. LOCK_active is only used to protect
'active' pointer, to protect the content of the active page
@@ -395,8 +395,6 @@ private:
#define BINLOG_COOKIE_IS_DUMMY(c) \
( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID )
-void binlog_checkpoint_callback(void *cookie);
-
class binlog_cache_mngr;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
@@ -451,27 +449,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
};
/*
- A list of struct xid_count_per_binlog is used to keep track of how many
- XIDs are in prepared, but not committed, state in each binlog. And how
- many commit_checkpoint_request()'s are pending.
-
- When count drops to zero in a binlog after rotation, it means that there
- are no more XIDs in prepared state, so that binlog is no longer needed
- for XA crash recovery, and we can log a new binlog checkpoint event.
-
- The list is protected against simultaneous access from multiple
- threads by LOCK_xid_list.
- */
- struct xid_count_per_binlog : public ilink {
- char *binlog_name;
- uint binlog_name_len;
- ulong binlog_id;
- /* Total prepared XIDs and pending checkpoint requests in this binlog. */
- long xid_count;
- xid_count_per_binlog(); /* Give link error if constructor used. */
- };
- I_List<xid_count_per_binlog> binlog_xid_count_list;
- /*
When this is set, a RESET MASTER is in progress.
Then we should not write any binlog checkpoints into the binlog (that
@@ -480,7 +457,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
checkpoint arrives - when all have arrived, RESET MASTER will complete.
*/
bool reset_master_pending;
- friend void binlog_checkpoint_callback(void *cookie);
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
mysql_mutex_t LOCK_index;
@@ -550,10 +526,35 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
int write_transaction_or_stmt(group_commit_entry *entry);
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
- void mark_xid_done(ulong cookie, bool write_checkpoint);
- void mark_xids_active(ulong cookie, uint xid_count);
public:
+ /*
+ A list of struct xid_count_per_binlog is used to keep track of how many
+ XIDs are in prepared, but not committed, state in each binlog. And how
+ many commit_checkpoint_request()'s are pending.
+
+ When count drops to zero in a binlog after rotation, it means that there
+ are no more XIDs in prepared state, so that binlog is no longer needed
+ for XA crash recovery, and we can log a new binlog checkpoint event.
+
+ The list is protected against simultaneous access from multiple
+ threads by LOCK_xid_list.
+ */
+ struct xid_count_per_binlog : public ilink {
+ char *binlog_name;
+ uint binlog_name_len;
+ ulong binlog_id;
+ /* Total prepared XIDs and pending checkpoint requests in this binlog. */
+ long xid_count;
+ /* For linking in requests to the binlog background thread. */
+ xid_count_per_binlog *next_in_queue;
+ xid_count_per_binlog(); /* Give link error if constructor used. */
+ };
+ I_List<xid_count_per_binlog> binlog_xid_count_list;
+ mysql_mutex_t LOCK_binlog_background_thread;
+ mysql_cond_t COND_binlog_background_thread;
+ mysql_cond_t COND_binlog_background_thread_end;
+
using MYSQL_LOG::generate_name;
using MYSQL_LOG::is_open;
@@ -709,6 +710,8 @@ public:
bool appendv(const char* buf,uint len,...);
bool append(Log_event* ev);
+ void mark_xids_active(ulong cookie, uint xid_count);
+ void mark_xid_done(ulong cookie, bool write_checkpoint);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
bool can_purge_log(const char *log_file_name);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 13de7523054..fb9e6b7107f 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -9881,23 +9881,6 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability
*/
}
- /*
- We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill
- any TIMESTAMP column with data from the row but instead will use
- the event's current time.
- As we replicate from TIMESTAMP to TIMESTAMP and slave has no extra
- columns, we know that all TIMESTAMP columns on slave will receive explicit
- data from the row, so TIMESTAMP_NO_AUTO_SET is ok.
- When we allow a table without TIMESTAMP to be replicated to a table having
- more columns including a TIMESTAMP column, or when we allow a TIMESTAMP
- column to be replicated into a BIGINT column and the slave's table has a
- TIMESTAMP column, then the slave's TIMESTAMP column will take its value
- from set_time() which we called earlier (consistent with SBR). And then in
- some cases we won't want TIMESTAMP_NO_AUTO_SET (will require some code to
- analyze if explicit data is provided for slave's TIMESTAMP columns).
- */
- m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
/* Honor next number column if present */
m_table->next_number_field= m_table->found_next_number_field;
/*
@@ -10986,8 +10969,6 @@ Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability
if ((err= find_key()))
return err;
- m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
return 0;
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index d7c66af769a..bd837adc9d9 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -924,22 +924,6 @@ int Write_rows_log_event_old::do_before_row_operations(TABLE *table)
from the start.
*/
table->file->ha_start_bulk_insert(0);
- /*
- We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill
- any TIMESTAMP column with data from the row but instead will use
- the event's current time.
- As we replicate from TIMESTAMP to TIMESTAMP and slave has no extra
- columns, we know that all TIMESTAMP columns on slave will receive explicit
- data from the row, so TIMESTAMP_NO_AUTO_SET is ok.
- When we allow a table without TIMESTAMP to be replicated to a table having
- more columns including a TIMESTAMP column, or when we allow a TIMESTAMP
- column to be replicated into a BIGINT column and the slave's table has a
- TIMESTAMP column, then the slave's TIMESTAMP column will take its value
- from set_time() which we called earlier (consistent with SBR). And then in
- some cases we won't want TIMESTAMP_NO_AUTO_SET (will require some code to
- analyze if explicit data is provided for slave's TIMESTAMP columns).
- */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
return error;
}
@@ -1128,8 +1112,6 @@ int Update_rows_log_event_old::do_before_row_operations(TABLE *table)
if (!m_memory)
return HA_ERR_OUT_OF_MEM;
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
return error;
}
@@ -2589,22 +2571,6 @@ Write_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabil
from the start.
*/
m_table->file->ha_start_bulk_insert(0);
- /*
- We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill
- any TIMESTAMP column with data from the row but instead will use
- the event's current time.
- As we replicate from TIMESTAMP to TIMESTAMP and slave has no extra
- columns, we know that all TIMESTAMP columns on slave will receive explicit
- data from the row, so TIMESTAMP_NO_AUTO_SET is ok.
- When we allow a table without TIMESTAMP to be replicated to a table having
- more columns including a TIMESTAMP column, or when we allow a TIMESTAMP
- column to be replicated into a BIGINT column and the slave's table has a
- TIMESTAMP column, then the slave's TIMESTAMP column will take its value
- from set_time() which we called earlier (consistent with SBR). And then in
- some cases we won't want TIMESTAMP_NO_AUTO_SET (will require some code to
- analyze if explicit data is provided for slave's TIMESTAMP columns).
- */
- m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
return error;
}
@@ -2814,8 +2780,6 @@ Update_rows_log_event_old::do_before_row_operations(const Slave_reporting_capabi
return HA_ERR_OUT_OF_MEM;
}
- m_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
return 0;
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 28e2c43ca43..ea38d61cca2 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -747,6 +747,7 @@ PSI_mutex_key key_LOCK_des_key_file;
#endif /* HAVE_OPENSSL */
PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
+ key_BINLOG_LOCK_binlog_background_thread,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -789,6 +790,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0},
{ &key_BINLOG_LOCK_xid_list, "MYSQL_BIN_LOG::LOCK_xid_list", 0},
+ { &key_BINLOG_LOCK_binlog_background_thread, "MYSQL_BIN_LOG::LOCK_binlog_background_thread", 0},
{ &key_RELAYLOG_LOCK_index, "MYSQL_RELAY_LOG::LOCK_index", 0},
{ &key_delayed_insert_mutex, "Delayed_insert::mutex", 0},
{ &key_hash_filo_lock, "hash_filo::lock", 0},
@@ -857,6 +859,8 @@ PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
+ key_BINLOG_COND_binlog_background_thread,
+ key_BINLOG_COND_binlog_background_thread_end,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
@@ -886,6 +890,8 @@ static PSI_cond_info all_server_conds[]=
#endif /* HAVE_MMAP */
{ &key_BINLOG_COND_xid_list, "MYSQL_BIN_LOG::COND_xid_list", 0},
{ &key_BINLOG_update_cond, "MYSQL_BIN_LOG::update_cond", 0},
+ { &key_BINLOG_COND_binlog_background_thread, "MYSQL_BIN_LOG::COND_binlog_background_thread", 0},
+ { &key_BINLOG_COND_binlog_background_thread_end, "MYSQL_BIN_LOG::COND_binlog_background_thread_end", 0},
{ &key_BINLOG_COND_queue_busy, "MYSQL_BIN_LOG::COND_queue_busy", 0},
{ &key_RELAYLOG_update_cond, "MYSQL_RELAY_LOG::update_cond", 0},
{ &key_RELAYLOG_COND_queue_busy, "MYSQL_RELAY_LOG::COND_queue_busy", 0},
@@ -7259,8 +7265,8 @@ SHOW_VAR status_vars[]= {
{"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS},
{"Opened_views", (char*) offsetof(STATUS_VAR, opened_views), SHOW_LONG_STATUS},
{"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_SIMPLE_FUNC},
- {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS},
{"Rows_sent", (char*) offsetof(STATUS_VAR, rows_sent), SHOW_LONGLONG_STATUS},
+ {"Rows_read", (char*) offsetof(STATUS_VAR, rows_read), SHOW_LONGLONG_STATUS},
{"Rows_tmp_read", (char*) offsetof(STATUS_VAR, rows_tmp_read), SHOW_LONGLONG_STATUS},
#ifdef HAVE_QUERY_CACHE
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_NOFLUSH},
@@ -8820,6 +8826,9 @@ PSI_stage_info stage_slave_waiting_worker_to_release_partition= { 0, "Waiting fo
PSI_stage_info stage_slave_waiting_worker_to_free_events= { 0, "Waiting for Slave Workers to free pending events", 0};
PSI_stage_info stage_slave_waiting_worker_queue= { 0, "Waiting for Slave Worker queue", 0};
PSI_stage_info stage_slave_waiting_event_from_coordinator= { 0, "Waiting for an event from Coordinator", 0};
+PSI_stage_info stage_binlog_waiting_background_tasks= { 0, "Waiting for background binlog tasks", 0};
+PSI_stage_info stage_binlog_processing_checkpoint_notify= { 0, "Processing binlog checkpoint notification", 0};
+PSI_stage_info stage_binlog_stopping_background_thread= { 0, "Stopping binlog background thread", 0};
#ifdef HAVE_PSI_INTERFACE
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 7da96ca932e..a07efa9178f 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -230,6 +230,7 @@ extern PSI_mutex_key key_LOCK_des_key_file;
#endif
extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
+ key_BINLOG_LOCK_binlog_background_thread,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -261,6 +262,8 @@ extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
extern PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
+ key_BINLOG_COND_binlog_background_thread,
+ key_BINLOG_COND_binlog_background_thread_end,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
@@ -402,6 +405,9 @@ extern PSI_stage_info stage_slave_waiting_worker_to_free_events;
extern PSI_stage_info stage_slave_waiting_worker_queue;
extern PSI_stage_info stage_slave_waiting_event_from_coordinator;
extern PSI_stage_info stage_slave_waiting_workers_to_exit;
+extern PSI_stage_info stage_binlog_waiting_background_tasks;
+extern PSI_stage_info stage_binlog_processing_checkpoint_notify;
+extern PSI_stage_info stage_binlog_stopping_background_thread;
#ifdef HAVE_PSI_STATEMENT_INTERFACE
/**
Statement instrumentation keys (sql).
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 67bc1639f2d..8aeb89ed9ed 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -14137,11 +14137,3 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
#endif /* !DBUG_OFF */
-/*****************************************************************************
-** Instantiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<QUICK_RANGE>;
-template class List_iterator<QUICK_RANGE>;
-#endif
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 8c01e979226..364dfb3bc20 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -59,6 +59,7 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");
+ relay_log.is_relay_log= TRUE;
#ifdef HAVE_PSI_INTERFACE
relay_log.set_psi_keys(key_RELAYLOG_LOCK_index,
key_RELAYLOG_update_cond,
@@ -217,8 +218,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
&mi->connection_name);
}
- rli->relay_log.is_relay_log= TRUE;
-
/*
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
diff --git a/sql/slave.cc b/sql/slave.cc
index e1bac640e00..95818e60426 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -5693,11 +5693,6 @@ bool rpl_master_erroneous_autoinc(THD *thd)
return FALSE;
}
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class I_List_iterator<i_string>;
-template class I_List_iterator<i_string_pair>;
-#endif
-
/**
@} (end of group Replication)
*/
diff --git a/sql/sp.cc b/sql/sp.cc
index db180bde4b5..f6f5d640bc0 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1350,7 +1350,6 @@ sp_update_routine(THD *thd, stored_procedure_type type, sp_name *name,
}
store_record(table,record[1]);
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time();
if (chistics->suid != SP_IS_DEFAULT_SUID)
table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]->
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 2ab5f96d4cb..b725f6d7fcc 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2425,7 +2425,6 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
{
LEX_STRING cmt = { 0, 0 };
uint unused1= 0;
- int unused2= 0;
if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
@@ -2442,8 +2441,7 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
sp_prepare_create_field(thd, field_def);
- if (prepare_create_field(field_def, &unused1, &unused2, &unused2,
- HA_CAN_GEOMETRY))
+ if (prepare_create_field(field_def, &unused1, HA_CAN_GEOMETRY))
{
return TRUE;
}
@@ -3112,8 +3110,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
(the order of query cache and subst_spvars calls is irrelevant because
queries with SP vars can't be cached)
*/
- if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0))
- general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+ general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
if (query_cache_send_result_to_client(thd, thd->query(),
thd->query_length()) <= 0)
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7e8a6a93d57..723d825de17 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1634,14 +1634,20 @@ ulong acl_get(const char *host, const char *ip,
acl_entry *entry;
DBUG_ENTER("acl_get");
- mysql_mutex_lock(&acl_cache->lock);
- end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db);
+ tmp_db= strmov(strmov(key, ip ? ip : "") + 1, user) + 1;
+ end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db);
+
+ if (end >= key + sizeof(key)) // db name was truncated
+ DBUG_RETURN(0); // no privileges for an invalid db name
+
if (lower_case_table_names)
{
my_casedn_str(files_charset_info, tmp_db);
db=tmp_db;
}
key_length= (size_t) (end-key);
+
+ mysql_mutex_lock(&acl_cache->lock);
if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
key_length)))
{
@@ -4888,11 +4894,17 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
bool check_grant_db(THD *thd,const char *db)
{
Security_context *sctx= thd->security_ctx;
- char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2];
+ char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2], *end;
uint len;
bool error= TRUE;
- len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
+ end= strmov(helping, sctx->priv_user) + 1;
+ end= strnmov(end, db, helping + sizeof(helping) - end);
+
+ if (end >= helping + sizeof(helping)) // db name was truncated
+ return 1; // no privileges for an invalid db name
+
+ len= (uint) (end - helping) + 1;
mysql_rwlock_rdlock(&LOCK_grant);
@@ -7013,17 +7025,6 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
}
-/*****************************************************************************
- Instantiate used templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List_iterator<LEX_COLUMN>;
-template class List_iterator<LEX_USER>;
-template class List<LEX_COLUMN>;
-template class List<LEX_USER>;
-#endif
-
/**
Validate if a user can proxy as another user
diff --git a/sql/sql_audit.h b/sql/sql_audit.h
index 51c695d091d..b2ce31f1d26 100644
--- a/sql/sql_audit.h
+++ b/sql/sql_audit.h
@@ -37,8 +37,16 @@ extern void mysql_audit_acquire_plugins(THD *thd, uint event_class);
#ifndef EMBEDDED_LIBRARY
extern void mysql_audit_notify(THD *thd, uint event_class,
uint event_subtype, ...);
+
+static inline bool mysql_audit_general_enabled()
+{
+ return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK;
+}
+
#else
-#define mysql_audit_notify(...)
+static inline void mysql_audit_notify(THD *thd, uint event_class,
+ uint event_subtype, ...) { }
+#define mysql_audit_general_enabled() 0
#endif
extern void mysql_audit_release(THD *thd);
@@ -72,8 +80,7 @@ void mysql_audit_general_log(THD *thd, time_t time,
const char *cmd, uint cmdlen,
const char *query, uint querylen)
{
-#ifndef EMBEDDED_LIBRARY
- if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK)
+ if (mysql_audit_general_enabled())
{
CHARSET_INFO *clientcs= thd ? thd->variables.character_set_client
: global_system_variables.character_set_client;
@@ -82,7 +89,6 @@ void mysql_audit_general_log(THD *thd, time_t time,
0, time, user, userlen, cmd, cmdlen,
query, querylen, clientcs, 0);
}
-#endif
}
/**
@@ -101,8 +107,7 @@ static inline
void mysql_audit_general(THD *thd, uint event_subtype,
int error_code, const char *msg)
{
-#ifndef EMBEDDED_LIBRARY
- if (mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK)
+ if (mysql_audit_general_enabled())
{
time_t time= my_time(0);
uint msglen= msg ? strlen(msg) : 0;
@@ -130,7 +135,6 @@ void mysql_audit_general(THD *thd, uint event_subtype,
error_code, time, user, userlen, msg, msglen,
query.str(), query.length(), query.charset(), rows);
}
-#endif
}
#define MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd) mysql_audit_notify(\
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index db926061406..834e5ac0046 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -8852,34 +8852,33 @@ err_no_arena:
******************************************************************************/
-/*
- Fill fields with given items.
+/**
+ Fill the fields of a table with the values of an Item list
- SYNOPSIS
- fill_record()
- thd thread handler
- fields Item_fields list to be filled
- values values to fill with
- ignore_errors TRUE if we should ignore errors
+ @param thd thread handler
+ @param table_arg the table that is being modified
+ @param fields Item_fields list to be filled
+ @param values values to fill with
+ @param ignore_errors TRUE if we should ignore errors
- NOTE
+ @details
fill_record() may set table->auto_increment_field_not_null and a
caller should make sure that it is reset after their last call to this
function.
- RETURN
- FALSE OK
- TRUE error occured
+ @return Status
+ @retval true An error occured.
+ @retval false OK.
*/
static bool
-fill_record(THD * thd, List<Item> &fields, List<Item> &values,
+fill_record(THD * thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
bool ignore_errors)
{
List_iterator_fast<Item> f(fields),v(values);
Item *value, *fld;
Item_field *field;
- TABLE *table= 0, *vcol_table= 0;
+ TABLE *vcol_table= 0;
bool save_abort_on_warning= thd->abort_on_warning;
bool save_no_errors= thd->no_errors;
DBUG_ENTER("fill_record");
@@ -8901,12 +8900,13 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
goto err;
}
- table= field->field->table;
- table->auto_increment_field_not_null= FALSE;
+ DBUG_ASSERT(field->field->table == table_arg);
+ table_arg->auto_increment_field_not_null= FALSE;
f.rewind();
}
else if (thd->lex->unit.insert_table_with_stored_vcol)
vcol_table= thd->lex->unit.insert_table_with_stored_vcol;
+
while ((fld= f++))
{
if (!(field= fld->filed_for_view_update()))
@@ -8916,7 +8916,7 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
}
value=v++;
Field *rfield= field->field;
- table= rfield->table;
+ TABLE* table= rfield->table;
if (rfield == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
if (rfield->vcol_info &&
@@ -8934,13 +8934,16 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
goto err;
}
+ rfield->set_explicit_default(value);
DBUG_ASSERT(vcol_table == 0 || vcol_table == table);
vcol_table= table;
}
/* Update virtual fields*/
thd->abort_on_warning= FALSE;
if (vcol_table && vcol_table->vfield &&
- update_virtual_fields(thd, vcol_table, TRUE))
+ update_virtual_fields(thd, vcol_table,
+ vcol_table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
@@ -8948,8 +8951,8 @@ fill_record(THD * thd, List<Item> &fields, List<Item> &values,
err:
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
- if (table)
- table->auto_increment_field_not_null= FALSE;
+ if (fields.elements)
+ table_arg->auto_increment_field_not_null= FALSE;
DBUG_RETURN(TRUE);
}
@@ -8958,42 +8961,39 @@ err:
Fill fields in list with values from the list of items and invoke
before triggers.
- SYNOPSIS
- fill_record_n_invoke_before_triggers()
- thd thread context
- fields Item_fields list to be filled
- values values to fill with
- ignore_errors TRUE if we should ignore errors
- triggers object holding list of triggers to be invoked
- event event type for triggers to be invoked
+ @param thd thread context
+ @param table the table that is being modified
+ @param fields Item_fields list to be filled
+ @param values values to fill with
+ @param ignore_errors TRUE if we should ignore errors
+ @param event event type for triggers to be invoked
- NOTE
+ @detail
This function assumes that fields which values will be set and triggers
to be invoked belong to the same table, and that TABLE::record[0] and
record[1] buffers correspond to new and old versions of row respectively.
- RETURN
- FALSE OK
- TRUE error occured
+ @return Status
+ @retval true An error occured.
+ @retval false OK.
*/
bool
-fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
+fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List<Item> &fields,
List<Item> &values, bool ignore_errors,
- Table_triggers_list *triggers,
enum trg_event_type event)
{
bool result;
- result= (fill_record(thd, fields, values, ignore_errors) ||
+ Table_triggers_list *triggers= table->triggers;
+ result= (fill_record(thd, table, fields, values, ignore_errors) ||
(triggers && triggers->process_triggers(thd, event,
TRG_ACTION_BEFORE, TRUE)));
/*
Re-calculate virtual fields to cater for cases when base columns are
updated by the triggers.
*/
- if (!result && triggers)
+ if (!result && triggers && table)
{
- TABLE *table= 0;
List_iterator_fast<Item> f(fields);
Item *fld;
Item_field *item_field;
@@ -9001,45 +9001,46 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
{
fld= (Item_field*)f++;
item_field= fld->filed_for_view_update();
- if (item_field && item_field->field &&
- (table= item_field->field->table) &&
- table->vfield)
- result= update_virtual_fields(thd, table, TRUE);
+ if (item_field && item_field->field && table && table->vfield)
+ {
+ DBUG_ASSERT(table == item_field->field->table);
+ result= update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_WRITE);
+ }
}
}
return result;
}
-/*
- Fill field buffer with values from Field list
+/**
+ Fill the field buffer of a table with the values of an Item list
- SYNOPSIS
- fill_record()
- thd thread handler
- ptr pointer on pointer to record
- values list of fields
- ignore_errors TRUE if we should ignore errors
- use_value forces usage of value of the items instead of result
+ @param thd thread handler
+ @param table_arg the table that is being modified
+ @param ptr pointer on pointer to record of fields
+ @param values values to fill with
+ @param ignore_errors TRUE if we should ignore errors
+ @param use_value forces usage of value of the items instead of result
- NOTE
+ @details
fill_record() may set table->auto_increment_field_not_null and a
caller should make sure that it is reset after their last call to this
function.
- RETURN
- FALSE OK
- TRUE error occured
+ @return Status
+ @retval true An error occured.
+ @retval false OK.
*/
bool
-fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
- bool use_value)
+fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
+ bool ignore_errors, bool use_value)
{
List_iterator_fast<Item> v(values);
List<TABLE> tbl_list;
Item *value;
- TABLE *table= 0;
Field *field;
bool abort_on_warning_saved= thd->abort_on_warning;
DBUG_ENTER("fill_record");
@@ -9054,7 +9055,7 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
On INSERT or UPDATE fields are checked to be from the same table,
thus we safely can take table from the first field.
*/
- table= (*ptr)->table;
+ DBUG_ASSERT((*ptr)->table == table);
/*
Reset the table->auto_increment_field_not_null as it is valid for
@@ -9085,10 +9086,14 @@ fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
else
if (value->save_in_field(field, 0) < 0)
goto err;
+ field->set_explicit_default(value);
}
/* Update virtual fields*/
thd->abort_on_warning= FALSE;
- if (table->vfield && update_virtual_fields(thd, table, TRUE))
+ if (table->vfield &&
+ update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= abort_on_warning_saved;
DBUG_RETURN(thd->is_error());
@@ -9101,36 +9106,34 @@ err:
/*
- Fill fields in array with values from the list of items and invoke
+ Fill fields in an array with values from the list of items and invoke
before triggers.
- SYNOPSIS
- fill_record_n_invoke_before_triggers()
- thd thread context
- ptr NULL-ended array of fields to be filled
- values values to fill with
- ignore_errors TRUE if we should ignore errors
- triggers object holding list of triggers to be invoked
- event event type for triggers to be invoked
+ @param thd thread context
+ @param table the table that is being modified
+ @param ptr the fields to be filled
+ @param values values to fill with
+ @param ignore_errors TRUE if we should ignore errors
+ @param event event type for triggers to be invoked
- NOTE
+ @detail
This function assumes that fields which values will be set and triggers
to be invoked belong to the same table, and that TABLE::record[0] and
record[1] buffers correspond to new and old versions of row respectively.
- RETURN
- FALSE OK
- TRUE error occured
+ @return Status
+ @retval true An error occured.
+ @retval false OK.
*/
bool
-fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
+fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
List<Item> &values, bool ignore_errors,
- Table_triggers_list *triggers,
enum trg_event_type event)
{
bool result;
- result= (fill_record(thd, ptr, values, ignore_errors, FALSE) ||
+ Table_triggers_list *triggers= table->triggers;
+ result= (fill_record(thd, table, ptr, values, ignore_errors, FALSE) ||
(triggers && triggers->process_triggers(thd, event,
TRG_ACTION_BEFORE, TRUE)));
/*
@@ -9139,9 +9142,11 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
*/
if (!result && triggers && *ptr)
{
- TABLE *table= (*ptr)->table;
+ DBUG_ASSERT(table == (*ptr)->table);
if (table->vfield)
- result= update_virtual_fields(thd, table, TRUE);
+ result= update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_WRITE);
}
return result;
@@ -9779,11 +9784,6 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
/* Make sure all columns get assigned to a default value */
table->use_all_columns();
table->no_replicate= 1;
- /*
- Don't set automatic timestamps as we may want to use time of logging,
- not from query start
- */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
}
else
thd->restore_backup_open_tables_state(backup);
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 3deb97c9730..af63aefa7f9 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -170,15 +170,15 @@ TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl);
TABLE *find_temporary_table(THD *thd, const char *table_key,
uint table_key_length);
void close_thread_tables(THD *thd);
-bool fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
+bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
+ List<Item> &fields,
List<Item> &values,
bool ignore_errors,
- Table_triggers_list *triggers,
enum trg_event_type event);
-bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
+bool fill_record_n_invoke_before_triggers(THD *thd, TABLE *table,
+ Field **field,
List<Item> &values,
bool ignore_errors,
- Table_triggers_list *triggers,
enum trg_event_type event);
bool insert_fields(THD *thd, Name_resolution_context *context,
const char *db_name, const char *table_name,
@@ -191,7 +191,7 @@ bool setup_fields(THD *thd, Item** ref_pointer_array,
List<Item> &item, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func);
void unfix_fields(List<Item> &items);
-bool fill_record(THD *thd, Field **field, List<Item> &values,
+bool fill_record(THD *thd, TABLE *table, Field **field, List<Item> &values,
bool ignore_errors, bool use_value);
Field *
@@ -303,7 +303,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
bool no_error);
void mark_tmp_table_for_reuse(TABLE *table);
bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
-int update_virtual_fields(THD *thd, TABLE *table, bool ignore_stored= FALSE);
+int update_virtual_fields(THD *thd, TABLE *table,
+ enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
int dynamic_column_error_message(enum_dyncol_func_result rc);
extern TABLE *unused_tables;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index fc5653750f3..cbb798d96a4 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -73,23 +73,6 @@ char empty_c_string[1]= {0}; /* used for not defined db */
const char * const THD::DEFAULT_WHERE= "field list";
-
-/*****************************************************************************
-** Instansiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-/* Used templates */
-template class List<Key>;
-template class List_iterator<Key>;
-template class List<Key_part_spec>;
-template class List_iterator<Key_part_spec>;
-template class List<Alter_drop>;
-template class List_iterator<Alter_drop>;
-template class List<Alter_column>;
-template class List_iterator<Alter_column>;
-#endif
-
/****************************************************************************
** User variables
****************************************************************************/
@@ -5183,27 +5166,6 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
DBUG_RETURN(pending); /* This is the current pending event */
}
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-/*
- Instantiate the versions we need, we have -fno-implicit-template as
- compiling option.
-*/
-template Rows_log_event*
-THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- size_t, size_t, bool,
- Write_rows_log_event*);
-
-template Rows_log_event*
-THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- size_t colcnt, size_t, bool,
- Delete_rows_log_event *);
-
-template Rows_log_event*
-THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
- size_t colcnt, size_t, bool,
- Update_rows_log_event *);
-#endif
-
/* Declare in unnamed namespace. */
CPP_UNNAMED_NS_START
/**
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 3dbccf9b41e..8df3a2eee36 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1272,7 +1272,8 @@ enum enum_thread_type
SYSTEM_THREAD_SLAVE_SQL= 4,
SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
SYSTEM_THREAD_EVENT_SCHEDULER= 16,
- SYSTEM_THREAD_EVENT_WORKER= 32
+ SYSTEM_THREAD_EVENT_WORKER= 32,
+ SYSTEM_THREAD_BINLOG_BACKGROUND= 64
};
inline char const *
@@ -4365,6 +4366,16 @@ public:
*/
#define CF_FORCE_ORIGINAL_BINLOG_FORMAT (1U << 16)
+/**
+ Statement that inserts new rows (INSERT, REPLACE, LOAD, ALTER TABLE)
+*/
+#define CF_INSERTS_DATA (1U << 11)
+
+/**
+ Statement that updates existing rows (UPDATE, multi-update)
+*/
+#define CF_UPDATES_DATA (1U << 12)
+
/* Bits in server_command_flags */
/**
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 0f07f01c6fd..09ddedecc75 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -330,7 +330,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
! thd->is_error())
{
if (table->vfield)
- update_virtual_fields(thd, table);
+ update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
// thd->is_error() is tested to disallow delete row on error
if (!select || select->skip_record(thd) > 0)
diff --git a/sql/sql_expression_cache.cc b/sql/sql_expression_cache.cc
index e65ec3c22b0..1193c7c27f4 100644
--- a/sql/sql_expression_cache.cc
+++ b/sql/sql_expression_cache.cc
@@ -257,7 +257,7 @@ my_bool Expression_cache_tmptable::put_value(Item *value)
}
*(items.head_ref())= value;
- fill_record(table_thd, cache_table->field, items, TRUE, TRUE);
+ fill_record(table_thd, cache_table, cache_table->field, items, TRUE, TRUE);
if (table_thd->is_error())
goto err;;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 25c696bc476..67f3955ea61 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -191,11 +191,6 @@ error:
different table maps, like on select ... insert
map Store here table map for used fields
- NOTE
- Clears TIMESTAMP_AUTO_SET_ON_INSERT from table->timestamp_field_type
- or leaves it as is, depending on if timestamp should be updated or
- not.
-
RETURN
0 OK
-1 Error
@@ -234,8 +229,6 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (check_grant_all_columns(thd, INSERT_ACL, &field_it))
return -1;
#endif
- clear_timestamp_auto_bits(table->timestamp_field_type,
- TIMESTAMP_AUTO_SET_ON_INSERT);
/*
No fields are provided so all fields must be provided in the values.
Thus we set all bits in the write set.
@@ -295,18 +288,8 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), thd->dup_field->field_name);
return -1;
}
- if (table->timestamp_field) // Don't automaticly set timestamp if used
- {
- if (bitmap_is_set(table->write_set,
- table->timestamp_field->field_index))
- clear_timestamp_auto_bits(table->timestamp_field_type,
- TIMESTAMP_AUTO_SET_ON_INSERT);
- else
- {
- bitmap_set_bit(table->write_set,
- table->timestamp_field->field_index);
- }
- }
+ if (table->default_field)
+ table->mark_default_fields_for_write();
}
/* Mark virtual columns used in the insert statement */
if (table->vfield)
@@ -339,9 +322,6 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
update_fields The update fields.
NOTE
- If the update fields include the timestamp field,
- remove TIMESTAMP_AUTO_SET_ON_UPDATE from table->timestamp_field_type.
-
If the update fields include an autoinc field, set the
table->next_number_field_updated flag.
@@ -355,21 +335,9 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List<Item> &update_values, table_map *map)
{
TABLE *table= insert_table_list->table;
- my_bool timestamp_mark;
my_bool autoinc_mark;
- LINT_INIT(timestamp_mark);
LINT_INIT(autoinc_mark);
- if (table->timestamp_field)
- {
- /*
- Unmark the timestamp field so that we can check if this is modified
- by update_fields
- */
- timestamp_mark= bitmap_test_and_clear(table->write_set,
- table->timestamp_field->field_index);
- }
-
table->next_number_field_updated= FALSE;
if (table->found_next_number_field)
@@ -393,17 +361,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
insert_table_list, map, false))
return -1;
- if (table->timestamp_field)
- {
- /* Don't set timestamp column if this is modified. */
- if (bitmap_is_set(table->write_set,
- table->timestamp_field->field_index))
- clear_timestamp_auto_bits(table->timestamp_field_type,
- TIMESTAMP_AUTO_SET_ON_UPDATE);
- if (timestamp_mark)
- bitmap_set_bit(table->write_set,
- table->timestamp_field->field_index);
- }
+ if (table->default_field)
+ table->mark_default_fields_for_write();
if (table->found_next_number_field)
{
@@ -716,7 +675,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
int error, res;
bool transactional_table, joins_freed= FALSE;
bool changed;
- bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED);
+ const bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED);
bool using_bulk_insert= 0;
uint value_count;
ulong counter = 1;
@@ -916,8 +875,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (fields.elements || !value_count)
{
restore_record(table,s->default_values); // Get empty record
- if (fill_record_n_invoke_before_triggers(thd, fields, *values, 0,
- table->triggers,
+ if (fill_record_n_invoke_before_triggers(thd, table, fields, *values, 0,
TRG_EVENT_INSERT))
{
if (values_list.elements != 1 && ! thd->is_error())
@@ -961,8 +919,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
share->default_values[share->null_bytes - 1];
}
}
- if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
- table->triggers,
+ if (fill_record_n_invoke_before_triggers(thd, table, table->field, *values, 0,
TRG_EVENT_INSERT))
{
if (values_list.elements != 1 && ! thd->is_error())
@@ -974,6 +931,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
break;
}
}
+ if (table->default_field && table->update_default_fields())
+ {
+ error= 1;
+ break;
+ }
if ((res= table_list->view_check_option(thd,
(values_list.elements == 1 ?
@@ -990,7 +952,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (lock_type == TL_WRITE_DELAYED)
{
LEX_STRING const st_query = { query, thd->query_length() };
+ DEBUG_SYNC(thd, "before_write_delayed");
error=write_delayed(thd, table, duplic, st_query, ignore, log_on);
+ DEBUG_SYNC(thd, "after_write_delayed");
query=0;
}
else
@@ -1680,9 +1644,10 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
}
key_copy((uchar*) key,table->record[0],table->key_info+key_nr,0);
+ key_part_map keypart_map= (1 << table->key_info[key_nr].key_parts) - 1;
if ((error= (table->file->ha_index_read_idx_map(table->record[1],
key_nr, (uchar*) key,
- HA_WHOLE_KEY,
+ keypart_map,
HA_READ_KEY_EXACT))))
goto err;
}
@@ -1699,13 +1664,32 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
restore_record(table,record[1]);
DBUG_ASSERT(info->update_fields->elements ==
info->update_values->elements);
- if (fill_record_n_invoke_before_triggers(thd, *info->update_fields,
+ if (fill_record_n_invoke_before_triggers(thd, table, *info->update_fields,
*info->update_values,
info->ignore,
- table->triggers,
TRG_EVENT_UPDATE))
goto before_trg_err;
+ bool different_records= (!records_are_comparable(table) ||
+ compare_record(table));
+ /*
+ Default fields must be updated before checking view updateability.
+ This branch of INSERT is executed only when a UNIQUE key was violated
+ with the ON DUPLICATE KEY UPDATE option. In this case the INSERT
+ operation is transformed to an UPDATE, and the default fields must
+ be updated as if this is an UPDATE.
+ */
+ if (different_records && table->default_field)
+ {
+ bool res;
+ enum_sql_command cmd= thd->lex->sql_command;
+ thd->lex->sql_command= SQLCOM_UPDATE;
+ res= table->update_default_fields();
+ thd->lex->sql_command= cmd;
+ if (res)
+ goto err;
+ }
+
/* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
if (info->view &&
(res= info->view->view_check_option(current_thd, info->ignore)) ==
@@ -1716,7 +1700,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
table->file->restore_auto_increment(prev_insert_id);
info->touched++;
- if (!records_are_comparable(table) || compare_record(table))
+ if (different_records)
{
if ((error=table->file->ha_update_row(table->record[1],
table->record[0])) &&
@@ -1787,8 +1771,6 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
*/
if (last_uniq_key(table,key_nr) &&
!table->file->referenced_by_foreign_key() &&
- (table->timestamp_field_type == TIMESTAMP_NO_AUTO_SET ||
- table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH) &&
(!table->triggers || !table->triggers->has_delete_triggers()))
{
if ((error=table->file->ha_update_row(table->record[1],
@@ -1951,7 +1933,6 @@ public:
ulonglong forced_insert_id;
ulong auto_increment_increment;
ulong auto_increment_offset;
- timestamp_auto_set_type timestamp_field_type;
LEX_STRING query;
Time_zone *time_zone;
@@ -2324,7 +2305,7 @@ end_create:
TABLE *Delayed_insert::get_local_table(THD* client_thd)
{
my_ptrdiff_t adjust_ptrs;
- Field **field,**org_field, *found_next_number_field;
+ Field **field,**org_field, *found_next_number_field, **dfield_ptr= 0;
TABLE *copy;
TABLE_SHARE *share;
uchar *bitmap;
@@ -2393,6 +2374,14 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
bitmap= (uchar*) (field + share->fields + 1);
copy->record[0]= (bitmap + share->column_bitmap_size*3);
memcpy((char*) copy->record[0], (char*) table->record[0], share->reclength);
+ if (share->default_fields)
+ {
+ copy->default_field= (Field**) client_thd->alloc((share->default_fields+1)*
+ sizeof(Field**));
+ if (!copy->default_field)
+ goto error;
+ dfield_ptr= copy->default_field;
+ }
/*
Make a copy of all fields.
The copied fields need to point into the copied record. This is done
@@ -2410,18 +2399,19 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
(*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0]
if (*org_field == found_next_number_field)
(*field)->table->found_next_number_field= *field;
+ if (share->default_fields &&
+ ((*org_field)->has_insert_default_function() ||
+ (*org_field)->has_update_default_function()))
+ {
+ /* Put the newly copied field into the set of default fields. */
+ *dfield_ptr= *field;
+ (*dfield_ptr)->unireg_check= (*org_field)->unireg_check;
+ dfield_ptr++;
+ }
}
*field=0;
-
- /* Adjust timestamp */
- if (table->timestamp_field)
- {
- /* Restore offset as this may have been reset in handle_inserts */
- copy->timestamp_field=
- (Field_timestamp*) copy->field[share->timestamp_field_offset];
- copy->timestamp_field->unireg_check= table->timestamp_field->unireg_check;
- copy->timestamp_field_type= copy->timestamp_field->get_auto_set_type();
- }
+ if (share->default_fields)
+ *dfield_ptr= NULL;
/* Adjust in_use for pointing to client thread */
copy->in_use= client_thd;
@@ -2511,7 +2501,6 @@ int write_delayed(THD *thd, TABLE *table, enum_duplicates duplic,
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt;
row->first_successful_insert_id_in_prev_stmt=
thd->first_successful_insert_id_in_prev_stmt;
- row->timestamp_field_type= table->timestamp_field_type;
/* Add session variable timezone
Time_zone object will not be freed even the thread is ended.
@@ -3053,7 +3042,6 @@ bool Delayed_insert::handle_inserts(void)
row->first_successful_insert_id_in_prev_stmt;
thd.stmt_depends_on_first_successful_insert_id_in_prev_stmt=
row->stmt_depends_on_first_successful_insert_id_in_prev_stmt;
- table->timestamp_field_type= row->timestamp_field_type;
table->auto_increment_field_not_null= row->auto_increment_field_not_null;
/* Copy the session variables. */
@@ -3523,6 +3511,8 @@ int select_insert::send_data(List<Item> &values)
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
store_values(values);
+ if (table->default_field && table->update_default_fields())
+ DBUG_RETURN(1);
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
if (thd->is_error())
{
@@ -3582,11 +3572,11 @@ int select_insert::send_data(List<Item> &values)
void select_insert::store_values(List<Item> &values)
{
if (fields->elements)
- fill_record_n_invoke_before_triggers(thd, *fields, values, 1,
- table->triggers, TRG_EVENT_INSERT);
+ fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1,
+ TRG_EVENT_INSERT);
else
- fill_record_n_invoke_before_triggers(thd, table->field, values, 1,
- table->triggers, TRG_EVENT_INSERT);
+ fill_record_n_invoke_before_triggers(thd, table, table->field, values, 1,
+ TRG_EVENT_INSERT);
}
void select_insert::send_error(uint errcode,const char *err)
@@ -3804,7 +3794,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_ENTER("create_table_from_items");
tmp_table.alias= 0;
- tmp_table.timestamp_field= 0;
tmp_table.s= &share;
init_tmp_table_share(thd, &share, "", 0, "", "");
@@ -3813,6 +3802,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
tmp_table.null_row= 0;
tmp_table.maybe_null= 0;
+ promote_first_timestamp_column(&alter_info->create_list);
+
while ((item=it++))
{
Create_field *cr_field;
@@ -4052,8 +4043,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
for (Field **f= field ; *f ; f++)
bitmap_set_bit(table->write_set, (*f)->field_index);
- /* Don't set timestamp if used */
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
table->next_number_field=table->found_next_number_field;
restore_record(table,s->default_values); // Get empty record
@@ -4126,8 +4115,8 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
void select_create::store_values(List<Item> &values)
{
- fill_record_n_invoke_before_triggers(thd, field, values, 1,
- table->triggers, TRG_EVENT_INSERT);
+ fill_record_n_invoke_before_triggers(thd, table, field, values, 1,
+ TRG_EVENT_INSERT);
}
@@ -4236,16 +4225,3 @@ void select_create::abort_result_set()
DBUG_VOID_RETURN;
}
-
-/*****************************************************************************
- Instansiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List_iterator_fast<List_item>;
-#ifndef EMBEDDED_LIBRARY
-template class I_List<Delayed_insert>;
-template class I_List_iterator<Delayed_insert>;
-template class I_List<delayed_row>;
-#endif /* EMBEDDED_LIBRARY */
-#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 975f0c77349..2c9a55208fc 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4445,6 +4445,3 @@ void binlog_unsafe_map_init()
}
#endif
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class Mem_root_array<ORDER*, true>;
-#endif
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index daa9298d52d..38853eb8b6d 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -273,7 +273,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
for (field=table->field; *field ; field++)
fields_vars.push_back(new Item_field(*field));
bitmap_set_all(table->write_set);
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/*
Let us also prepare SET clause, altough it is probably empty
in this case.
@@ -289,21 +288,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
check_that_all_fields_are_given_values(thd, table, table_list))
DBUG_RETURN(TRUE);
- /*
- Check whenever TIMESTAMP field with auto-set feature specified
- explicitly.
- */
- if (table->timestamp_field)
- {
- if (bitmap_is_set(table->write_set,
- table->timestamp_field->field_index))
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- else
- {
- bitmap_set_bit(table->write_set,
- table->timestamp_field->field_index);
- }
- }
+ /* Add all fields with default functions to table->write_set. */
+ if (table->default_field)
+ table->mark_default_fields_for_write();
/* Fix the expressions in SET clause */
if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
DBUG_RETURN(TRUE);
@@ -846,8 +833,12 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_WARN_TOO_FEW_RECORDS,
ER(ER_WARN_TOO_FEW_RECORDS),
thd->warning_info->current_row_for_warning());
+ /*
+ Timestamp fields that are NOT NULL are autoupdated if there is no
+ corresponding value in the data file.
+ */
if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
- ((Field_timestamp*) field)->set_time();
+ field->set_time();
}
else
{
@@ -862,6 +853,8 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if ((pos+=length) > read_info.row_end)
pos= read_info.row_end; /* Fills rest with space */
}
+ /* Do not auto-update this field. */
+ field->set_has_explicit_value();
}
if (pos != read_info.row_end)
{
@@ -873,10 +866,10 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
if (thd->killed ||
- fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
+ fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
ignore_check_option_errors,
- table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT) ||
+ (table->default_field && table->update_default_fields()))
DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
@@ -993,12 +986,18 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
field->set_null();
if (!field->maybe_null())
{
+ /*
+ Timestamp fields that are NOT NULL are autoupdated if there is no
+ corresponding value in the data file.
+ */
if (field->type() == MYSQL_TYPE_TIMESTAMP)
- ((Field_timestamp*) field)->set_time();
+ field->set_time();
else if (field != table->next_number_field)
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_NULL_TO_NOTNULL, 1);
}
+ /* Do not auto-update this field. */
+ field->set_has_explicit_value();
}
else if (item->type() == Item::STRING_ITEM)
{
@@ -1022,6 +1021,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
field->store((char*) pos, length, read_info.read_charset);
+ field->set_has_explicit_value();
}
else if (item->type() == Item::STRING_ITEM)
{
@@ -1063,7 +1063,8 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
DBUG_RETURN(1);
}
if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
- ((Field_timestamp*) field)->set_time();
+ field->set_time();
+ field->set_has_explicit_value();
/*
TODO: We probably should not throw warning for each field.
But how about intention to always have the same number
@@ -1090,10 +1091,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
if (thd->killed ||
- fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
+ fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
ignore_check_option_errors,
- table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT) ||
+ (table->default_field && table->update_default_fields()))
DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
@@ -1203,11 +1204,13 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (!field->maybe_null())
{
if (field->type() == FIELD_TYPE_TIMESTAMP)
- ((Field_timestamp *) field)->set_time();
+ field->set_time();
else if (field != table->next_number_field)
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_NULL_TO_NOTNULL, 1);
}
+ /* Do not auto-update this field. */
+ field->set_has_explicit_value();
}
else
((Item_user_var_as_out_param *) item)->set_null_value(cs);
@@ -1222,6 +1225,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE;
field->store((char *) tag->value.ptr(), tag->value.length(), cs);
+ field->set_has_explicit_value();
}
else
((Item_user_var_as_out_param *) item)->set_value(
@@ -1266,10 +1270,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
}
if (thd->killed ||
- fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
+ fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
ignore_check_option_errors,
- table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT) ||
+ (table->default_field && table->update_default_fields()))
DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 36447a1836d..14601f99138 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -270,12 +270,14 @@ void init_update_queries(void)
CF_CAN_GENERATE_ROW_EVENTS;
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
- CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS ;
+ CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS |
+ CF_INSERTS_DATA;
sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND |
CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS;
+ CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS |
+ CF_INSERTS_DATA;
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS;
@@ -294,19 +296,23 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_UPDATES_DATA;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_UPDATES_DATA;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_INSERTS_DATA;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_INSERTS_DATA;
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -318,11 +324,13 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;;
+ CF_CAN_BE_EXPLAINED |
+ CF_INSERTS_DATA;;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
- CF_CAN_BE_EXPLAINED;
+ CF_CAN_BE_EXPLAINED |
+ CF_INSERTS_DATA;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE |
CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE |
@@ -6175,6 +6183,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
{
register Create_field *new_field;
LEX *lex= thd->lex;
+ uint8 datetime_precision= length ? atoi(length) : 0;
DBUG_ENTER("add_field_to_list");
if (check_string_char_length(field_name, "", NAME_CHAR_LEN,
@@ -6211,11 +6220,13 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
no need fix_fields()
We allow only one function as part of default value -
- NOW() as default for TIMESTAMP type.
+ NOW() as default for TIMESTAMP and DATETIME type.
*/
if (default_value->type() == Item::FUNC_ITEM &&
- !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
- type == MYSQL_TYPE_TIMESTAMP))
+ (static_cast<Item_func*>(default_value)->functype() !=
+ Item_func::NOW_FUNC ||
+ (mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_DATETIME) ||
+ default_value->decimals < datetime_precision))
{
my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
DBUG_RETURN(1);
@@ -6237,7 +6248,9 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
}
}
- if (on_update_value && type != MYSQL_TYPE_TIMESTAMP)
+ if (on_update_value &&
+ (mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_DATETIME ||
+ on_update_value->decimals < datetime_precision))
{
my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
DBUG_RETURN(1);
@@ -7097,8 +7110,10 @@ void sql_kill(THD *thd, ulong id, killed_state state)
uint error;
if (!(error= kill_one_thread(thd, id, state)))
{
- if (! thd->killed)
+ if ((!thd->killed))
my_ok(thd);
+ else
+ my_error(killed_errno(thd->killed), MYF(0), id);
}
else
my_error(error, MYF(0), id);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 2bec12e4f66..f042f028450 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6526,9 +6526,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->pack_frm_data= NULL;
lpt->pack_frm_len= 0;
- /* Never update timestamp columns when alter */
- lpt->table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
-
if (table->file->alter_table_flags(alter_info->flags) &
HA_PARTITION_ONE_PHASE)
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 969e6ee4574..24dde140a8a 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2508,14 +2508,24 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
*/
if (sl->prep_where)
{
- sl->where= sl->prep_where->copy_andor_structure(thd);
+ /*
+ We need this rollback because memory allocated in
+ copy_andor_structure() will be freed
+ */
+ thd->change_item_tree((Item**)&sl->where,
+ sl->prep_where->copy_andor_structure(thd));
sl->where->cleanup();
}
else
sl->where= NULL;
if (sl->prep_having)
{
- sl->having= sl->prep_having->copy_andor_structure(thd);
+ /*
+ We need this rollback because memory allocated in
+ copy_andor_structure() will be freed
+ */
+ thd->change_item_tree((Item**)&sl->having,
+ sl->prep_having->copy_andor_structure(thd));
sl->having->cleanup();
}
else
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 8f565cb3d32..90302897a49 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1291,11 +1291,9 @@ JOIN::optimize_inner()
DBUG_RETURN(1); // error == -1
}
if (const_table_map != found_const_table_map &&
- !(select_options & SELECT_DESCRIBE) &&
- (!conds ||
- !(conds->used_tables() & RAND_TABLE_BIT) ||
- select_lex->master_unit() == &thd->lex->unit)) // upper level SELECT
+ !(select_options & SELECT_DESCRIBE))
{
+ // There is at least one empty const table
zero_result_cause= "no matching row in const table";
DBUG_PRINT("error",("Error: %s", zero_result_cause));
error= 0;
@@ -2143,6 +2141,7 @@ JOIN::reinit()
ULL(0));
first_record= 0;
+ cleaned= false;
if (exec_tmp_table1)
{
@@ -5513,7 +5512,8 @@ best_access_path(JOIN *join,
!ref_or_null_part)
{ /* use eq key */
max_key_part= (uint) ~0;
- if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ if ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME ||
+ test(key_flags & HA_EXT_NOSAME))
{
tmp = prev_record_reads(join->positions, idx, found_ref);
records=1.0;
@@ -8111,18 +8111,23 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
*ref_key=0; // end_marker
if (j->type == JT_FT)
DBUG_RETURN(0);
+ ulong key_flags= j->table->actual_key_flags(keyinfo);
if (j->type == JT_CONST)
j->table->const_table= 1;
- else if (((j->table->actual_key_flags(keyinfo) &
- (HA_NOSAME | HA_NULL_PART_KEY))
- != HA_NOSAME) ||
+ else if (((key_flags & (HA_NOSAME | HA_NULL_PART_KEY))!= HA_NOSAME) ||
keyparts != j->table->actual_n_key_parts(keyinfo) ||
null_ref_key)
{
- /* Must read with repeat */
- j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
- j->ref.null_ref_key= null_ref_key;
- j->ref.null_ref_part= null_ref_part;
+ if (test(key_flags & HA_EXT_NOSAME) && keyparts == keyinfo->ext_key_parts &&
+ !null_ref_key)
+ j->type= JT_EQ_REF;
+ else
+ {
+ /* Must read with repeat */
+ j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
+ j->ref.null_ref_key= null_ref_key;
+ j->ref.null_ref_part= null_ref_part;
+ }
}
else if (keyuse_uses_no_tables)
{
@@ -9283,7 +9288,7 @@ void JOIN::drop_unused_derived_keys()
JOIN_TAB *tab;
for (tab= first_linear_tab(this, WITHOUT_CONST_TABLES);
tab;
- tab= next_linear_tab(this, tab, WITHOUT_BUSH_ROOTS))
+ tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
{
TABLE *table=tab->table;
@@ -9571,7 +9576,7 @@ end_sj_materialize(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
if (item->is_null())
DBUG_RETURN(NESTED_LOOP_OK);
}
- fill_record(thd, table->field, sjm->sjm_table_cols, TRUE, FALSE);
+ fill_record(thd, table, table->field, sjm->sjm_table_cols, TRUE, FALSE);
if (thd->is_error())
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if ((error= table->file->ha_write_tmp_row(table->record[0])))
@@ -10774,6 +10779,7 @@ void JOIN::cleanup(bool full)
{
tab->cleanup();
}
+ cleaned= true;
}
else
{
@@ -11247,14 +11253,6 @@ public:
COND_CMP(Item *a,Item_func *b) :and_level(a),cmp_func(b) {}
};
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class I_List<COND_CMP>;
-template class I_List_iterator<COND_CMP>;
-template class List<Item_func_match>;
-template class List_iterator<Item_func_match>;
-#endif
-
-
/**
Find the multiple equality predicate containing a field.
@@ -16622,6 +16620,17 @@ int safe_index_read(JOIN_TAB *tab)
}
+/**
+ Reads content of constant table
+
+ @param tab table
+ @param pos position of table in query plan
+
+ @retval 0 ok, one row was found or one NULL-complemented row was created
+ @retval -1 ok, no row was found and no NULL-complemented row was created
+ @retval 1 error
+*/
+
static int
join_read_const_table(JOIN_TAB *tab, POSITION *pos)
{
@@ -16740,6 +16749,16 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
+/**
+ Read a constant table when there is at most one matching row, using a table
+ scan.
+
+ @param tab Table to read
+
+ @retval 0 Row was found
+ @retval -1 Row was not found
+ @retval 1 Got an error (other than row not found) during read
+*/
static int
join_read_system(JOIN_TAB *tab)
{
@@ -16772,12 +16791,9 @@ join_read_system(JOIN_TAB *tab)
@param tab Table to read
- @retval
- 0 Row was found
- @retval
- -1 Row was not found
- @retval
- 1 Got an error (other than row not found) during read
+ @retval 0 Row was found
+ @retval -1 Row was not found
+ @retval 1 Got an error (other than row not found) during read
*/
static int
@@ -18638,15 +18654,18 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE ||
- quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
+ quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_INTERSECT ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION ||
quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT)
- goto use_filesort;
- ref_key= select->quick->index;
- ref_key_parts= select->quick->used_key_parts;
+ ref_key= MAX_KEY;
+ else
+ {
+ ref_key= select->quick->index;
+ ref_key_parts= select->quick->used_key_parts;
+ }
}
- if (ref_key >= 0)
+ if (ref_key >= 0 && ref_key != MAX_KEY)
{
/*
We come here when there is a REF key.
@@ -19170,49 +19189,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
*(join->pre_sort_join_tab)= *tab;
- /*TODO: here, close the index scan, cancel index-only read. */
-#if 0
- /* MariaDB doesn't need the following: */
- if (select)
- {
- /*
- We need to preserve tablesort's output resultset here, because
- QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by
- SQL_SELECT::cleanup()) may free it assuming it's the result of the quick
- select operation that we no longer need. Note that all the other parts of
- this data structure are cleaned up when
- QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next
- SQL_SELECT::cleanup() call changes sort.io_cache alone.
- */
- IO_CACHE *tablesort_result_cache;
-
- tablesort_result_cache= table->sort.io_cache;
- table->sort.io_cache= NULL;
- // select->cleanup(); // filesort did select
- /*
- If a quick object was created outside of create_sort_index()
- that might be reused, then do not call select->cleanup() since
- it will delete the quick object.
- */
- if (!keep_quick)
- {
- select->cleanup();
- /*
- The select object should now be ready for the next use. If it
- is re-used then there exists a backup copy of this join tab
- which has the pointer to it. The join tab will be restored in
- JOIN::reset(). So here we just delete the pointer to it.
- */
- tab->select= NULL;
- // If we deleted the quick select object we need to clear quick_keys
- table->quick_keys.clear_all();
- table->intersect_keys.clear_all();
- }
- // Restore the output resultset
- table->sort.io_cache= tablesort_result_cache;
- }
-#endif
tab->select=NULL;
tab->set_select_cond(NULL, __LINE__);
tab->type=JT_ALL; // Read with normal read_record
@@ -19236,34 +19213,13 @@ void JOIN::clean_pre_sort_join_tab()
the table already deleted by st_select_lex_unit::cleanup().
We rely on that fake_select_lex didn't have quick select.
*/
-#if 0
- if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick)
- {
- /*
- We need to preserve tablesort's output resultset here, because
- QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by
- SQL_SELECT::cleanup()) may free it assuming it's the result of the quick
- select operation that we no longer need. Note that all the other parts of
- this data structure are cleaned up when
- QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next
- SQL_SELECT::cleanup() call changes sort.io_cache alone.
- */
- IO_CACHE *tablesort_result_cache;
-
- tablesort_result_cache= table->sort.io_cache;
- table->sort.io_cache= NULL;
- pre_sort_join_tab->select->cleanup();
- table->quick_keys.clear_all(); // as far as we cleanup select->quick
- table->intersect_keys.clear_all();
- table->sort.io_cache= tablesort_result_cache;
- }
-#endif
- //table->disable_keyread(); // Restore if we used indexes
if (pre_sort_join_tab->select && pre_sort_join_tab->select->quick)
{
pre_sort_join_tab->select->cleanup();
}
}
+
+
/*****************************************************************************
Remove duplicates from tmp table
This should be recoded to add a unique index to the table and remove
@@ -20744,40 +20700,66 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
res_selected_fields.empty();
res_all_fields.empty();
- uint i, border= all_fields.elements - elements;
- for (i= 0; (item= it++); i++)
+ uint border= all_fields.elements - elements;
+ for (uint i= 0; (item= it++); i++)
{
Field *field;
-
- if ((item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) ||
- (item->type() == Item::FUNC_ITEM &&
- ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC))
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
item_field= item;
- else
+ else if (item->type() == Item::FIELD_ITEM)
+ item_field= item->get_tmp_table_item(thd);
+ else if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*)item)->functype() == Item_func::SUSERVAR_FUNC)
{
- if (item->type() == Item::FIELD_ITEM)
+ field= item->get_tmp_table_field();
+ if (field != NULL)
{
- item_field= item->get_tmp_table_item(thd);
+ /*
+ Replace "@:=<expression>" with "@:=<tmp table column>". Otherwise,
+ we would re-evaluate <expression>, and if expression were
+ a subquery, this would access already-unlocked tables.
+ */
+ Item_func_set_user_var* suv=
+ new Item_func_set_user_var((Item_func_set_user_var*) item);
+ Item_field *new_field= new Item_field(field);
+ if (!suv || !new_field || suv->fix_fields(thd, (Item**)&suv))
+ DBUG_RETURN(true); // Fatal error
+ ((Item *)suv)->name= item->name;
+ /*
+ We are replacing the argument of Item_func_set_user_var after its
+ value has been read. The argument's null_value should be set by
+ now, so we must set it explicitly for the replacement argument
+ since the null_value may be read without any preceeding call to
+ val_*().
+ */
+ new_field->update_null_value();
+ List<Item> list;
+ list.push_back(new_field);
+ suv->set_arguments(list);
+ item_field= suv;
}
- else if ((field= item->get_tmp_table_field()))
+ else
+ item_field= item;
+ }
+ else if ((field= item->get_tmp_table_field()))
+ {
+ if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
+ item_field= ((Item_sum*) item)->result_item(field);
+ else
+ item_field= (Item*) new Item_field(field);
+ if (!item_field)
+ DBUG_RETURN(true); // Fatal error
+
+ if (item->real_item()->type() != Item::FIELD_ITEM)
+ field->orig_table= 0;
+ item_field->name= item->name;
+ if (item->type() == Item::REF_ITEM)
{
- if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
- item_field= ((Item_sum*) item)->result_item(field);
- else
- item_field= (Item*) new Item_field(field);
- if (!item_field)
- DBUG_RETURN(TRUE); // Fatal error
-
- if (item->real_item()->type() != Item::FIELD_ITEM)
- field->orig_table= 0;
- item_field->name= item->name;
- if (item->type() == Item::REF_ITEM)
- {
- Item_field *ifield= (Item_field *) item_field;
- Item_ref *iref= (Item_ref *) item;
- ifield->table_name= iref->table_name;
- ifield->db_name= iref->db_name;
- }
+ Item_field *ifield= (Item_field *) item_field;
+ Item_ref *iref= (Item_ref *) item;
+ ifield->table_name= iref->table_name;
+ ifield->db_name= iref->db_name;
+ }
#ifndef DBUG_OFF
if (!item_field->name)
{
@@ -20789,20 +20771,20 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
item_field->name= sql_strmake(str.ptr(),str.length());
}
#endif
- }
- else
- item_field= item;
}
+ else
+ item_field= item;
+
res_all_fields.push_back(item_field);
ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
item_field;
}
List_iterator_fast<Item> itr(res_all_fields);
- for (i= 0; i < border; i++)
+ for (uint i= 0; i < border; i++)
itr++;
itr.sublist(res_selected_fields, elements);
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
}
@@ -22613,6 +22595,17 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
str->append(STRING_WITH_LEN("select "));
+ if (join && join->cleaned)
+ {
+ /*
+ JOIN already cleaned up so it is dangerous to print items
+ because temporary tables they pointed on could be freed.
+ */
+ str->append('#');
+ str->append(select_number);
+ return;
+ }
+
/* First add options */
if (options & SELECT_STRAIGHT_JOIN)
str->append(STRING_WITH_LEN("straight_join "));
@@ -23080,6 +23073,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
ha_rows table_records= table->file->stats.records;
bool group= join && join->group && order == join->group_list;
ha_rows ref_key_quick_rows= HA_POS_ERROR;
+ const bool has_limit= (select_limit_arg != HA_POS_ERROR);
/*
If not used with LIMIT, only use keys if the whole query can be
@@ -23104,7 +23098,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
else
keys= usable_keys;
- if (ref_key >= 0 && table->covering_keys.is_set(ref_key))
+ if (ref_key >= 0 && ref_key != MAX_KEY &&
+ table->covering_keys.is_set(ref_key))
ref_key_quick_rows= table->quick_rows[ref_key];
if (join)
@@ -23211,7 +23206,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
be included into the result set.
*/
if (select_limit > table_records/rec_per_key)
- select_limit= table_records;
+ select_limit= table_records;
else
select_limit= (ha_rows) (select_limit*rec_per_key);
} /* group */
@@ -23293,7 +23288,7 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
*new_key= best_key;
*new_key_direction= best_key_direction;
- *new_select_limit= best_select_limit;
+ *new_select_limit= has_limit ? best_select_limit : table_records;
if (new_used_key_parts != NULL)
*new_used_key_parts= best_key_parts;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 8420a223fb6..54aca3c4829 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -896,6 +896,14 @@ protected:
public:
JOIN_TAB *join_tab, **best_ref;
+ /*
+ Saved join_tab for pre_sorting. create_sort_index() will save here..
+ */
+ JOIN_TAB *pre_sort_join_tab;
+ uint pre_sort_index;
+ Item *pre_sort_idx_pushed_cond;
+ void clean_pre_sort_join_tab();
+
/*
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
either:
@@ -908,15 +916,6 @@ public:
JOIN_TAB *table_access_tabs;
uint top_table_access_tabs_count;
- /*
- Saved join_tab for pre_sorting. create_sort_index() will save here..
- */
- JOIN_TAB *pre_sort_join_tab;
- uint pre_sort_index;
- Item *pre_sort_idx_pushed_cond;
- void clean_pre_sort_join_tab();
-
-
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
@@ -1140,6 +1139,8 @@ public:
bool skip_sort_order;
bool need_tmp, hidden_group_fields;
+ /* TRUE if there was full cleunap of the JOIN */
+ bool cleaned;
DYNAMIC_ARRAY keyuse;
Item::cond_result cond_value, having_value;
List<Item> all_fields; ///< to store all fields that used in query
@@ -1274,6 +1275,7 @@ public:
optimized= 0;
have_query_plan= QEP_NOT_PRESENT_YET;
initialized= 0;
+ cleaned= 0;
cond_equal= 0;
having_equal= 0;
exec_const_cond= 0;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 73d441a2d9d..4d251aa1c81 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1386,8 +1386,35 @@ static void append_directory(THD *thd, String *packet, const char *dir_type,
#define LIST_PROCESS_HOST_LEN 64
-static bool get_field_default_value(THD *thd, Field *timestamp_field,
- Field *field, String *def_value,
+
+/**
+ Print "ON UPDATE" clause of a field into a string.
+
+ @param timestamp_field Pointer to timestamp field of a table.
+ @param field The field to generate ON UPDATE clause for.
+ @bool lcase Whether to print in lower case.
+ @return false on success, true on error.
+*/
+static bool print_on_update_clause(Field *field, String *val, bool lcase)
+{
+ DBUG_ASSERT(val->charset()->mbminlen == 1);
+ val->length(0);
+ if (field->has_update_default_function())
+ {
+ if (lcase)
+ val->append(STRING_WITH_LEN("on update "));
+ else
+ val->append(STRING_WITH_LEN("ON UPDATE "));
+ val->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ if (field->decimals() > 0)
+ val->append_parenthesized(field->decimals());
+ return true;
+ }
+ return false;
+}
+
+
+static bool get_field_default_value(THD *thd, Field *field, String *def_value,
bool quoted)
{
bool has_default;
@@ -1398,8 +1425,7 @@ static bool get_field_default_value(THD *thd, Field *timestamp_field,
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
*/
- has_now_default= (timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_UN_FIELD);
+ has_now_default= field->has_insert_default_function();
has_default= (field_type != FIELD_TYPE_BLOB &&
!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
@@ -1411,7 +1437,11 @@ static bool get_field_default_value(THD *thd, Field *timestamp_field,
if (has_default)
{
if (has_now_default)
+ {
def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ if (field->decimals() > 0)
+ def_value->append_parenthesized(field->decimals());
+ }
else if (!field->is_null())
{ // Not null by default
char tmp[MAX_FIELD_WIDTH];
@@ -1643,16 +1673,18 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
}
if (!field->vcol_info &&
- get_field_default_value(thd, table->timestamp_field,
- field, &def_value, 1))
+ get_field_default_value(thd, field, &def_value, 1))
{
packet->append(STRING_WITH_LEN(" DEFAULT "));
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
}
- if (!limited_mysql_mode && table->timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_DN_FIELD)
- packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
+ if (!limited_mysql_mode && print_on_update_clause(field, &def_value, false))
+ {
+ packet->append(STRING_WITH_LEN(" "));
+ packet->append(def_value);
+ }
+
if (field->unireg_check == Field::NEXT_NUMBER &&
!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
@@ -2116,10 +2148,6 @@ public:
double progress;
};
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class I_List<thread_info>;
-#endif
-
static const char *thread_state_info(THD *tmp)
{
#ifndef EMBEDDED_LIBRARY
@@ -2320,7 +2348,7 @@ void Show_explain_request::call_in_target_thread()
int select_result_explain_buffer::send_data(List<Item> &items)
{
- fill_record(thd, dst_table->field, items, TRUE, FALSE);
+ fill_record(thd, dst_table, dst_table->field, items, TRUE, FALSE);
if ((dst_table->file->ha_write_tmp_row(dst_table->record[0])))
return 1;
return 0;
@@ -4056,8 +4084,9 @@ end:
/* Restore original LEX value, statement's arena and THD arena values. */
lex_end(thd->lex);
- if (i_s_arena.free_list)
- i_s_arena.free_items();
+ // Free items, before restoring backup_arena below.
+ DBUG_ASSERT(i_s_arena.free_list == NULL);
+ thd->free_items();
/*
For safety reset list of open temporary tables before closing
@@ -5212,7 +5241,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
const char *wild= lex->wild ? lex->wild->ptr() : NullS;
CHARSET_INFO *cs= system_charset_info;
TABLE *show_table;
- Field **ptr, *field, *timestamp_field;
+ Field **ptr, *field;
int count;
DBUG_ENTER("get_schema_column_record");
@@ -5236,7 +5265,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
show_table= tables->table;
count= 0;
ptr= show_table->field;
- timestamp_field= show_table->timestamp_field;
show_table->use_all_columns(); // Required for default
restore_record(show_table, s->default_values);
@@ -5284,7 +5312,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
cs);
table->field[4]->store((longlong) count, TRUE);
- if (get_field_default_value(thd, timestamp_field, field, &type, 0))
+ if (get_field_default_value(thd, field, &type, 0))
{
table->field[5]->store(type.ptr(), type.length(), cs);
table->field[5]->set_notnull();
@@ -5301,10 +5329,8 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
if (field->unireg_check == Field::NEXT_NUMBER)
table->field[17]->store(STRING_WITH_LEN("auto_increment"), cs);
- if (timestamp_field == field &&
- field->unireg_check != Field::TIMESTAMP_DN_FIELD)
- table->field[17]->store(STRING_WITH_LEN("on update CURRENT_TIMESTAMP"),
- cs);
+ if (print_on_update_clause(field, &type, true))
+ table->field[17]->store(type.ptr(), type.length(), cs);
if (field->vcol_info)
{
if (field->stored_in_db)
@@ -8905,11 +8931,6 @@ ST_SCHEMA_TABLE schema_tables[]=
};
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List_iterator_fast<char>;
-template class List<char>;
-#endif
-
int initialize_schema_table(st_plugin_int *plugin)
{
ST_SCHEMA_TABLE *schema_table;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 75029a03790..89536b93feb 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -502,6 +502,24 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
return FALSE;
}
+
+/**
+ Append a parenthesized number to String.
+ Used in various pieces of SHOW related code.
+
+ @param nr Number
+ @param radix Radix, optional parameter, 10 by default.
+*/
+bool String::append_parenthesized(long nr, int radix)
+{
+ char buff[64], *end;
+ buff[0]= '(';
+ end= int10_to_str(nr, buff + 1, radix);
+ *end++ = ')';
+ return append(buff, (uint) (end - buff));
+}
+
+
bool String::append_with_prefill(const char *s,uint32 arg_length,
uint32 full_length, char fill_char)
{
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 8b09d449c2b..2966fc2a920 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -346,6 +346,7 @@ public:
bool append(IO_CACHE* file, uint32 arg_length);
bool append_with_prefill(const char *s, uint32 arg_length,
uint32 full_length, char fill_char);
+ bool append_parenthesized(long nr, int radix= 10);
int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1
bool replace(uint32 offset,uint32 arg_length,const char *to,uint32 length);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 66e3b0b2544..6e99ebb0d37 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2610,7 +2610,6 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
prepare_create_field()
sql_field field to prepare for packing
blob_columns count for BLOBs
- timestamps count for timestamps
table_flags table flags
DESCRIPTION
@@ -2624,7 +2623,6 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
int prepare_create_field(Create_field *sql_field,
uint *blob_columns,
- int *timestamps, int *timestamps_with_niladic,
longlong table_flags)
{
unsigned int dup_val_count;
@@ -2746,21 +2744,6 @@ int prepare_create_field(Create_field *sql_field,
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
case MYSQL_TYPE_TIMESTAMP:
- /* We should replace old TIMESTAMP fields with their newer analogs */
- if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
- {
- if (!*timestamps)
- {
- sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
- (*timestamps_with_niladic)++;
- }
- else
- sql_field->unireg_check= Field::NONE;
- }
- else if (sql_field->unireg_check != Field::NONE)
- (*timestamps_with_niladic)++;
-
- (*timestamps)++;
/* fall-through */
default:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
@@ -2832,6 +2815,40 @@ bool check_duplicate_warning(THD *thd, char *msg, ulong length)
}
+/**
+ Modifies the first column definition whose SQL type is TIMESTAMP
+ by adding the features DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
+
+ @param column_definitions The list of column definitions, in the physical
+ order in which they appear in the table.
+ */
+void promote_first_timestamp_column(List<Create_field> *column_definitions)
+{
+ List_iterator<Create_field> it(*column_definitions);
+ Create_field *column_definition;
+
+ while ((column_definition= it++) != NULL)
+ {
+ if (column_definition->sql_type == MYSQL_TYPE_TIMESTAMP || // TIMESTAMP
+ column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
+ {
+ if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
+ column_definition->def == NULL && // no constant default,
+ column_definition->unireg_check == Field::NONE) // no function default
+ {
+ DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to "
+ "DEFAULT CURRENT_TIMESTAMP ON UPDATE "
+ "CURRENT_TIMESTAMP",
+ column_definition->field_name
+ ));
+ column_definition->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
+ }
+ return;
+ }
+ }
+}
+
+
/*
Preparation for table creation
@@ -2872,7 +2889,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
ulong record_offset= 0;
KEY *key_info;
KEY_PART_INFO *key_part_info;
- int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
List_iterator<Create_field> it(alter_info->create_list);
@@ -3156,7 +3172,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_ASSERT(sql_field->charset != 0);
if (prepare_create_field(sql_field, &blob_columns,
- &timestamps, &timestamps_with_niladic,
file->ha_table_flags()))
DBUG_RETURN(TRUE);
if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
@@ -3187,12 +3202,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
record_offset+= sql_field->pack_length;
}
}
- if (timestamps_with_niladic > 1)
- {
- my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
- ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
- DBUG_RETURN(TRUE);
- }
if (auto_increment > 1)
{
my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
@@ -4559,6 +4568,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
/* Got lock. */
DEBUG_SYNC(thd, "locked_table_name");
+ promote_first_timestamp_column(&alter_info->create_list);
result= mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name, create_info,
alter_info, FALSE, 0, &is_trans);
@@ -6386,6 +6396,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
need_copy_table= alter_info->change_level;
set_table_default_charset(thd, create_info, db);
+ promote_first_timestamp_column(&alter_info->create_list);
if (thd->variables.old_alter_table
|| (table->s->db_type() != create_info->db_type)
@@ -6753,8 +6764,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
*/
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
{
- /* We don't want update TIMESTAMP fields during ALTER TABLE. */
- new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field;
DBUG_EXECUTE_IF("abort_copy_table", {
my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
@@ -7331,6 +7340,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
ulonglong prev_insert_id, time_to_report_progress;
List_iterator<Create_field> it(create);
Create_field *def;
+ Field **dfield_ptr= to->default_field;
DBUG_ENTER("copy_data_between_tables");
/* Two or 3 stages; Sorting, copying data and update indexes */
@@ -7358,6 +7368,7 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
errpos= 3;
copy_end=copy;
+ to->s->default_fields= 0;
for (Field **ptr=to->field ; *ptr ; ptr++)
{
def=it++;
@@ -7377,8 +7388,23 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
}
(copy_end++)->set(*ptr,def->field,0);
}
-
+ else
+ {
+ /*
+ Update the set of auto-update fields to contain only the new fields
+ added to the table. Only these fields should be updated automatically.
+ Old fields keep their current values, and therefore should not be
+ present in the set of autoupdate fields.
+ */
+ if ((*ptr)->has_insert_default_function())
+ {
+ *(dfield_ptr++)= *ptr;
+ ++to->s->default_fields;
+ }
+ }
}
+ if (dfield_ptr)
+ *dfield_ptr= NULL;
if (order)
{
@@ -7468,7 +7494,12 @@ copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
}
prev_insert_id= to->file->next_insert_id;
if (to->vfield)
- update_virtual_fields(thd, to, TRUE);
+ update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE);
+ if (to->default_field && to->update_default_fields())
+ {
+ error= 1;
+ break;
+ }
if (thd->is_error())
{
error= 1;
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 00de6ed1b8d..9d5e768a5a3 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -187,7 +187,6 @@ void close_cached_table(THD *thd, TABLE *table);
void sp_prepare_create_field(THD *thd, Create_field *sql_field);
int prepare_create_field(Create_field *sql_field,
uint *blob_columns,
- int *timestamps, int *timestamps_with_niladic,
longlong table_flags);
CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
HA_CREATE_INFO *create_info);
@@ -208,6 +207,9 @@ void execute_ddl_log_recovery();
bool execute_ddl_log_entry(THD *thd, uint first_entry);
bool check_duplicate_warning(THD *thd, char *msg, ulong length);
+template<typename T> class List;
+void promote_first_timestamp_column(List<Create_field> *column_definitions);
+
/*
These prototypes where under INNODB_COMPATIBILITY_HOOKS.
*/
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 7fab29a7d64..bda9b919663 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -63,7 +63,7 @@ int select_union::send_data(List<Item> &values)
return 0;
if (table->no_rows_with_nulls)
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
- fill_record(thd, table->field, values, TRUE, FALSE);
+ fill_record(thd, table, table->field, values, TRUE, FALSE);
if (thd->is_error())
return 1;
if (table->no_rows_with_nulls)
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 42e2eb6cbfd..4ed67c86eb1 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -342,19 +342,8 @@ int mysql_update(THD *thd,
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
DBUG_RETURN(1);
}
- if (table->timestamp_field)
- {
- // Don't set timestamp column if this is modified
- if (bitmap_is_set(table->write_set,
- table->timestamp_field->field_index))
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- else
- {
- if (((uint) table->timestamp_field_type) & TIMESTAMP_AUTO_SET_ON_UPDATE)
- bitmap_set_bit(table->write_set,
- table->timestamp_field->field_index);
- }
- }
+ if (table->default_field)
+ table->mark_default_fields_for_write();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check values */
@@ -389,7 +378,7 @@ int mysql_update(THD *thd,
to compare records and detect data change.
*/
if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) &&
- (((uint) table->timestamp_field_type) & TIMESTAMP_AUTO_SET_ON_UPDATE))
+ table->default_field && table->has_default_function(true))
bitmap_union(table->read_set, table->write_set);
// Don't count on usage of 'only index' when calculating which key to use
table->covering_keys.clear_all();
@@ -563,7 +552,9 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (table->vfield)
- update_virtual_fields(thd, table);
+ update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
if (!select || (error= select->skip_record(thd)) > 0)
{
@@ -676,7 +667,9 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (table->vfield)
- update_virtual_fields(thd, table);
+ update_virtual_fields(thd, table,
+ table->triggers ? VCOL_UPDATE_ALL :
+ VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
if (!select || select->skip_record(thd) > 0)
{
@@ -684,8 +677,7 @@ int mysql_update(THD *thd,
continue; /* repeat the read of the same row if it still exists */
store_record(table,record[1]);
- if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
- table->triggers,
+ if (fill_record_n_invoke_before_triggers(thd, table, fields, values, 0,
TRG_EVENT_UPDATE))
break; /* purecov: inspected */
@@ -693,6 +685,11 @@ int mysql_update(THD *thd,
if (!can_compare_record || compare_record(table))
{
+ if (table->default_field && table->update_default_fields())
+ {
+ error= 1;
+ break;
+ }
if ((res= table_list->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK)
{
@@ -1239,11 +1236,6 @@ int mysql_multi_update_prepare(THD *thd)
while ((tl= ti++))
{
TABLE *table= tl->table;
- /* Only set timestamp column if this is not modified */
- if (table->timestamp_field &&
- bitmap_is_set(table->write_set,
- table->timestamp_field->field_index))
- table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/* if table will be updated then check that it is unique */
if (table->map & tables_for_update)
@@ -1491,8 +1483,7 @@ int multi_update::prepare(List<Item> &not_used_values,
to compare records and detect data change.
*/
if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) &&
- (((uint) table->timestamp_field_type) &
- TIMESTAMP_AUTO_SET_ON_UPDATE))
+ table->default_field && table->has_default_function(true))
bitmap_union(table->read_set, table->write_set);
}
}
@@ -1871,10 +1862,10 @@ int multi_update::send_data(List<Item> &not_used_values)
table->status|= STATUS_UPDATED;
store_record(table,record[1]);
- if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
+ if (fill_record_n_invoke_before_triggers(thd, table, *fields_for_table[offset],
*values_for_table[offset], 0,
- table->triggers,
- TRG_EVENT_UPDATE))
+ TRG_EVENT_UPDATE) ||
+ (table->default_field && table->update_default_fields()))
DBUG_RETURN(1);
/*
@@ -1975,7 +1966,7 @@ int multi_update::send_data(List<Item> &not_used_values)
} while ((tbl= tbl_it++));
/* Store regular updated fields in the row. */
- fill_record(thd,
+ fill_record(thd, tmp_table,
tmp_table->field + 1 + unupdated_check_opt_tables.elements,
*values_for_table[offset], TRUE, FALSE);
@@ -2165,7 +2156,10 @@ int multi_update::do_updates()
for (copy_field_ptr=copy_field;
copy_field_ptr != copy_field_end;
copy_field_ptr++)
+ {
(*copy_field_ptr->do_copy)(copy_field_ptr);
+ copy_field_ptr->to_field->set_has_explicit_value();
+ }
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
@@ -2175,6 +2169,8 @@ int multi_update::do_updates()
if (!can_compare_record || compare_record(table))
{
int error;
+ if (table->default_field && (error= table->update_default_fields()))
+ goto err2;
if ((error= cur_table->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK)
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b14757f7581..e9df67a7a05 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1595,6 +1595,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
optional_flush_tables_arguments opt_dyncol_type dyncol_type
opt_time_precision kill_type kill_option int_num
+ opt_default_time_precision
/*
Bit field of MYSQL_START_TRANS_OPT_* flags.
@@ -6025,9 +6026,9 @@ attribute:
NULL_SYM { Lex->type&= ~ NOT_NULL_FLAG; }
| not NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
| DEFAULT now_or_signed_literal { Lex->default_value=$2; }
- | ON UPDATE_SYM NOW_SYM optional_braces
+ | ON UPDATE_SYM NOW_SYM opt_default_time_precision
{
- Item *item= new (YYTHD->mem_root) Item_func_now_local(6);
+ Item *item= new (YYTHD->mem_root) Item_func_now_local($4);
if (item == NULL)
MYSQL_YYABORT;
Lex->on_update_value= item;
@@ -6119,9 +6120,9 @@ type_with_opt_collate:
now_or_signed_literal:
- NOW_SYM optional_braces
+ NOW_SYM opt_default_time_precision
{
- $$= new (YYTHD->mem_root) Item_func_now_local(6);
+ $$= new (YYTHD->mem_root) Item_func_now_local($2);
if ($$ == NULL)
MYSQL_YYABORT;
}
@@ -7945,6 +7946,12 @@ select_alias:
| TEXT_STRING_sys { $$=$1; }
;
+opt_default_time_precision:
+ /* empty */ { $$= NOT_FIXED_DEC; }
+ | '(' ')' { $$= NOT_FIXED_DEC; }
+ | '(' real_ulong_num ')' { $$= $2; };
+ ;
+
opt_time_precision:
/* empty */ { $$= 0; }
| '(' ')' { $$= 0; }
diff --git a/sql/sys_vars.h b/sql/sys_vars.h
index 98a2b4c17fb..98c71e1df13 100644
--- a/sql/sys_vars.h
+++ b/sql/sys_vars.h
@@ -2047,18 +2047,3 @@ public:
}
};
-
-/****************************************************************************
- Used templates
-****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<set_var_base>;
-template class List_iterator_fast<set_var_base>;
-template class Sys_var_integer<int, GET_INT, SHOW_SINT>;
-template class Sys_var_integer<uint, GET_UINT, SHOW_INT>;
-template class Sys_var_integer<ulong, GET_ULONG, SHOW_LONG>;
-template class Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS>;
-template class Sys_var_integer<ulonglong, GET_ULL, SHOW_LONGLONG>;
-#endif
-
diff --git a/sql/table.cc b/sql/table.cc
index 18aaed6d81f..9954d91cab4 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -981,7 +981,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keyinfo->ext_key_part_map= 0;
if (share->use_ext_keys && i)
{
- keyinfo->ext_key_flags= keyinfo->flags | HA_NOSAME;
keyinfo->ext_key_part_map= 0;
for (j= 0;
j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS;
@@ -1002,7 +1001,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keyinfo->ext_key_parts++;
keyinfo->ext_key_part_map|= 1 << j;
}
- }
+ }
+ if (j == first_key_parts)
+ keyinfo->ext_key_flags= keyinfo->flags | HA_NOSAME | HA_EXT_NOSAME;
}
share->ext_key_parts+= keyinfo->ext_key_parts;
}
@@ -1250,6 +1251,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
com_length= uint2korr(forminfo+284);
vcol_screen_length= uint2korr(forminfo+286);
share->vfields= 0;
+ share->default_fields= 0;
share->stored_fields= share->fields;
if (forminfo[46] != (uchar)255)
{
@@ -1581,8 +1583,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (reg_field->unireg_check == Field::NEXT_NUMBER)
share->found_next_number_field= field_ptr;
- if (share->timestamp_field == reg_field)
- share->timestamp_field_offset= i;
if (use_hash)
{
@@ -1604,6 +1604,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if (share->stored_rec_length>=recpos)
share->stored_rec_length= recpos-1;
}
+ if (reg_field->has_insert_default_function() ||
+ reg_field->has_update_default_function())
+ ++share->default_fields;
}
*field_ptr=0; // End marker
/* Sanity checks: */
@@ -2315,7 +2318,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
uint records, i, bitmap_size;
bool error_reported= FALSE;
uchar *record, *bitmaps;
- Field **field_ptr, **vfield_ptr;
+ Field **field_ptr, **vfield_ptr, **dfield_ptr;
uint8 save_context_analysis_only= thd->lex->context_analysis_only;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
@@ -2419,9 +2422,6 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
if (share->found_next_number_field)
outparam->found_next_number_field=
outparam->field[(uint) (share->found_next_number_field - share->field)];
- if (share->timestamp_field)
- outparam->timestamp_field= (Field_timestamp*) outparam->field[share->timestamp_field_offset];
-
/* Fix key->name and key_part->field */
if (share->key_parts)
@@ -2472,11 +2472,9 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
}
/*
- Process virtual columns, if any.
+ Process virtual and default columns, if any.
*/
- if (!share->vfields)
- outparam->vfield= NULL;
- else
+ if (share->vfields)
{
if (!(vfield_ptr = (Field **) alloc_root(&outparam->mem_root,
(uint) ((share->vfields+1)*
@@ -2484,10 +2482,24 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
goto err;
outparam->vfield= vfield_ptr;
+ }
+
+ if (share->default_fields)
+ {
+ if (!(dfield_ptr = (Field **) alloc_root(&outparam->mem_root,
+ (uint) ((share->default_fields+1)*
+ sizeof(Field*)))))
+ goto err;
+ outparam->default_field= dfield_ptr;
+ }
+
+ if (share->vfields || share->default_fields)
+ {
+ /* Reuse the same loop both for virtual and default fields. */
for (field_ptr= outparam->field; *field_ptr; field_ptr++)
{
- if ((*field_ptr)->vcol_info)
+ if (share->vfields && (*field_ptr)->vcol_info)
{
if (unpack_vcol_info_from_frm(thd,
outparam,
@@ -2500,8 +2512,15 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
}
*(vfield_ptr++)= *field_ptr;
}
+ if (share->default_fields &&
+ ((*field_ptr)->has_insert_default_function() ||
+ (*field_ptr)->has_update_default_function()))
+ *(dfield_ptr++)= *field_ptr;
}
- *vfield_ptr= 0; // End marker
+ if (share->vfields)
+ *vfield_ptr= 0; // End marker
+ if (share->default_fields)
+ *dfield_ptr= 0; // End marker
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -3927,9 +3946,6 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
DBUG_ASSERT(!auto_increment_field_not_null);
auto_increment_field_not_null= FALSE;
- if (timestamp_field)
- timestamp_field_type= timestamp_field->get_auto_set_type();
-
pos_in_table_list= tl;
clear_column_bitmaps();
@@ -5856,6 +5872,51 @@ void TABLE::mark_virtual_columns_for_write(bool insert_fl)
/**
+ Check if a table has a default function either for INSERT or UPDATE-like
+ operation
+ @retval true there is a default function
+ @retval false there is no default function
+*/
+
+bool TABLE::has_default_function(bool is_update)
+{
+ Field **dfield_ptr, *dfield;
+ bool res= false;
+ for (dfield_ptr= default_field; *dfield_ptr; dfield_ptr++)
+ {
+ dfield= (*dfield_ptr);
+ if (is_update)
+ res= dfield->has_update_default_function();
+ else
+ res= dfield->has_insert_default_function();
+ if (res)
+ return res;
+ }
+ return res;
+}
+
+
+/**
+ Add all fields that have a default function to the table write set.
+*/
+
+void TABLE::mark_default_fields_for_write()
+{
+ Field **dfield_ptr, *dfield;
+ enum_sql_command cmd= in_use->lex->sql_command;
+ for (dfield_ptr= default_field; *dfield_ptr; dfield_ptr++)
+ {
+ dfield= (*dfield_ptr);
+ if (((sql_command_flags[cmd] & CF_INSERTS_DATA) &&
+ dfield->has_insert_default_function()) ||
+ ((sql_command_flags[cmd] & CF_UPDATES_DATA) &&
+ dfield->has_update_default_function()))
+ bitmap_set_bit(write_set, dfield->field_index);
+ }
+}
+
+
+/**
@brief
Allocate space for keys
@@ -6416,22 +6477,25 @@ bool is_simple_order(ORDER *order)
@param thd Thread handle
@param table The TABLE object
- @param for_write Requests to compute only fields needed for write
+ @param vcol_update_mode Specifies what virtual column are computed
@details
The function computes the values of the virtual columns of the table and
stores them in the table record buffer.
- Only fields from vcol_set are computed, and, when the flag for_write is not
- set to TRUE, a virtual field is computed only if it's not stored.
- The flag for_write is set to TRUE for row insert/update operations.
-
+ If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are
+ computed. Otherwise, only fields from vcol_set are computed: all of them,
+ if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with
+ the stored_in_db flag set to false, if vcol_update_mode is equal to
+ VCOL_UPDATE_FOR_READ.
+
@retval
0 Success
@retval
>0 Error occurred when storing a virtual field value
*/
-int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
+int update_virtual_fields(THD *thd, TABLE *table,
+ enum enum_vcol_update_mode vcol_update_mode)
{
DBUG_ENTER("update_virtual_fields");
Field **vfield_ptr, *vfield;
@@ -6444,9 +6508,9 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
{
vfield= (*vfield_ptr);
DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item);
- /* Only update those fields that are marked in the vcol_set bitmap */
- if (bitmap_is_set(table->vcol_set, vfield->field_index) &&
- (for_write || !vfield->stored_in_db))
+ if ((bitmap_is_set(table->vcol_set, vfield->field_index) &&
+ (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) ||
+ vcol_update_mode == VCOL_UPDATE_ALL)
{
/* Compute the actual value of the virtual fields */
error= vfield->vcol_info->expr_item->save_in_field(vfield, 0);
@@ -6461,6 +6525,56 @@ int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
DBUG_RETURN(0);
}
+
+/**
+ Update all DEFAULT and/or ON INSERT fields.
+
+ @details
+ Compute and set the default value of all fields with a default function.
+ There are two kinds of default functions - one is used for INSERT-like
+ operations, the other for UPDATE-like operations. Depending on the field
+ definition and the current operation one or the other kind of update
+ function is evaluated.
+
+ @retval
+ 0 Success
+ @retval
+ >0 Error occurred when storing a virtual field value
+*/
+
+int TABLE::update_default_fields()
+{
+ DBUG_ENTER("update_default_fields");
+ Field **dfield_ptr, *dfield;
+ int res= 0;
+ enum_sql_command cmd= in_use->lex->sql_command;
+
+ DBUG_ASSERT(default_field);
+
+ /* Iterate over virtual fields in the table */
+ for (dfield_ptr= default_field; *dfield_ptr; dfield_ptr++)
+ {
+ dfield= (*dfield_ptr);
+ /*
+ If an explicit default value for a filed overrides the default,
+ do not update the field with its automatic default value.
+ */
+ if (!(dfield->flags & HAS_EXPLICIT_VALUE))
+ {
+ if (sql_command_flags[cmd] & CF_INSERTS_DATA)
+ res= dfield->evaluate_insert_default_function();
+ if (sql_command_flags[cmd] & CF_UPDATES_DATA)
+ res= dfield->evaluate_update_default_function();
+ if (res)
+ DBUG_RETURN(res);
+ }
+ /* Unset the explicit default flag for the next record. */
+ dfield->flags&= ~HAS_EXPLICIT_VALUE;
+ }
+ DBUG_RETURN(res);
+}
+
+
/*
@brief Reset const_table flag
@@ -6767,12 +6881,3 @@ uint TABLE_SHARE::actual_n_key_parts(THD *thd)
ext_key_parts : key_parts;
}
-
-/*****************************************************************************
-** Instansiate templates
-*****************************************************************************/
-
-#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<String>;
-template class List_iterator<String>;
-#endif
diff --git a/sql/table.h b/sql/table.h
index 1f546693fb3..a43f729ba5c 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -300,6 +300,12 @@ enum tmp_table_type
};
enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
+enum enum_vcol_update_mode
+{
+ VCOL_UPDATE_FOR_READ= 0,
+ VCOL_UPDATE_FOR_WRITE,
+ VCOL_UPDATE_ALL
+};
class Filesort_info
{
@@ -350,25 +356,6 @@ public:
};
-/*
- Values in this enum are used to indicate how a tables TIMESTAMP field
- should be treated. It can be set to the current timestamp on insert or
- update or both.
- WARNING: The values are used for bit operations. If you change the
- enum, you must keep the bitwise relation of the values. For example:
- (int) TIMESTAMP_AUTO_SET_ON_BOTH must be equal to
- (int) TIMESTAMP_AUTO_SET_ON_INSERT | (int) TIMESTAMP_AUTO_SET_ON_UPDATE.
- We use an enum here so that the debugger can display the value names.
-*/
-enum timestamp_auto_set_type
-{
- TIMESTAMP_NO_AUTO_SET= 0, TIMESTAMP_AUTO_SET_ON_INSERT= 1,
- TIMESTAMP_AUTO_SET_ON_UPDATE= 2, TIMESTAMP_AUTO_SET_ON_BOTH= 3
-};
-#define clear_timestamp_auto_bits(_target_, _bits_) \
- (_target_)= (enum timestamp_auto_set_type)((int)(_target_) & ~(int)(_bits_))
-
-class Field_timestamp;
class Field_blob;
class Table_triggers_list;
@@ -608,7 +595,6 @@ struct TABLE_SHARE
/* The following is copied to each TABLE on OPEN */
Field **field;
Field **found_next_number_field;
- Field *timestamp_field; /* Used only during open */
KEY *key_info; /* data of keys in database */
uint *blob_field; /* Index to blobs in Field arrray*/
@@ -680,7 +666,6 @@ struct TABLE_SHARE
uint uniques; /* Number of UNIQUE index */
uint null_fields; /* number of null fields */
uint blob_fields; /* number of blob fields */
- uint timestamp_field_offset; /* Field number for timestamp field */
uint varchar_fields; /* number of varchar fields */
uint db_create_options; /* Create options from database */
uint db_options_in_use; /* Options in use */
@@ -695,6 +680,7 @@ struct TABLE_SHARE
uint column_bitmap_size;
uchar frm_version;
uint vfields; /* Number of computed (virtual) fields */
+ uint default_fields; /* Number of default fields */
bool use_ext_keys; /* Extended keys can be used */
bool null_field_first;
bool system; /* Set if system table (one record) */
@@ -1007,8 +993,9 @@ public:
Field *next_number_field; /* Set if next_number is activated */
Field *found_next_number_field; /* Set on open */
- Field_timestamp *timestamp_field;
Field **vfield; /* Pointer to virtual fields*/
+ /* Fields that are updated automatically on INSERT or UPDATE. */
+ Field **default_field;
/* Table's triggers, 0 if there are no of them */
Table_triggers_list *triggers;
@@ -1064,19 +1051,6 @@ public:
*/
ha_rows quick_condition_rows;
- /*
- If this table has TIMESTAMP field with auto-set property (pointed by
- timestamp_field member) then this variable indicates during which
- operations (insert only/on update/in both cases) we should set this
- field to current timestamp. If there are no such field in this table
- or we should not automatically set its value during execution of current
- statement then the variable contains TIMESTAMP_NO_AUTO_SET (i.e. 0).
-
- Value of this variable is set for each statement in open_table() and
- if needed cleared later in statement processing code (see mysql_update()
- as example).
- */
- timestamp_auto_set_type timestamp_field_type;
table_map map; /* ID bit of table (1,2,4,8,16...) */
uint lock_position; /* Position in MYSQL_LOCK.table */
@@ -1212,6 +1186,8 @@ public:
void mark_columns_needed_for_insert(void);
bool mark_virtual_col(Field *field);
void mark_virtual_columns_for_write(bool insert_fl);
+ void mark_default_fields_for_write();
+ bool has_default_function(bool is_update);
inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
MY_BITMAP *write_set_arg)
{
@@ -1298,6 +1274,7 @@ public:
bool update_const_key_parts(COND *conds);
uint actual_n_key_parts(KEY *keyinfo);
ulong actual_key_flags(KEY *keyinfo);
+ int update_default_fields();
};