List:Commits« Previous MessageNext Message »
From:Martin Hansson Date:May 11 2011 1:06pm
Subject:bzr push into mysql-trunk branch (martin.hansson:3368 to 3369) WL#5874
View as plain text  
 3369 Martin Hansson	2011-05-11
      Wl#5874
      
      Done:
      - Memory leak fixed.
      - An extra constructor added for the UPDATE part of INSERT ON DUPLICATE KEY.
      - COPY_INFO statistics moved to their own nested class. Lets us use a default constructor and shorten COPY_INFO's initializer lists.
      
      Not done:
      - REPLACE INTO is not yet done and tests for it are missing.
      - At Tor's behest, all arguments taken by reference must be changed to taking them by pointers.
      - Lots of now-dead code must be deleted. Most notably the Field_timestamp pointers in TABLE and TABLE_SHARE, and Field_timestamp::set_time().
      - We need to test backward compatibility for .frm files.

    removed:
      mysql-test/r/wl5874.result
      mysql-test/t/wl5874.test
    added:
      mysql-test/r/function_defaults.result
      mysql-test/t/function_defaults.test
    modified:
      new_files.txt
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_insert.cc
      sql/sql_load.cc
      sql/table.cc
      unittest/gunit/copy_info-t.cc
 3368 Martin Hansson	2011-05-10
      Wl#5874
      
      All tests pass, but some more remains to be done.
      
      - Fatal memory leak in COPY_INFO. Hopefully this can be remedied by freeing
        the memory in the destructor, but it must be verified that it is always
        called. (In MySQL code we cannot take this for granted).
      
      - REPLACE INTO is not yet done and tests for it are missing.
      
      - At Tor's behest, all arguments taken by reference must be changed to taking
        them by pointers.
      
      - Lots of now-dead code must be deleted. Most notably the Field_timestamp
        pointers in TABLE and TABLE_SHARE, and Field_timestamp::set_time().
      
      - We need to test backward compatibility for .frm files.

    added:
      mysql-test/r/wl5874.result
      mysql-test/t/wl5874.test
      new_files.txt
      unittest/gunit/copy_info-t.cc
      unittest/gunit/create_field-t.cc
      unittest/gunit/field_timestamp-t.cc
      unittest/gunit/item_func_now_local-t.cc
      unittest/gunit/mock_field_timestamp.h
      unittest/gunit/servertest.h
    modified:
      .bzr-mysql/default.conf
      mysql-test/r/create.result
      mysql-test/r/type_timestamp.result
      mysql-test/t/create.test
      mysql-test/t/type_timestamp.test
      sql/event_db_repository.cc
      sql/field.cc
      sql/field.h
      sql/ha_ndbcluster.cc
      sql/ha_partition.cc
      sql/item_timefunc.cc
      sql/item_timefunc.h
      sql/sp_head.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_insert.cc
      sql/sql_insert.h
      sql/sql_list.h
      sql/sql_load.cc
      sql/sql_parse.cc
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_table.h
      sql/sql_update.cc
      sql/table.cc
      sql/table.h
      sql/unireg.cc
      storage/archive/ha_archive.cc
      storage/csv/ha_tina.cc
      storage/example/ha_example.cc
      storage/federated/ha_federated.cc
      storage/heap/ha_heap.cc
      storage/innobase/handler/ha_innodb.cc
      storage/myisam/ha_myisam.cc
      storage/myisammrg/ha_myisammrg.cc
      unittest/gunit/CMakeLists.txt
=== added file 'mysql-test/r/function_defaults.result'
--- a/mysql-test/r/function_defaults.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/function_defaults.result	2011-05-11 13:05:53 +0000
@@ -0,0 +1,256 @@
+#
+# Worklog#5874:
+#
+#
+SET TIME_ZONE = "+00:00";
+CREATE TABLE t1 (
+a TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+c TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+d TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+e TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+f INT
+);
+# 2011-04-19 07:22:02 UTC
+SET TIMESTAMP = 1303197722;
+INSERT INTO t1 ( f ) VALUES (1);
+SELECT * FROM t1;
+a	b	c	d	e	f
+2011-04-19 07:22:02	2011-04-19 07:22:02	2011-04-19 07:22:02	0000-00-00 00:00:00	0000-00-00 00:00:00	1
+# 2011-04-19 07:23:18 UTC
+SET TIMESTAMP = 1303197798;
+UPDATE t1 SET f = 2;
+SELECT * FROM t1;
+a	b	c	d	e	f
+2011-04-19 07:23:18	2011-04-19 07:23:18	2011-04-19 07:22:02	2011-04-19 07:23:18	2011-04-19 07:23:18	2
+DROP TABLE t1;
+#
+# Test of ON DUPLICATE KEY
+#
+CREATE TABLE t1 ( a INT PRIMARY KEY, b INT, c TIMESTAMP );
+INSERT INTO t1 VALUES
+(1, 0, '2001-01-01 01:01:01'),
+(2, 0, '2002-02-02 02:02:02'),
+(3, 0, '2003-03-03 03:03:03');
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	0	2002-02-02 02:02:02
+3	0	2003-03-03 03:03:03
+UPDATE t1 SET b = 2, c = c WHERE a = 2;
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	2	2002-02-02 02:02:02
+3	0	2003-03-03 03:03:03
+INSERT INTO t1 (a) VALUES (4);
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	2	2002-02-02 02:02:02
+3	0	2003-03-03 03:03:03
+4	NULL	2011-04-19 07:23:18
+UPDATE t1 SET c = '2004-04-04 04:04:04' WHERE a = 4;
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	2	2002-02-02 02:02:02
+3	0	2003-03-03 03:03:03
+4	NULL	2004-04-04 04:04:04
+INSERT INTO t1 (a) VALUES (3), (5) ON DUPLICATE KEY UPDATE b = 3, c = c;
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	2	2002-02-02 02:02:02
+3	3	2003-03-03 03:03:03
+4	NULL	2004-04-04 04:04:04
+5	NULL	2011-04-19 07:23:18
+INSERT INTO t1 (a, c) VALUES
+(4, '2004-04-04 00:00:00'),
+(6, '2006-06-06 06:06:06')
+ON DUPLICATE KEY UPDATE b = 4;
+SELECT * FROM t1;
+a	b	c
+1	0	2001-01-01 01:01:01
+2	2	2002-02-02 02:02:02
+3	3	2003-03-03 03:03:03
+4	4	2011-04-19 07:23:18
+5	NULL	2011-04-19 07:23:18
+6	NULL	2006-06-06 06:06:06
+DROP TABLE t1;
+#
+# Test of INSERT DELAYED ... SET ...
+#
+# 2011-04-19 08:02:40 UTC
+SET TIMESTAMP = 1303200160;
+CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
+INSERT DELAYED INTO t1 SET a = 1;
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	tmsp
+1	2011-04-19 08:02:40
+SELECT * FROM t1 WHERE tmsp = 0;
+a	tmsp
+INSERT DELAYED INTO t1 SET a = 2, tmsp = '1980-01-02 10:20:30';
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	tmsp
+1	2011-04-19 08:02:40
+2	1980-01-02 10:20:30
+DROP TABLE t1;
+#
+# Test of INSERT DELAYED ... VALUES ...
+#
+# 2011-04-19 08:04:01 UTC 
+SET TIMESTAMP = 1303200241;
+CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
+INSERT DELAYED INTO t1 ( a ) VALUES (1);
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	tmsp
+1	2011-04-19 08:04:01
+INSERT DELAYED INTO t1 VALUES (2, '1977-12-19 12:34:56');
+FLUSH TABLE t1;
+SELECT * FROM t1;
+a	tmsp
+1	2011-04-19 08:04:01
+2	1977-12-19 12:34:56
+DROP TABLE t1;
+# 2011-04-20 07:05:39 UTC
+SET TIMESTAMP = 1303283139;
+CREATE TABLE t1 (
+a TIMESTAMP DEFAULT "2010-10-11 12:34:56",
+b DATETIME DEFAULT "2010-10-11 12:34:56"
+);
+INSERT INTO t1          VALUES (NULL, NULL), (DEFAULT, DEFAULT);
+INSERT INTO t1 ( a, b ) VALUES (NULL, NULL), (DEFAULT, DEFAULT);
+SELECT * FROM t1;
+a	b
+2011-04-20 07:05:39	NULL
+2010-10-11 12:34:56	2010-10-11 12:34:56
+2011-04-20 07:05:39	NULL
+2010-10-11 12:34:56	2010-10-11 12:34:56
+DROP TABLE t1;
+CREATE TABLE t1 ( 
+a TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
+b DATETIME DEFAULT CURRENT_TIMESTAMP, 
+c INT
+);
+# 2011-04-20 09:53:41 UTC
+SET TIMESTAMP = 1303293221;
+INSERT INTO t1 VALUES (NULL, NULL, 1), (DEFAULT, DEFAULT, 2);
+INSERT INTO t1 ( a, b, c ) VALUES (NULL, NULL, 3), (DEFAULT, DEFAULT, 4);
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	NULL	1
+2011-04-20 09:53:41	2011-04-20 09:53:41	2
+2011-04-20 09:53:41	NULL	3
+2011-04-20 09:53:41	2011-04-20 09:53:41	4
+SET TIME_ZONE = "+03:00";
+SELECT * FROM t1;
+a	b	c
+2011-04-20 12:53:41	NULL	1
+2011-04-20 12:53:41	2011-04-20 09:53:41	2
+2011-04-20 12:53:41	NULL	3
+2011-04-20 12:53:41	2011-04-20 09:53:41	4
+SET TIME_ZONE = "+00:00";
+DELETE FROM t1;
+INSERT INTO t1 ( c ) VALUES (1);
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	2011-04-20 09:53:41	1
+# 2011-04-20 17:06:13 
+SET TIMESTAMP = 1303311973;
+UPDATE t1 t11, t1 t12 SET t11.c = 1;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	2011-04-20 09:53:41	1
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	2011-04-20 09:53:41	2
+DROP TABLE t1;
+CREATE TABLE t1 (
+a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+b DATETIME ON UPDATE CURRENT_TIMESTAMP,
+c INT
+);
+# 2011-04-20 09:53:41 UTC
+SET TIMESTAMP = 1303293221;
+INSERT INTO t1 ( c ) VALUES ( 1 );
+SELECT * FROM t1;
+a	b	c
+0000-00-00 00:00:00	NULL	1
+UPDATE t1 SET c = 1;
+SELECT * FROM t1;
+a	b	c
+0000-00-00 00:00:00	NULL	1
+UPDATE t1 SET c = 2;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 09:53:41	2011-04-20 09:53:41	2
+# 2011-04-20 15:06:13 UTC
+SET TIMESTAMP = 1303311973;
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
+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;
+SELECT * FROM t1;
+a	b	c
+2011-04-20 15:06:13	2011-04-20 15:06:13	3
+DROP TABLE t1;
+# 
+# Test of CREATE TABLE ... SELECT ...
+# 
+CREATE TABLE t1 (
+a TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+c TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+d DATETIME DEFAULT CURRENT_TIMESTAMP,
+e DATETIME ON UPDATE CURRENT_TIMESTAMP,
+f DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+);
+CREATE TABLE t2 SELECT a, b, c, d, e, f FROM t1;
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `a` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `b` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `c` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `d` datetime DEFAULT NULL,
+  `e` datetime DEFAULT NULL,
+  `f` datetime DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1, t2;
+#
+# Test of ALTER TABLE, reordering columns.
+#
+CREATE TABLE t1 ( a TIMESTAMP, b INT );
+ALTER TABLE t1 MODIFY a TIMESTAMP AFTER b;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `b` int(11) DEFAULT NULL,
+  `a` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 ( a INT, b TIMESTAMP, c TIMESTAMP NULL );
+ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `a` int(11) DEFAULT NULL,
+  `c` timestamp NULL DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 ( a INT, b TIMESTAMP NULL );
+ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;

