[Commits] Rev 4473: MDEV-6849 ON UPDATE CURRENT_TIMESTAMP doesn't always work in lp:~maria-captains/maria/10.0

Sergei Golubchik serg at mariadb.org
Tue Nov 11 11:40:46 EET 2014


At lp:~maria-captains/maria/10.0

------------------------------------------------------------
revno: 4473
revision-id: sergii at pisem.net-20141111094046-m13fp2219808bkl2
parent: sergii at pisem.net-20141111093935-9ix76vd0cs6nb77k
fixes bug: https://mariadb.atlassian.net/browse/MDEV-6849
committer: Sergei Golubchik <sergii at pisem.net>
branch nick: 10.0
timestamp: Tue 2014-11-11 10:40:46 +0100
message:
  MDEV-6849 ON UPDATE CURRENT_TIMESTAMP doesn't always work
  
  reset default fields not for every modified row, but only once,
  at the beginning, as the set of modified fields doesn't change.
  
  exception: INSERT ... ON DUPLICATE KEY UPDATE - the set of fields
  does change per row and in that case we reset default fields per row.
=== modified file 'mysql-test/include/function_defaults.inc'
--- a/mysql-test/include/function_defaults.inc	2012-10-17 12:43:56 +0000
+++ b/mysql-test/include/function_defaults.inc	2014-11-11 09:40:46 +0000
@@ -408,15 +408,28 @@ UPDATE t1 SET c = 2;
 SELECT * FROM t1;
 
 --echo #
+--echo # Test that ON UPDATE CURRENT_TIMESTAMP works after non-changing UPDATE.
+--echo #
+
+--echo # 2011-04-20 09:54:13 UTC
+SET TIMESTAMP = 1303293253.794613;
+
+UPDATE t1 SET c = 2, b = '2011-04-20 09:53:41.794613';
+SELECT * FROM t1;
+
+UPDATE t1 SET c = 3;
+SELECT * FROM t1;
+
+--echo #
 --echo # Test of multiple-table UPDATE for ON UPDATE CURRENT_TIMESTAMP
 --echo #
 --echo # 2011-04-20 15:06:13 UTC
 SET TIMESTAMP = 1303311973.534231;
 
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
+UPDATE t1 t11, t1 t12 SET t11.c = 3;
 SELECT * FROM t1;
 
-UPDATE t1 t11, t1 t12 SET t11.c = 3;
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
 SELECT * FROM t1;
 
 DROP TABLE t1;

=== modified file 'mysql-test/r/function_defaults.result'
--- a/mysql-test/r/function_defaults.result	2012-10-17 12:43:56 +0000
+++ b/mysql-test/r/function_defaults.result	2014-11-11 09:40:46 +0000
@@ -435,18 +435,31 @@ SELECT * FROM t1;
 a	b	c
 2011-04-20 09:53:41	2011-04-20 09:53:41	2
 #
+# Test that ON UPDATE CURRENT_TIMESTAMP works after non-changing UPDATE.
+#
+# 2011-04-20 09:54:13 UTC
+SET TIMESTAMP = 1303293253.794613;
+UPDATE t1 SET c = 2, b = '2011-04-20 09:53:41.794613';
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	2011-04-20 09:53:41	2
+UPDATE t1 SET c = 3;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:54:13	2011-04-20 09:54:13	3
+#
 # Test of multiple-table UPDATE for ON UPDATE CURRENT_TIMESTAMP
 #
 # 2011-04-20 15:06:13 UTC
 SET TIMESTAMP = 1303311973.534231;
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
+UPDATE t1 t11, t1 t12 SET t11.c = 3;
 SELECT * FROM t1;
 a	b	c
-2011-04-20 09:53:41	2011-04-20 09:53:41	2
-UPDATE t1 t11, t1 t12 SET t11.c = 3;
+2011-04-20 09:54:13	2011-04-20 09:54:13	3
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
 SELECT * FROM t1;
 a	b	c
-2011-04-20 15:06:13	2011-04-20 15:06:13	3
+2011-04-20 15:06:13	2011-04-20 15:06:13	2
 DROP TABLE t1;
 #
 # Test of a multiple-table update where only one table is updated and
@@ -1967,18 +1980,31 @@ SELECT * FROM t1;
 a	b	c
 2011-04-20 09:53:41.794613	2011-04-20 09:53:41.794613	2
 #
+# Test that ON UPDATE CURRENT_TIMESTAMP works after non-changing UPDATE.
+#
+# 2011-04-20 09:54:13 UTC
+SET TIMESTAMP = 1303293253.794613;
+UPDATE t1 SET c = 2, b = '2011-04-20 09:53:41.794613';
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41.794613	2011-04-20 09:53:41.794613	2
+UPDATE t1 SET c = 3;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:54:13.794613	2011-04-20 09:54:13.794613	3
+#
 # Test of multiple-table UPDATE for ON UPDATE CURRENT_TIMESTAMP
 #
 # 2011-04-20 15:06:13 UTC
 SET TIMESTAMP = 1303311973.534231;
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
+UPDATE t1 t11, t1 t12 SET t11.c = 3;
 SELECT * FROM t1;
 a	b	c