=== removed file 'mysql-test/r/wl5874.result'
--- a/mysql-test/r/wl5874.result	2011-05-10 14:18:34 +0000
+++ b/mysql-test/r/wl5874.result	1970-01-01 00:00:00 +0000
@@ -1,202 +0,0 @@
-#
-# Worklog#5874:
-#
-#
-SET TIME_ZONE = "+00:00";
-CREATE TABLE t2 (
-a TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-c TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-d TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-e TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-f INT
-);
-# 2011-04-19 07:22:02 UTC
-SET TIMESTAMP = 1303197722;
-INSERT INTO t2 ( f ) VALUES (1);
-SELECT * FROM t2;
-a	b	c	d	e	f
-2011-04-19 07:22:02	2011-04-19 07:22:02	2011-04-19 07:22:02	0000-00-00 00:00:00	0000-00-00 00:00:00	1
-# 2011-04-19 07:23:18 UTC
-SET TIMESTAMP = 1303197798;
-UPDATE t2 SET f = 2;
-SELECT * FROM t2;
-a	b	c	d	e	f
-2011-04-19 07:23:18	2011-04-19 07:23:18	2011-04-19 07:22:02	2011-04-19 07:23:18	2011-04-19 07:23:18	2
-DROP TABLE t2;
-#
-# Test of INSERT DELAYED ... SET ...
-#
-# 2011-04-19 08:02:40 UTC
-SET TIMESTAMP = 1303200160;
-CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
-INSERT DELAYED INTO t1 SET a = 1;
-FLUSH TABLE t1;
-SELECT * FROM t1;
-a	tmsp
-1	2011-04-19 08:02:40
-SELECT * FROM t1 WHERE tmsp = 0;
-a	tmsp
-INSERT DELAYED INTO t1 SET a = 2, tmsp = '1980-01-02 10:20:30';
-FLUSH TABLE t1;
-SELECT * FROM t1;
-a	tmsp
-1	2011-04-19 08:02:40
-2	1980-01-02 10:20:30
-DROP TABLE t1;
-#
-# Test of INSERT DELAYED ... VALUES ...
-#
-# 2011-04-19 08:04:01 UTC 
-SET TIMESTAMP = 1303200241;
-CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
-INSERT DELAYED INTO t1 ( a ) VALUES (1);
-FLUSH TABLE t1;
-SELECT * FROM t1;
-a	tmsp
-1	2011-04-19 08:04:01
-INSERT DELAYED INTO t1 VALUES (2, '1977-12-19 12:34:56');
-FLUSH TABLE t1;
-SELECT * FROM t1;
-a	tmsp
-1	2011-04-19 08:04:01
-2	1977-12-19 12:34:56
-DROP TABLE t1;
-# 2011-04-20 07:05:39 UTC
-SET TIMESTAMP = 1303283139;
-CREATE TABLE t1 (
-a TIMESTAMP DEFAULT "2010-10-11 12:34:56",
-b DATETIME DEFAULT "2010-10-11 12:34:56"
-);
-INSERT INTO t1          VALUES (NULL, NULL), (DEFAULT, DEFAULT);
-INSERT INTO t1 ( a, b ) VALUES (NULL, NULL), (DEFAULT, DEFAULT);
-SELECT * FROM t1;
-a	b
-2011-04-20 07:05:39	NULL
-2010-10-11 12:34:56	2010-10-11 12:34:56
-2011-04-20 07:05:39	NULL
-2010-10-11 12:34:56	2010-10-11 12:34:56
-DROP TABLE t1;
-CREATE TABLE t1 ( 
-a TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
-b DATETIME DEFAULT CURRENT_TIMESTAMP, 
-c INT
-);
-# 2011-04-20 09:53:41 UTC
-SET TIMESTAMP = 1303293221;
-INSERT INTO t1 VALUES (NULL, NULL, 1), (DEFAULT, DEFAULT, 2);
-INSERT INTO t1 ( a, b, c ) VALUES (NULL, NULL, 3), (DEFAULT, DEFAULT, 4);
-SELECT * FROM t1;
-a	b	c
-2011-04-20 09:53:41	NULL	1
-2011-04-20 09:53:41	2011-04-20 09:53:41	2
-2011-04-20 09:53:41	NULL	3
-2011-04-20 09:53:41	2011-04-20 09:53:41	4
-SET TIME_ZONE = "+03:00";
-SELECT * FROM t1;
-a	b	c
-2011-04-20 12:53:41	NULL	1
-2011-04-20 12:53:41	2011-04-20 09:53:41	2
-2011-04-20 12:53:41	NULL	3
-2011-04-20 12:53:41	2011-04-20 09:53:41	4
-SET TIME_ZONE = "+00:00";
-DELETE FROM t1;
-INSERT INTO t1 ( c ) VALUES (1);
-SELECT * FROM t1;
-a	b	c
-2011-04-20 09:53:41	2011-04-20 09:53:41	1
-# 2011-04-20 17:06:13 
-SET TIMESTAMP = 1303311973;
-UPDATE t1 t11, t1 t12 SET t11.c = 1;
-SELECT * FROM t1;
-a	b	c
-2011-04-20 09:53:41	2011-04-20 09:53:41	1
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
-SELECT * FROM t1;
-a	b	c
-2011-04-20 09:53:41	2011-04-20 09:53:41	2
-DROP TABLE t1;
-CREATE TABLE t1 (
-a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-b DATETIME ON UPDATE CURRENT_TIMESTAMP,
-c INT
-);
-# 2011-04-20 09:53:41 UTC
-SET TIMESTAMP = 1303293221;
-INSERT INTO t1 ( c ) VALUES ( 1 );
-SELECT * FROM t1;
-a	b	c
-0000-00-00 00:00:00	NULL	1
-UPDATE t1 SET c = 1;
-SELECT * FROM t1;
-a	b	c
-0000-00-00 00:00:00	NULL	1
-UPDATE t1 SET c = 2;
-SELECT * FROM t1;
-a	b	c
-2011-04-20 09:53:41	2011-04-20 09:53:41	2
-# 2011-04-20 15:06:13 UTC
-SET TIMESTAMP = 1303311973;
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
-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;
-SELECT * FROM t1;
-a	b	c
-2011-04-20 15:06:13	2011-04-20 15:06:13	3
-DROP TABLE t1;
-# 
-# Test of CREATE TABLE ... SELECT ...
-# 
-CREATE TABLE t1 (
-a TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-c TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-d DATETIME DEFAULT CURRENT_TIMESTAMP,
-e DATETIME ON UPDATE CURRENT_TIMESTAMP,
-f DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-);
-CREATE TABLE t2 SELECT a, b, c, d, e, f FROM t1;
-SHOW CREATE TABLE t2;
-Table	Create Table
-t2	CREATE TABLE `t2` (
-  `a` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
-  `b` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
-  `c` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
-  `d` datetime DEFAULT NULL,
-  `e` datetime DEFAULT NULL,
-  `f` datetime DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-DROP TABLE t1, t2;
-#
-# Test of ALTER TABLE, reordering columns.
-#
-CREATE TABLE t1 ( a TIMESTAMP, b INT );
-ALTER TABLE t1 MODIFY a TIMESTAMP AFTER b;
-SHOW CREATE TABLE t1;
-Table	Create Table
-t1	CREATE TABLE `t1` (
-  `b` int(11) DEFAULT NULL,
-  `a` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-DROP TABLE t1;
-CREATE TABLE t1 ( a INT, b TIMESTAMP, c TIMESTAMP NULL );
-ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
-SHOW CREATE TABLE t1;
-Table	Create Table
-t1	CREATE TABLE `t1` (
-  `b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  `a` int(11) DEFAULT NULL,
-  `c` timestamp NULL DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-DROP TABLE t1;
-CREATE TABLE t1 ( a INT, b TIMESTAMP NULL );
-ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
-SHOW CREATE TABLE t1;
-Table	Create Table
-t1	CREATE TABLE `t1` (
-  `b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  `a` int(11) DEFAULT NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-DROP TABLE t1;

=== added file 'mysql-test/t/function_defaults.test'
--- a/mysql-test/t/function_defaults.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/function_defaults.test	2011-05-11 13:05:53 +0000
@@ -0,0 +1,212 @@
+--echo #
+--echo # Worklog#5874:
+--echo #
+--echo #
+SET TIME_ZONE = "+00:00";
+
+CREATE TABLE t1 (
+  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  c TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+  d TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  e TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  f INT
+);
+
+--echo # 2011-04-19 07:22:02 UTC
+SET TIMESTAMP = 1303197722;
+
+INSERT INTO t1 ( f ) VALUES (1);
+SELECT * FROM t1;
+
+--echo # 2011-04-19 07:23:18 UTC
+SET TIMESTAMP = 1303197798;
+
+UPDATE t1 SET f = 2;
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Test of ON DUPLICATE KEY
+--echo #
+CREATE TABLE t1 ( a INT PRIMARY KEY, b INT, c TIMESTAMP );
+
+INSERT INTO t1 VALUES
+  (1, 0, '2001-01-01 01:01:01'),
+  (2, 0, '2002-02-02 02:02:02'),
+  (3, 0, '2003-03-03 03:03:03');
+SELECT * FROM t1;
+
+UPDATE t1 SET b = 2, c = c WHERE a = 2;
+SELECT * FROM t1;
+
+INSERT INTO t1 (a) VALUES (4);
+SELECT * FROM t1;
+
+UPDATE t1 SET c = '2004-04-04 04:04:04' WHERE a = 4;
+SELECT * FROM t1;
+
+INSERT INTO t1 (a) VALUES (3), (5) ON DUPLICATE KEY UPDATE b = 3, c = c;
+SELECT * FROM t1;
+
+INSERT INTO t1 (a, c) VALUES
+  (4, '2004-04-04 00:00:00'),
+  (6, '2006-06-06 06:06:06')
+ON DUPLICATE KEY UPDATE b = 4;
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Test of INSERT DELAYED ... SET ...
+--echo #
+
+--echo # 2011-04-19 08:02:40 UTC
+SET TIMESTAMP = 1303200160;
+
+CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
+
+INSERT DELAYED INTO t1 SET a = 1;
+FLUSH TABLE t1;
+
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE tmsp = 0;
+
+INSERT DELAYED INTO t1 SET a = 2, tmsp = '1980-01-02 10:20:30';
+FLUSH TABLE t1;
+
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Test of INSERT DELAYED ... VALUES ...
+--echo #
+
+--echo # 2011-04-19 08:04:01 UTC 
+SET TIMESTAMP = 1303200241;
+
+CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
+
+INSERT DELAYED INTO t1 ( a ) VALUES (1);
+FLUSH TABLE t1;
+SELECT * FROM t1;
+
+INSERT DELAYED INTO t1 VALUES (2, '1977-12-19 12:34:56');
+FLUSH TABLE t1;
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo # 2011-04-20 07:05:39 UTC
+SET TIMESTAMP = 1303283139;
+CREATE TABLE t1 (
+  a TIMESTAMP DEFAULT "2010-10-11 12:34:56",
+  b DATETIME DEFAULT "2010-10-11 12:34:56"
+);
+
+INSERT INTO t1          VALUES (NULL, NULL), (DEFAULT, DEFAULT);
+INSERT INTO t1 ( a, b ) VALUES (NULL, NULL), (DEFAULT, DEFAULT);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+CREATE TABLE t1 ( 
+  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
+  b DATETIME DEFAULT CURRENT_TIMESTAMP, 
+  c INT
+);
+
+--echo # 2011-04-20 09:53:41 UTC
+SET TIMESTAMP = 1303293221;
+
+INSERT INTO t1 VALUES (NULL, NULL, 1), (DEFAULT, DEFAULT, 2);
+INSERT INTO t1 ( a, b, c ) VALUES (NULL, NULL, 3), (DEFAULT, DEFAULT, 4);
+SELECT * FROM t1;
+
+SET TIME_ZONE = "+03:00";
+SELECT * FROM t1;
+SET TIME_ZONE = "+00:00";
+
+DELETE FROM t1;
+
+INSERT INTO t1 ( c ) VALUES (1);
+SELECT * FROM t1;
+
+--echo # 2011-04-20 17:06:13 
+SET TIMESTAMP = 1303311973;
+
+UPDATE t1 t11, t1 t12 SET t11.c = 1;
+SELECT * FROM t1;
+
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
+
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+  a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  b DATETIME ON UPDATE CURRENT_TIMESTAMP,
+  c INT
+);
+
+--echo # 2011-04-20 09:53:41 UTC
+SET TIMESTAMP = 1303293221;
+
+INSERT INTO t1 ( c ) VALUES ( 1 );
+SELECT * FROM t1;
+
+UPDATE t1 SET c = 1;
+SELECT * FROM t1;
+
+UPDATE t1 SET c = 2;
+SELECT * FROM t1;
+
+--echo # 2011-04-20 15:06:13 UTC
+SET TIMESTAMP = 1303311973;
+
+UPDATE t1 t11, t1 t12 SET t11.c = 2;
+SELECT * FROM t1;
+
+UPDATE t1 t11, t1 t12 SET t11.c = 3;
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo # 
+--echo # Test of CREATE TABLE ... SELECT ...
+--echo # 
+CREATE TABLE t1 (
+  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+  b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  c TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  d DATETIME DEFAULT CURRENT_TIMESTAMP,
+  e DATETIME ON UPDATE CURRENT_TIMESTAMP,
+  f DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+);
+
+CREATE TABLE t2 SELECT a, b, c, d, e, f FROM t1;
+
+SHOW CREATE TABLE t2;
+
+DROP TABLE t1, t2;
+
+--echo #
+--echo # Test of ALTER TABLE, reordering columns.
+--echo #
+CREATE TABLE t1 ( a TIMESTAMP, b INT );
+ALTER TABLE t1 MODIFY a TIMESTAMP AFTER b;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ( a INT, b TIMESTAMP, c TIMESTAMP NULL );
+ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ( a INT, b TIMESTAMP NULL );
+ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;

=== removed file 'mysql-test/t/wl5874.test'
--- a/mysql-test/t/wl5874.test	2011-05-10 14:18:34 +0000
+++ b/mysql-test/t/wl5874.test	1970-01-01 00:00:00 +0000
@@ -1,181 +0,0 @@
---echo #
---echo # Worklog#5874:
---echo #
---echo #
-SET TIME_ZONE = "+00:00";
-
-CREATE TABLE t2 (
-  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  b TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  c TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-  d TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  e TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  f INT
-);
-
---echo # 2011-04-19 07:22:02 UTC
-SET TIMESTAMP = 1303197722;
-
-INSERT INTO t2 ( f ) VALUES (1);
-SELECT * FROM t2;
-
---echo # 2011-04-19 07:23:18 UTC
-SET TIMESTAMP = 1303197798;
-
-UPDATE t2 SET f = 2;
-SELECT * FROM t2;
-
-DROP TABLE t2;
-
---echo #
---echo # Test of INSERT DELAYED ... SET ...
---echo #
-
---echo # 2011-04-19 08:02:40 UTC
-SET TIMESTAMP = 1303200160;
-
-CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
-
-INSERT DELAYED INTO t1 SET a = 1;
-FLUSH TABLE t1;
-
-SELECT * FROM t1;
-SELECT * FROM t1 WHERE tmsp = 0;
-
-INSERT DELAYED INTO t1 SET a = 2, tmsp = '1980-01-02 10:20:30';
-FLUSH TABLE t1;
-
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
---echo #
---echo # Test of INSERT DELAYED ... VALUES ...
---echo #
-
---echo # 2011-04-19 08:04:01 UTC 
-SET TIMESTAMP = 1303200241;
-
-CREATE TABLE t1 ( a INT, tmsp TIMESTAMP );
-
-INSERT DELAYED INTO t1 ( a ) VALUES (1);
-FLUSH TABLE t1;
-SELECT * FROM t1;
-
-INSERT DELAYED INTO t1 VALUES (2, '1977-12-19 12:34:56');
-FLUSH TABLE t1;
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
---echo # 2011-04-20 07:05:39 UTC
-SET TIMESTAMP = 1303283139;
-CREATE TABLE t1 (
-  a TIMESTAMP DEFAULT "2010-10-11 12:34:56",
-  b DATETIME DEFAULT "2010-10-11 12:34:56"
-);
-
-INSERT INTO t1          VALUES (NULL, NULL), (DEFAULT, DEFAULT);
-INSERT INTO t1 ( a, b ) VALUES (NULL, NULL), (DEFAULT, DEFAULT);
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
-CREATE TABLE t1 ( 
-  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 
-  b DATETIME DEFAULT CURRENT_TIMESTAMP, 
-  c INT
-);
-
---echo # 2011-04-20 09:53:41 UTC
-SET TIMESTAMP = 1303293221;
-
-INSERT INTO t1 VALUES (NULL, NULL, 1), (DEFAULT, DEFAULT, 2);
-INSERT INTO t1 ( a, b, c ) VALUES (NULL, NULL, 3), (DEFAULT, DEFAULT, 4);
-SELECT * FROM t1;
-
-SET TIME_ZONE = "+03:00";
-SELECT * FROM t1;
-SET TIME_ZONE = "+00:00";
-
-DELETE FROM t1;
-
-INSERT INTO t1 ( c ) VALUES (1);
-SELECT * FROM t1;
-
---echo # 2011-04-20 17:06:13 
-SET TIMESTAMP = 1303311973;
-
-UPDATE t1 t11, t1 t12 SET t11.c = 1;
-SELECT * FROM t1;
-
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
-
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
-CREATE TABLE t1 (
-  a TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  b DATETIME ON UPDATE CURRENT_TIMESTAMP,
-  c INT
-);
-
---echo # 2011-04-20 09:53:41 UTC
-SET TIMESTAMP = 1303293221;
-
-INSERT INTO t1 ( c ) VALUES ( 1 );
-SELECT * FROM t1;
-
-UPDATE t1 SET c = 1;
-SELECT * FROM t1;
-
-UPDATE t1 SET c = 2;
-SELECT * FROM t1;
-
---echo # 2011-04-20 15:06:13 UTC
-SET TIMESTAMP = 1303311973;
-
-UPDATE t1 t11, t1 t12 SET t11.c = 2;
-SELECT * FROM t1;
-
-UPDATE t1 t11, t1 t12 SET t11.c = 3;
-SELECT * FROM t1;
-
-DROP TABLE t1;
-
---echo # 
---echo # Test of CREATE TABLE ... SELECT ...
---echo # 
-CREATE TABLE t1 (
-  a TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-  b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  c TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  d DATETIME DEFAULT CURRENT_TIMESTAMP,
-  e DATETIME ON UPDATE CURRENT_TIMESTAMP,
-  f DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-);
-
-CREATE TABLE t2 SELECT a, b, c, d, e, f FROM t1;
-
-SHOW CREATE TABLE t2;
-
-DROP TABLE t1, t2;
-
---echo #
---echo # Test of ALTER TABLE, reordering columns.
---echo #
-CREATE TABLE t1 ( a TIMESTAMP, b INT );
-ALTER TABLE t1 MODIFY a TIMESTAMP AFTER b;
-SHOW CREATE TABLE t1;
-DROP TABLE t1;
-
-CREATE TABLE t1 ( a INT, b TIMESTAMP, c TIMESTAMP NULL );
-ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
-SHOW CREATE TABLE t1;
-DROP TABLE t1;
-
-CREATE TABLE t1 ( a INT, b TIMESTAMP NULL );
-ALTER TABLE t1 MODIFY b TIMESTAMP FIRST;
-SHOW CREATE TABLE t1;
-DROP TABLE t1;

=== modified file 'new_files.txt'
--- a/new_files.txt	2011-05-10 14:18:34 +0000
+++ b/new_files.txt	2011-05-11 13:05:53 +0000
@@ -5,5 +5,5 @@ unittest/gunit/item_func_now_local-t.cc
 unittest/gunit/mock_field_timestamp.h
 unittest/gunit/servertest.cc
 unittest/gunit/servertest.h
-mysql-test/t/wl5874.test
-mysql-test/r/wl5874.result
+mysql-test/t/function_defaults.test
+mysql-test/r/function_defaults.result

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2011-05-10 14:18:34 +0000
+++ b/sql/sql_class.cc	2011-05-11 13:05:53 +0000
@@ -3885,99 +3885,86 @@ void xid_cache_delete(XID_STATE *xid_sta
 
 
 /**
-   @param table The modified table.
-   @param modified_fields List of columns that are modified by the DML
+   For a certain data changing operation, allocates and calculates a bitmap of
+   which columns will receive a default value resulting from a function.
+
+   @param table The table whose data changes as a result of performing the
+   operation. It is assumed that all changed fields belong to this table.
+
+   @param changed_fields List of columns that are modified by the data change
    statement. This may be NULL, meaning all columns are modified.
 
-   The table's MEM_ROOT is used for allocating the bitmap.
+   @param operation The data change operation to be carried out.
+
+   @retval NULL Memory allocation error.
  */
 MY_BITMAP *get_default_assigned_columns(const TABLE &table,
-                                        List<Item> *modified_fields,
+                                        List<Item> *changed_fields,
                                         const COPY_INFO &operation)
 {
   DBUG_ENTER("get_default_assigned_columns");
-  
+
   /* We cannot trust table.s->column_bitmap_size during multi-table UPDATE. */
   const uint column_bitmap_size= bitmap_buffer_size(table.s->fields);
   DBUG_ASSERT(column_bitmap_size > 0);
 
-  /* 
-     This lets us handle INSERT DELAYED, where the thread performing the data
-     change is not the thread executing this function.  todo: add unit test
-     for this
-  */
-  MEM_ROOT *mem_root= table.in_use->mem_root; //operation.get_mem_root();
-
-  DBUG_PRINT("wl5874_important", ("table @ %p mem_root %p", &table, mem_root));
-
-  my_bitmap_map *columns_bits=
-//    (my_bitmap_map*)alloc_root(mem_root, column_bitmap_size);
-    static_cast<my_bitmap_map*>(my_malloc(column_bitmap_size, MYF(0)));
-  if (columns_bits == NULL)
-    DBUG_RETURN(NULL);
-
-//  MY_BITMAP *columns= (MY_BITMAP*)alloc_root(mem_root, sizeof(MY_BITMAP));
   MY_BITMAP *columns=
     static_cast<MY_BITMAP*>(my_malloc(sizeof(MY_BITMAP), MYF(0)));
   
   if (columns == NULL)
     DBUG_RETURN(NULL);
   
-  DBUG_ASSERT((void*)columns != (void*)columns_bits);
+  if (bitmap_init(columns, NULL, table.s->fields, FALSE) != 0)
+    DBUG_RETURN(NULL);
 
-  DBUG_ASSERT(table.s->fields > 0);
-  bitmap_init(columns, columns_bits, table.s->fields, FALSE);
+  if (changed_fields == NULL)
+    /* All columns assigned; No defaults set, functions or otherwise. */
+    DBUG_RETURN(columns);
 
-  /* Find columns with function default on insert. */
+  /* Find columns with function default on insert or update. */
   for (uint i= 0; i < table.s->fields; ++i)
   {
     Field *current_field= table.field[i];
-    DBUG_PRINT("wl5874_red", ("Field %s @ %p", 
-                              current_field->field_name,
-                              current_field));
+    const char *function_default_status = "";
     if (operation.get_operation_type() == COPY_INFO::INSERT_OPERATION &&
         current_field->has_insert_default_function())
     {
-      DBUG_PRINT("wl5874_red", ("Field %s has INSERT default function", 
-                                current_field->field_name));
+      function_default_status = "Has INSERT default function";
       bitmap_set_bit(columns, current_field->field_index);
     }
     if (operation.get_operation_type() == COPY_INFO::UPDATE_OPERATION && 
         current_field->has_update_default_function())
     {
-      DBUG_PRINT("wl5874_red", ("Field %s has UPDATE default function",
-                         current_field->field_name));
+      function_default_status = "Has UPDATE default function";
       bitmap_set_bit(columns, current_field->field_index);
     }
+    DBUG_PRINT("wl5874_red", ("Field %s @ %p %s", 
+                              current_field->field_name,
+                              current_field,
+                              function_default_status));
   }
 
-  /* Remove explicitly assigned columns. */
-  if (modified_fields != NULL)
+  /* Remove explicitly assigned columns from the bitmap. */
+  List_iterator<Item> lvalue_it(*changed_fields);
+  Item *lvalue_item;
+  while ((lvalue_item= lvalue_it++) != NULL)
   {
-    List_iterator<Item> lvalue_it(*modified_fields);
-    Item *lvalue_item;
-    while ((lvalue_item= lvalue_it++) != NULL)
+    if (lvalue_item->type() == Item::FIELD_ITEM)
     {
-      if (lvalue_item->type() == Item::FIELD_ITEM)
+      Field *lvalue= static_cast<Item_field*>(lvalue_item)->field;
+      DBUG_ASSERT(lvalue->table == &table);
+      
+      if (lvalue != NULL)
       {
-        Field *lvalue= static_cast<Item_field*>(lvalue_item)->field;
-        if (lvalue != NULL)
-        {
-          DBUG_PRINT("wl5874_red",
-                     ("Field %s is assigned", lvalue->field_name));
-          bitmap_clear_bit(columns, lvalue->field_index);
-        }
-        else
-          DBUG_PRINT("wl5874_red", ("Item %s is not resolved!", 
-                                    lvalue_item->name));
+        DBUG_PRINT("wl5874_red",
+                   ("Field %s is assigned", lvalue->field_name));
+        bitmap_clear_bit(columns, lvalue->field_index);
       }
+      else
+        DBUG_PRINT("wl5874_red", ("Item %s is not resolved!", 
+                                  lvalue_item->name));
     }
   }
-  else
-    /*
-      All columns assigned; there can be no defaults, functions or otherwise.
-    */
-    bitmap_clear_all(columns);
   
   DBUG_RETURN(columns);
 }

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2011-05-10 14:18:34 +0000
+++ b/sql/sql_class.h	2011-05-11 13:05:53 +0000
@@ -193,11 +193,27 @@ MY_BITMAP *get_default_assigned_columns(
 class COPY_INFO
 {
 public:
+  class Statistics
+  {
+  public:
+    Statistics() : 
+      records(0), deleted(0), updated(0), copied(0), error_count(0), touched(0)
+      {}
+
+    ha_rows records; /**< Number of processed records */
+    ha_rows deleted; /**< Number of deleted records */
+    ha_rows updated; /**< Number of updated records */
+    ha_rows copied;  /**< Number of copied records */
+    ha_rows error_count;
+    ha_rows touched; /* Number of touched records */
+  };
+
   enum operation_type { INSERT_OPERATION, UPDATE_OPERATION };
+
 private:
   /**
      Describes the data change operation that this object represents.
-   */
+  */
   operation_type m_optype;
   List<Item> *m_inserted_fields;
   /* const */ bool m_inserts_defaults_only;
@@ -205,12 +221,7 @@ private:
   MY_BITMAP *m_function_default_update_columns;
 
 public:
-  ha_rows records; /**< Number of processed records */
-  ha_rows deleted; /**< Number of deleted records */
-  ha_rows updated; /**< Number of updated records */
-  ha_rows copied;  /**< Number of copied records */
-  ha_rows error_count;
-  ha_rows touched; /* Number of touched records */
+  Statistics stats;
   enum enum_duplicates handle_duplicates;
   int escape_char, last_errno;
   bool ignore;
@@ -220,11 +231,11 @@ public:
   /* for VIEW ... WITH CHECK OPTION */
   TABLE_LIST *view;
   bool is_select_create;
-
+  
   /**
      Initializes this operation as an INSERT that can spawn an UPDATE
      operation.
-
+     
      @table_list The parser object representing the table to be modified.
      @inserted_fields The values to be inserted for the columns. May be NULL,
      which is interpreted as all columns in the order they appear in the table
@@ -237,7 +248,7 @@ public:
      INSERT operation caused a duplicate key error.
 
      @duplicate_handling The policy for handling duplicates.
-   */
+  */
   COPY_INFO(operation_type optype,
             TABLE_LIST *table_list,
             List<Item> *inserted_fields,
@@ -250,8 +261,6 @@ public:
     m_inserts_defaults_only(false),
     m_function_default_insert_columns(NULL),
     m_function_default_update_columns(NULL),
-    records(0), deleted(0), updated(0), copied(0), error_count(0), 
-    touched(0),
     handle_duplicates(duplicate_handling),
     escape_char(0), last_errno(0),
     ignore(ignore_check_option_errors),
@@ -262,10 +271,10 @@ public:
     {
       DBUG_ASSERT(optype == INSERT_OPERATION);
     }
-
-    /**
+  
+  /**
      Initializes this data change operation as an INSERT.
-
+     
      @param all_rows. A list of rows from the INSERT INTO ... VALUES row[,
      row] construct. MySQL supports the syntax 
      
@@ -281,17 +290,16 @@ public:
      
      is not allowed. Hence we know that the number of elements in all rows
      is the same.
-    */
+  */
   COPY_INFO(operation_type optype,
-            List<Item> &inserted_fields,
-            List<List<Item> > &all_rows) : 
+            List<Item> *inserted_fields,
+            List<List<Item> > *all_rows) : 
     m_optype(optype),
-    m_inserted_fields(&inserted_fields),
-    m_inserts_defaults_only(all_rows.elements > 0 &&
-                           all_rows.head()->elements == 0),
+    m_inserted_fields(inserted_fields),
+    m_inserts_defaults_only(all_rows->elements > 0 &&
+                            all_rows->head()->elements == 0),
     m_function_default_insert_columns(NULL),
     m_function_default_update_columns(NULL),
-    records(0), deleted(0), updated(0), copied(0), error_count(0), touched(0),
     handle_duplicates(DUP_ERROR), escape_char(0), last_errno(0), ignore(false),
     update_fields(NULL), update_values(NULL), view(NULL),
     is_select_create(false)
@@ -300,16 +308,16 @@ public:
     }
 
 
-    /**
-       Creates a data change operation where the values to be inserted are not
-       known at the time of initialization. For instance, the may be read from
-       a file.
-
-       @param optype              The data change opreation type.
-       @param ignore_duplicates   Whether duplicate rows are ignored.
-       @param duplicates_handling How to handle duplicates.
-       @param escape_character    The escape character.
-    */
+  /**
+     Creates a data change operation where the values to be inserted are not
+     known at the time of initialization. For instance, they may be read from
+     a file.
+     
+     @param optype              The data change opreation type.
+     @param ignore_duplicates   Whether duplicate rows are ignored.
+     @param duplicates_handling How to handle duplicates.
+     @param escape_character    The escape character.
+  */
   COPY_INFO(operation_type optype, bool ignore_duplicates,
             enum_duplicates duplicates_handling, int escape_character) : 
     m_optype(optype),
@@ -317,7 +325,6 @@ public:
     m_inserts_defaults_only(false),
     m_function_default_insert_columns(NULL),
     m_function_default_update_columns(NULL),
-    records(0), deleted(0), updated(0), copied(0), error_count(0), touched(0),
     handle_duplicates(duplicates_handling), escape_char(escape_character),
     last_errno(0), ignore(ignore_duplicates),
     update_fields(NULL), update_values(NULL), view(NULL),
@@ -326,28 +333,64 @@ public:
       DBUG_ASSERT(optype == INSERT_OPERATION);
     }
 
-    /**
-       Initializes this data change operation as an UPDATE.
-       @param fields The column objects that are to be updated.
-       @param values The values to be assigned to the fields.
-    */
+  /**
+     Initializes a new data change operation as an UPDATE.
+     @param fields The column objects that are to be updated.
+     @param values The values to be assigned to the fields.
+  */
   COPY_INFO(operation_type optype, List<Item> &fields, List<Item> &values) :
     m_optype(optype),
     m_inserted_fields(NULL),
     m_inserts_defaults_only(false),
     m_function_default_insert_columns(NULL),
     m_function_default_update_columns(NULL),
-    records(0), deleted(0), updated(0), copied(0), error_count(0), touched(0),
     handle_duplicates(DUP_ERROR), escape_char(0), last_errno(0), ignore(false),
     update_fields(&fields), update_values(&values), view(NULL),
-    is_select_create(false) {
+    is_select_create(false)
+    {
+      DBUG_ASSERT(optype == UPDATE_OPERATION);
+    }
+
+  /**
+     Constructs an UPDATE operation to handle the @c UPDATE part of an INSERT
+     ON DUPLICATE KEY UPDATE operation.
+
+     @param optype The new operation type, which must be UPDATE_OPERATION.
+
+     @param A COPY_INFO describing an INSERT ON DUPLICATE KEY UPDATE
+     operation.
+  */
+  COPY_INFO(operation_type optype, const COPY_INFO &insert_update) :
+    m_optype(optype),
+    m_inserted_fields(NULL),
+    m_inserts_defaults_only(false),    
+    m_function_default_insert_columns(NULL),
+    m_function_default_update_columns(NULL),
+    stats(insert_update.stats),
+    handle_duplicates(DUP_ERROR), escape_char(insert_update.escape_char),
+    last_errno(insert_update.last_errno), ignore(insert_update.ignore),
+    update_fields(insert_update.update_fields),
+    update_values(insert_update.update_values), view(NULL),
+    is_select_create(false)
+    {
       DBUG_ASSERT(optype == UPDATE_OPERATION);
+      DBUG_ASSERT(update_fields != NULL);
+      DBUG_ASSERT(update_values != NULL);
     }
 
   void set_operation_type(operation_type optype) { m_optype = optype; }
   operation_type get_operation_type() const { return m_optype; }
 
-  List<Item> *get_inserted_fields() { return m_inserted_fields; }
+  /**
+     Removes any references to statement-local data.
+   */
+  void detach_from_statement()
+  {
+    m_inserted_fields= NULL;
+    update_fields= NULL;
+    update_values= NULL;
+  }
+
 
   bool is_full_row()
   {
@@ -389,9 +432,15 @@ public:
 
   ~COPY_INFO() {
     DBUG_PRINT("wl5874_important", ("~COPY_INFO"));
-/*    delete m_function_default_insert_columns;
-    delete m_function_default_update_columns;
-*/
+
+    if (m_function_default_insert_columns != NULL)
+      bitmap_free(m_function_default_insert_columns);
+
+    if (m_function_default_update_columns != NULL)
+      bitmap_free(m_function_default_update_columns);
+
+    my_free(m_function_default_insert_columns);
+    my_free(m_function_default_update_columns);
   }
 
 };

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2011-05-10 14:18:34 +0000
+++ b/sql/sql_insert.cc	2011-05-11 13:05:53 +0000
@@ -631,7 +631,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   uint value_count;
   ulong counter = 1;
   ulonglong id;
-  COPY_INFO info(COPY_INFO::INSERT_OPERATION, fields, values_list);
+  COPY_INFO info(COPY_INFO::INSERT_OPERATION, &fields, &values_list);
   TABLE *table= 0;
   List_iterator_fast<List_item> its(values_list);
   List_item *values;
@@ -825,7 +825,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       {
 	if (values_list.elements != 1 && ! thd->is_error())
 	{
-	  info.records++;
+	  info.stats.records++;
 	  continue;
 	}
 	/*
@@ -865,7 +865,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       {
 	if (values_list.elements != 1 && ! thd->is_error())
 	{
-	  info.records++;
+	  info.stats.records++;
 	  continue;
 	}
 	error=1;
@@ -913,7 +913,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   {
     if (!error)
     {
-      info.copied=values_list.elements;
+      info.stats.copied=values_list.elements;
       end_delayed_insert(thd);
     }
   }
@@ -936,7 +936,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
     transactional_table= table->file->has_transactions();
 
-    if ((changed= (info.copied || info.deleted || info.updated)))
+    if ((changed= (info.stats.copied || info.stats.deleted || info.stats.updated)))
     {
       /*
         Invalidate the table in the query cache if something changed.
@@ -1028,7 +1028,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
     thd->first_successful_insert_id_in_cur_stmt :
     (thd->arg_of_last_insert_id_function ?
      thd->first_successful_insert_id_in_prev_stmt :
-     ((table->next_number_field && info.copied) ?
+     ((table->next_number_field && info.stats.copied) ?
      table->next_number_field->val_int() : 0));
   table->next_number_field=0;
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -1042,26 +1042,26 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) ||
 				    !thd->cuted_fields))
   {
-    my_ok(thd, info.copied + info.deleted +
+    my_ok(thd, info.stats.copied + info.stats.deleted +
                ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
-                info.touched : info.updated),
+                info.stats.touched : info.stats.updated),
           id);
   }
   else
   {
     char buff[160];
     ha_rows updated=((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
-                     info.touched : info.updated);
+                     info.stats.touched : info.stats.updated);
     if (ignore)
-      sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
+      sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.stats.records,
 	      (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 :
-	      (ulong) (info.records - info.copied),
+	      (ulong) (info.stats.records - info.stats.copied),
               (ulong) thd->warning_info->statement_warn_count());
     else
-      sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
-	      (ulong) (info.deleted + updated),
+      sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.stats.records,
+	      (ulong) (info.stats.deleted + updated),
               (ulong) thd->warning_info->statement_warn_count());
-    ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
+    ::my_ok(thd, info.stats.copied + info.stats.deleted + updated, id, buff);
   }
   thd->abort_on_warning= 0;
   DBUG_RETURN(FALSE);
@@ -1470,7 +1470,7 @@ int write_record(THD *thd, TABLE *table,
   ulonglong insert_id_for_cur_row= 0;
   DBUG_ENTER("write_record");
 
-  info->records++;
+  info->stats.records++;
   save_read_set=  table->read_set;
   save_write_set= table->write_set;
 
@@ -1559,8 +1559,7 @@ int write_record(THD *thd, TABLE *table,
         /*
           This is very elegant, but perhaps a tad inefficient?
          */
-        COPY_INFO update(*info);
-        update.set_operation_type(COPY_INFO::UPDATE_OPERATION);
+        COPY_INFO update(COPY_INFO::UPDATE_OPERATION, *info);
         int res= 0;
         /*
           We don't check for other UNIQUE keys - the first row
@@ -1570,7 +1569,8 @@ int write_record(THD *thd, TABLE *table,
 	DBUG_ASSERT(table->insert_values != NULL);
         store_record(table,insert_values);
         restore_record(table,record[1]);
-        DBUG_PRINT("wl5874_red", ("update_fields %i", info->update_fields->elements));
+        DBUG_PRINT("wl5874_red", ("# update_fields %i",
+                                  info->update_fields->elements));
         DBUG_ASSERT(info->update_fields->elements ==
                     info->update_values->elements);
         if (fill_record_n_invoke_before_triggers(thd, *info->update_fields,
@@ -1592,7 +1592,7 @@ int write_record(THD *thd, TABLE *table,
         if (table->next_number_field)
           table->file->adjust_next_insert_id_after_explicit_value(
             table->next_number_field->val_int());
-        info->touched++;
+        info->stats.touched++;
         if (!records_are_comparable(table) || compare_records(table))
         {
           DBUG_PRINT("wl5874_red", ("compare records is true"));
@@ -1611,7 +1611,7 @@ int write_record(THD *thd, TABLE *table,
           }
 
           if (error != HA_ERR_RECORD_IS_THE_SAME)
-            info->updated++;
+            info->stats.updated++;
           else
             error= 0;
           /*
@@ -1625,13 +1625,13 @@ int write_record(THD *thd, TABLE *table,
           trg_error= (table->triggers &&
                       table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                                         TRG_ACTION_AFTER, TRUE));
-          info->copied++;
+          info->stats.copied++;
         }
 
         if (table->next_number_field)
           table->file->adjust_next_insert_id_after_explicit_value(
             table->next_number_field->val_int());
-        info->touched++;
+        info->stats.touched++;
 
         goto ok_or_after_trg_err;
       }
@@ -1664,7 +1664,7 @@ int write_record(THD *thd, TABLE *table,
               error != HA_ERR_RECORD_IS_THE_SAME)
             goto err;
           if (error != HA_ERR_RECORD_IS_THE_SAME)
-            info->deleted++;
+            info->stats.deleted++;
           else
             error= 0;
           thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
@@ -1682,7 +1682,7 @@ int write_record(THD *thd, TABLE *table,
             goto before_trg_err;
           if ((error=table->file->ha_delete_row(table->record[1])))
             goto err;
-          info->deleted++;
+          info->stats.deleted++;
           if (!table->file->has_transactions())
             thd->transaction.stmt.modified_non_trans_table= TRUE;
           if (table->triggers &&
@@ -1732,7 +1732,7 @@ int write_record(THD *thd, TABLE *table,
   }
 
 after_trg_n_copied_inc:
-  info->copied++;
+  info->stats.copied++;
   thd->record_first_successful_insert_id_in_cur_stmt(table->file->insert_id_for_cur_row);
   trg_error= (table->triggers &&
               table->triggers->process_triggers(thd, TRG_EVENT_INSERT,
@@ -1924,7 +1924,7 @@ public:
   }
   ~Delayed_insert()
   {
-    DBUG_PRINT("wl5874_important", ("~Delayed_insert"));
+    DBUG_ENTER("~Delayed_insert");
     /* The following is not really needed, but just for safety */
     delayed_row *row;
     while ((row=rows.get()))
@@ -1945,6 +1945,7 @@ public:
     delayed_insert_threads--;
     mysql_mutex_unlock(&LOCK_thread_count);
     mysql_cond_broadcast(&COND_thread_count); /* Tell main we are ready */
+    DBUG_VOID_RETURN;
   }
 
   /* The following is for checking when we can delete ourselves */
@@ -3030,7 +3031,7 @@ bool Delayed_insert::handle_inserts(void
     thd.clear_error(); // reset error for binlog
     if (write_record(&thd, table, &info))
     {
-      info.error_count++;				// Ignore errors
+      info.stats.error_count++;				// Ignore errors
       thread_safe_increment(delayed_insert_errors,&LOCK_delayed_status);
       row->log_query = 0;
     }
@@ -3558,7 +3559,7 @@ bool select_insert::send_eof()
   table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
   table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
 
-  changed= (info.copied || info.deleted || info.updated);
+  changed= (info.stats.copied || info.stats.deleted || info.stats.updated);
   if (changed)
   {
     /*
@@ -3605,21 +3606,21 @@ bool select_insert::send_eof()
   }
   char buff[160];
   if (info.ignore)
-    sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
-	    (ulong) (info.records - info.copied),
+    sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.stats.records,
+	    (ulong) (info.stats.records - info.stats.copied),
             (ulong) thd->warning_info->statement_warn_count());
   else
-    sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
-	    (ulong) (info.deleted+info.updated),
+    sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.stats.records,
+	    (ulong) (info.stats.deleted+info.stats.updated),
             (ulong) thd->warning_info->statement_warn_count());
-  row_count= info.copied + info.deleted +
+  row_count= info.stats.copied + info.stats.deleted +
              ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
-              info.touched : info.updated);
+              info.stats.touched : info.stats.updated);
   id= (thd->first_successful_insert_id_in_cur_stmt > 0) ?
     thd->first_successful_insert_id_in_cur_stmt :
     (thd->arg_of_last_insert_id_function ?
      thd->first_successful_insert_id_in_prev_stmt :
-     (info.copied ? autoinc_value_of_last_inserted_row : 0));
+     (info.stats.copied ? autoinc_value_of_last_inserted_row : 0));
   ::my_ok(thd, row_count, id, buff);
   DBUG_RETURN(0);
 }
@@ -3657,7 +3658,7 @@ void select_insert::abort_result_set() {
       If table creation failed, the number of rows modified will also be
       zero, so no check for that is made.
     */
-    changed= (info.copied || info.deleted || info.updated);
+    changed= (info.stats.copied || info.stats.deleted || info.stats.updated);
     transactional_table= table->file->has_transactions();
     if (thd->transaction.stmt.modified_non_trans_table)
     {

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2011-05-10 14:18:34 +0000
+++ b/sql/sql_load.cc	2011-05-11 13:05:53 +0000
@@ -585,8 +585,8 @@ int mysql_load(THD *thd,sql_exchange *ex
     error= -1;				// Error on read
     goto err;
   }
-  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
-	  (ulong) (info.records - info.copied),
+  sprintf(name, ER(ER_LOAD_INFO), (ulong) info.stats.records, (ulong) info.stats.deleted,
+	  (ulong) (info.stats.records - info.stats.copied),
           (ulong) thd->warning_info->statement_warn_count());
 
   if (thd->transaction.stmt.modified_non_trans_table)
@@ -636,9 +636,9 @@ int mysql_load(THD *thd,sql_exchange *ex
 #endif /*!EMBEDDED_LIBRARY*/
 
   /* ok to client sent only after binlog write and engine commit */
-  my_ok(thd, info.copied + info.deleted, 0L, name);
+  my_ok(thd, info.stats.copied + info.stats.deleted, 0L, name);
 err:
-  DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
+  DBUG_ASSERT(transactional_table || !(info.stats.copied || info.stats.deleted) ||
               thd->transaction.stmt.modified_non_trans_table);
   table->file->ha_release_auto_increment();
   table->auto_increment_field_not_null= FALSE;

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2011-05-10 14:18:34 +0000
+++ b/sql/table.cc	2011-05-11 13:05:53 +0000
@@ -5570,13 +5570,6 @@ bool TABLE::set_function_defaults(COPY_I
   
   const MY_BITMAP *used_defaults= operation.get_function_default_columns(*this);
 
-  DBUG_PRINT("wl5874_important", ("current_thd := %p mem_root %p in_use %p this %p",
-                                  current_thd,
-                                  current_thd->mem_root,
-                                  in_use,
-                                  this
-                                  ));
-
   if (used_defaults == NULL)
   {
     DBUG_PRINT("wl5874", ("error"));

=== modified file 'unittest/gunit/copy_info-t.cc'
--- a/unittest/gunit/copy_info-t.cc	2011-05-10 14:18:34 +0000
+++ b/unittest/gunit/copy_info-t.cc	2011-05-11 13:05:53 +0000
@@ -37,14 +37,51 @@ TABLE *make_table(Field **columns, int n
   return table;
 }
 
+TEST_F(ServerTest, constructors)
+{
+  TABLE_LIST *table_list= NULL;
+  COPY_INFO insert_cum_update(COPY_INFO::INSERT_OPERATION,
+                              table_list,
+                              reinterpret_cast<List<Item>*>(1),
+                              reinterpret_cast<List<Item>*>(2),
+                              reinterpret_cast<List<Item>*>(3),
+                              DUP_UPDATE,
+                              true);
+                              
+  EXPECT_EQ(0U, insert_cum_update.stats.records);
+  EXPECT_EQ(0U, insert_cum_update.stats.deleted);
+  EXPECT_EQ(0U, insert_cum_update.stats.updated);
+  EXPECT_EQ(0U, insert_cum_update.stats.copied);
+  EXPECT_EQ(0U, insert_cum_update.stats.error_count);
+  EXPECT_EQ(0U, insert_cum_update.stats.touched);
+
+  insert_cum_update.stats.records= 1;
+  insert_cum_update.stats.deleted= 2;
+  insert_cum_update.stats.updated= 3;
+  insert_cum_update.stats.copied= 4;
+  insert_cum_update.stats.error_count= 5;
+  insert_cum_update.stats.touched= 6;
+
+  COPY_INFO on_duplicate_update(COPY_INFO::UPDATE_OPERATION,
+                                insert_cum_update);
+
+  EXPECT_EQ(1U, on_duplicate_update.stats.records);
+  EXPECT_EQ(2U, on_duplicate_update.stats.deleted);
+  EXPECT_EQ(3U, on_duplicate_update.stats.updated);
+  EXPECT_EQ(4U, on_duplicate_update.stats.copied);
+  EXPECT_EQ(5U, on_duplicate_update.stats.error_count);
+  EXPECT_EQ(6U, on_duplicate_update.stats.touched);
+                              
+}
+
 TEST_F(ServerTest, determine_default_assigned_columns_NULL)
 {
   Field_string a(NULL, 0, NULL, 0, Field::NONE, "a", &my_charset_latin1);
   Field_string b(NULL, 0, NULL, 0, Field::NONE, "b", &my_charset_latin1);
   Field *fields[2] = { &a, &b };
   TABLE *table= make_table(fields, 2);
-  COPY_INFO dml_op(COPY_INFO::INSERT_OPERATION, NULL, NULL, NULL, NULL, DUP_ERROR,
-                   false);
+  List<List<Item> > all_rows;
+  COPY_INFO dml_op(COPY_INFO::INSERT_OPERATION, NULL, &all_rows);
   MY_BITMAP *cols= 
     get_default_assigned_columns(*table, NULL, dml_op);
   EXPECT_TRUE(bitmap_is_clear_all(cols));
@@ -68,7 +105,7 @@ TEST_F(ServerTest, determine_default_ass
   List<Item> insert_fields;
   insert_fields.push_front(new Item_field(&a));
 
-  COPY_INFO dml_op(COPY_INFO::INSERT_OPERATION, NULL, NULL, NULL, NULL, DUP_ERROR,
+  COPY_INFO dml_op(COPY_INFO::INSERT_OPERATION, NULL, NULL, NULL, NULL, DUP_UPDATE,
                    false);
 
   // This must be handled


Attachment: [text/bzr-bundle] bzr/martin.hansson@oracle.com-20110511130553-a5ocq72eg25l0t6e.bundle
Thread
bzr push into mysql-trunk branch (martin.hansson:3368 to 3369) WL#5874Martin Hansson11 May