-2011-04-20 09:53:41.794613	2011-04-20 09:53:41.794613	2
-UPDATE t1 t11, t1 t12 SET t11.c = 3;
+2011-04-20 09:54:13.794613	2011-04-20 09:54:13.794613	3
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
 SELECT * FROM t1;
 a	b	c
-2011-04-20 15:06:13.534231	2011-04-20 15:06:13.534231	3
+2011-04-20 15:06:13.534231	2011-04-20 15:06:13.534231	2
 DROP TABLE t1;
 #
 # Test of a multiple-table update where only one table is updated and

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2014-09-30 17:31:14 +0000
+++ b/sql/sql_insert.cc	2014-11-11 09:40:46 +0000
@@ -868,6 +868,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       table_list->prepare_check_option(thd))
     error= 1;
 
+  table->reset_default_fields();
+
   while ((values= its++))
   {
     if (fields.elements || !value_count)
@@ -1661,6 +1663,13 @@ int write_record(THD *thd, TABLE *table,
 	DBUG_ASSERT(table->insert_values != NULL);
         store_record(table,insert_values);
         restore_record(table,record[1]);
+
+        /*
+          in INSERT ... ON DUPLICATE KEY UPDATE the set of modified fields can
+          change per row. Thus, we have to do reset_default_fields() per row.
+          Twice (before insert and before update).
+        */
+        table->reset_default_fields();
         DBUG_ASSERT(info->update_fields->elements ==
                     info->update_values->elements);
         if (fill_record_n_invoke_before_triggers(thd, table, *info->update_fields,
@@ -1688,6 +1697,7 @@ int write_record(THD *thd, TABLE *table,
           if (res)
             goto err;
         }
+        table->reset_default_fields();
 
         /* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
         if (info->view &&

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2014-09-30 17:31:14 +0000
+++ b/sql/sql_load.cc	2014-11-11 09:40:46 +0000
@@ -478,6 +478,7 @@ int mysql_load(THD *thd,sql_exchange *ex
   thd_proc_info(thd, "reading file");
   if (!(error= MY_TEST(read_info.error)))
   {
+    table->reset_default_fields();
     table->next_number_field=table->found_next_number_field;
     if (ignore ||
 	handle_duplicates == DUP_REPLACE)

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2014-11-11 09:39:35 +0000
+++ b/sql/sql_update.cc	2014-11-11 09:40:46 +0000
@@ -717,6 +717,8 @@ int mysql_update(THD *thd,
   if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)
     table->prepare_for_position();
 
+  table->reset_default_fields();
+
   /*
     We can use compare_record() to optimize away updates if
     the table handler is returning all columns OR if
@@ -1693,6 +1695,7 @@ int multi_update::prepare(List<Item> &no
       table->covering_keys.clear_all();
       table->pos_in_table_list= tl;
       table->prepare_triggers_for_update_stmt_or_event();
+      table->reset_default_fields();
     }
   }
 

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2014-10-29 12:20:46 +0000
+++ b/sql/table.cc	2014-11-11 09:40:46 +0000
@@ -6736,7 +6736,7 @@ int TABLE::update_default_fields()
 
   DBUG_ASSERT(default_field);
 
-  /* Iterate over virtual fields in the table */
+  /* Iterate over fields with default functions in the table */
   for (dfield_ptr= default_field; *dfield_ptr; dfield_ptr++)
   {
     dfield= (*dfield_ptr);
@@ -6753,12 +6753,16 @@ int TABLE::update_default_fields()
       if (res)
         DBUG_RETURN(res);
     }
-    /* Unset the explicit default flag for the next record. */
-    dfield->flags&= ~HAS_EXPLICIT_VALUE;
   }
   DBUG_RETURN(res);
 }
 
+void TABLE::reset_default_fields()
+{
+  if (default_field)
+    for (Field **df= default_field; *df; df++)
+      (*df)->flags&= ~HAS_EXPLICIT_VALUE;
+}
 
 /*
   Prepare triggers  for INSERT-like statement.

=== modified file 'sql/table.h'
--- a/sql/table.h	2014-09-16 12:03:17 +0000
+++ b/sql/table.h	2014-11-11 09:40:46 +0000
@@ -1377,6 +1377,7 @@ struct TABLE
   uint actual_n_key_parts(KEY *keyinfo);
   ulong actual_key_flags(KEY *keyinfo);
   int update_default_fields();
+  void reset_default_fields();
   inline ha_rows stat_records() { return used_stat_records; }
 
   void prepare_triggers_for_insert_stmt_or_event();



More information about the commits mailing list