#At file:///data0/martin/bzrroot/bug11746628/t-enginestuff/ based on revid:tor.didriksen@stripped
3318 Martin Hansson 2011-03-24
Preliminary refactoring in order to fix Bug 11746628 -
27645: DATETIME FIELD DOES NOT ACCEPT DEFAULT NOW()
This patch removes all references to the members
TABLE::timestamp_field and TABLE::timestamp_field_type from
the handler API, as these are subject to removal in the fix
for the bug. Instead a new interface
TABLE::[begin|end][insert|update]() has been introduced. The
new member functions are called from the handler class as
opposed to copy-pasting the code in all handler subclasses,
as was the case previously.
added:
unittest/gunit/table-t.cc
modified:
sql/field.h
sql/ha_ndbcluster.cc
sql/ha_partition.cc
sql/handler.cc
sql/table.cc
sql/table.h
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
=== modified file 'sql/field.h'
--- a/sql/field.h 2011-03-22 11:44:40 +0000
+++ b/sql/field.h 2011-03-24 10:23:22 +0000
@@ -21,6 +21,7 @@
#include "sql_string.h" /* String */
#include "my_decimal.h" /* my_decimal */
#include "sql_error.h" /* MYSQL_ERROR */
+#include "mysql_version.h" /* FRM_VER */
#define DATETIME_DEC 6
@@ -1398,7 +1399,7 @@ public:
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 0; }
- void set_time();
+ virtual void set_time();
virtual void set_default()
{
if (table->timestamp_field == this &&
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2011-03-22 11:44:40 +0000
+++ b/sql/ha_ndbcluster.cc 2011-03-24 10:23:22 +0000
@@ -2902,9 +2902,6 @@ int ha_ndbcluster::write_row(uchar *reco
}
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());
@@ -3142,11 +3139,6 @@ int ha_ndbcluster::update_row(const ucha
}
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],
=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc 2011-03-18 10:31:17 +0000
+++ b/sql/ha_partition.cc 2011-03-24 10:23:22 +0000
@@ -3233,10 +3233,6 @@ void ha_partition::try_semi_consistent_r
Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
- 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.
*/
int ha_partition::write_row(uchar * buf)
@@ -3247,17 +3243,11 @@ 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;
sql_mode_t saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
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.
@@ -3327,7 +3317,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);
}
@@ -3362,18 +3351,8 @@ int ha_partition::update_row(const uchar
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)))
@@ -3448,7 +3427,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);
}
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2011-03-22 11:44:40 +0000
+++ b/sql/handler.cc 2011-03-24 10:23:22 +0000
@@ -5951,7 +5951,9 @@ int handler::ha_write_row(uchar *buf)
MYSQL_START_TABLE_IO_WAIT(locker, &state, m_psi,
PSI_TABLE_WRITE_ROW, MAX_KEY, 0);
+ table->start_insert();
error= write_row(buf);
+ table->end_insert();
MYSQL_END_TABLE_IO_WAIT(locker);
MYSQL_INSERT_ROW_DONE(error);
@@ -5984,7 +5986,9 @@ int handler::ha_update_row(const uchar *
MYSQL_START_TABLE_IO_WAIT(locker, &state, m_psi,
PSI_TABLE_UPDATE_ROW, MAX_KEY, 0);
+ table->start_update();
error= update_row(old_data, new_data);
+ table->end_update();
MYSQL_END_TABLE_IO_WAIT(locker);
MYSQL_UPDATE_ROW_DONE(error);
=== modified file 'sql/table.cc'
--- a/sql/table.cc 2011-03-17 09:47:50 +0000
+++ b/sql/table.cc 2011-03-24 10:23:22 +0000
@@ -5411,6 +5411,45 @@ bool TABLE::update_const_key_parts(Item
}
/**
+ This member function is called by the handler right before a new row is
+ inserted in the table.
+*/
+void TABLE::start_insert() {
+ saved_timestamp_field_type= timestamp_field_type;
+ if ((timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) != 0)
+ timestamp_field->set_time();
+ timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+}
+
+/**
+ This member function is called by the handler right after a new row is
+ inserted in the table.
+*/
+void TABLE::end_insert() {
+ timestamp_field_type= saved_timestamp_field_type;
+}
+
+/**
+ This member function is called by the handler right before a row in the
+ table is updated.
+*/
+void TABLE::start_update() {
+ saved_timestamp_field_type= timestamp_field_type;
+ if ((timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) != 0)
+ timestamp_field->set_time();
+ timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+}
+
+/**
+ This member function is called by the handler right after a row in the
+ table is updated.
+*/
+void TABLE::end_update() {
+ timestamp_field_type= saved_timestamp_field_type;
+}
+
+
+/**
Test if the order list consists of simple field expressions
@param order Linked list of ORDER BY arguments
=== modified file 'sql/table.h'
--- a/sql/table.h 2011-03-09 20:54:55 +0000
+++ b/sql/table.h 2011-03-24 10:23:22 +0000
@@ -931,6 +931,7 @@ private:
TABLE *share_next, **share_prev;
friend struct TABLE_share;
+ timestamp_auto_set_type saved_timestamp_field_type;
public:
@@ -1174,6 +1175,12 @@ public:
}
bool update_const_key_parts(Item *conds);
+
+ void start_insert();
+ void end_insert();
+ void start_update();
+ void end_update();
+
};
=== modified file 'storage/archive/ha_archive.cc'
--- a/storage/archive/ha_archive.cc 2011-03-22 11:44:40 +0000
+++ b/storage/archive/ha_archive.cc 2011-03-24 10:23:22 +0000
@@ -871,8 +871,6 @@ int ha_archive::write_row(uchar *buf)
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
mysql_mutex_lock(&share->mutex);
if (!share->archive_write_open)
=== modified file 'storage/csv/ha_tina.cc'
--- a/storage/csv/ha_tina.cc 2011-03-22 11:44:40 +0000
+++ b/storage/csv/ha_tina.cc 2011-03-24 10:23:22 +0000
@@ -986,9 +986,6 @@ int ha_tina::write_row(uchar * buf)
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
-
size= encode_quote(buf);
if (!share->tina_write_opened)
@@ -1037,8 +1034,8 @@ int ha_tina::open_update_temp_file_if_ne
/*
This is called for an update.
- Make sure you put in code to increment the auto increment, also
- update any timestamp data. Currently auto increment is not being
+ Make sure you put in code to increment the auto increment.
+ Currently auto increment is not being
fixed since autoincrements have yet to be added to this table handler.
This will be called in a table scan right before the previous ::rnd_next()
call.
@@ -1051,9 +1048,6 @@ int ha_tina::update_row(const uchar * ol
ha_statistic_increment(&SSV::ha_update_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
-
size= encode_quote(new_data);
/*
=== modified file 'storage/example/ha_example.cc'
--- a/storage/example/ha_example.cc 2011-03-22 11:44:40 +0000
+++ b/storage/example/ha_example.cc 2011-03-24 10:23:22 +0000
@@ -365,9 +365,6 @@ int ha_example::close(void)
ha_berekly.cc has an example of how to store it intact by "packing" it
for ha_berkeley's own native storage type.
- See the note for update_row() on auto_increments and timestamps. This
- case also applies to write_row().
-
Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
@@ -396,16 +393,6 @@ int ha_example::write_row(uchar *buf)
Keep in mind that the server can do updates based on ordering if an ORDER BY
clause was used. Consecutive ordering is not guaranteed.
- @details
- Currently new_data will not have an updated auto_increament record, or
- and updated timestamp field. You can do these for example by doing:
- @code
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
- if (table->next_number_field && record == table->record[0])
- update_auto_increment();
- @endcode
-
Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
@see
=== modified file 'storage/federated/ha_federated.cc'
--- a/storage/federated/ha_federated.cc 2011-03-22 11:44:40 +0000
+++ b/storage/federated/ha_federated.cc 2011-03-24 10:23:22 +0000
@@ -1834,8 +1834,6 @@ int ha_federated::write_row(uchar *buf)
values_string.length(0);
insert_field_value_string.length(0);
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
/*
start both our field and field values strings
@@ -2108,12 +2106,12 @@ int ha_federated::repair(THD* thd, HA_CH
Keep in mind that the server can do updates based on ordering if an ORDER BY
clause was used. Consecutive ordering is not guaranteed.
- Currently new_data will not have an updated auto_increament record, or
- and updated timestamp field. You can do these for federated by doing these:
- if (table->timestamp_on_update_now)
- update_timestamp(new_row+table->timestamp_on_update_now-1);
- if (table->next_number_field && record == table->record[0])
- update_auto_increment();
+
+ Currently new_data will not have an updated AUTO_INCREMENT record. You can
+ do this for federated by doing the following:
+
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
*/
=== modified file 'storage/heap/ha_heap.cc'
--- a/storage/heap/ha_heap.cc 2011-03-22 11:44:40 +0000
+++ b/storage/heap/ha_heap.cc 2011-03-24 10:23:22 +0000
@@ -225,8 +225,7 @@ int ha_heap::write_row(uchar * buf)
{
int res;
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
+
if (table->next_number_field && buf == table->record[0])
{
if ((res= update_auto_increment()))
@@ -249,8 +248,7 @@ int ha_heap::update_row(const uchar * ol
{
int res;
ha_statistic_increment(&SSV::ha_update_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
+
res= heap_update(file,old_data,new_data);
if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD >
file->s->records)
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc 2011-03-22 11:44:40 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2011-03-24 10:23:22 +0000
@@ -5338,9 +5338,6 @@ ha_innobase::write_row(
ha_statistic_increment(&SSV::ha_write_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
-
sql_command = thd_sql_command(user_thd);
if ((sql_command == SQLCOM_ALTER_TABLE
@@ -5727,9 +5724,6 @@ ha_innobase::update_row(
ha_statistic_increment(&SSV::ha_update_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
-
if (prebuilt->upd_node) {
uvect = prebuilt->upd_node->update;
} else {
=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc 2011-03-22 11:44:40 +0000
+++ b/storage/myisam/ha_myisam.cc 2011-03-24 10:23:22 +0000
@@ -766,10 +766,6 @@ int ha_myisam::write_row(uchar *buf)
{
ha_statistic_increment(&SSV::ha_write_count);
- /* 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();
-
/*
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.
@@ -1532,8 +1528,6 @@ bool ha_myisam::is_crashed() const
int ha_myisam::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();
return mi_update(file,old_data,new_data);
}
=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc 2011-03-22 11:44:40 +0000
+++ b/storage/myisammrg/ha_myisammrg.cc 2011-03-24 10:23:22 +0000
@@ -1046,8 +1046,6 @@ int ha_myisammrg::write_row(uchar * buf)
if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
DBUG_RETURN(HA_ERR_TABLE_READONLY);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
- table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
{
int error;
@@ -1061,8 +1059,6 @@ int ha_myisammrg::update_row(const uchar
{
DBUG_ASSERT(this->file->children_attached);
ha_statistic_increment(&SSV::ha_update_count);
- if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
- table->timestamp_field->set_time();
return myrg_update(file,old_data,new_data);
}
=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt 2011-02-17 14:39:47 +0000
+++ b/unittest/gunit/CMakeLists.txt 2011-03-24 10:23:22 +0000
@@ -222,6 +222,7 @@ SET(TESTS
# Add tests (link them with gunit library and the server libraries)
SET(SERVER_TESTS
item
+ table
)
FOREACH(test ${TESTS})
=== added file 'unittest/gunit/table-t.cc'
--- a/unittest/gunit/table-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/table-t.cc 2011-03-24 10:23:22 +0000
@@ -0,0 +1,109 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+// First include (the generated) my_config.h, to get correct platform defines,
+// then gtest.h (before any other MySQL headers), to avoid min() macros etc ...
+#include "my_config.h"
+#include <gtest/gtest.h>
+
+#include "table.h"
+#include "field.h"
+
+namespace {
+
+class Mock_field_timestamp : public Field_timestamp
+{
+public:
+ bool set_time_called;
+ Mock_field_timestamp() : Field_timestamp(false, "mock", &my_charset_latin1),
+ set_time_called(false) {}
+ void set_time() { set_time_called= true; }
+ void reset_mock() { set_time_called= false; }
+};
+
+
+TEST(TableTest, start_insert)
+{
+ TABLE table;
+ Mock_field_timestamp field;
+ table.timestamp_field= &field;
+
+ table.timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ table.start_insert();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_FALSE(field.set_time_called);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_INSERT;
+ table.start_insert();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_TRUE(field.set_time_called);
+ table.end_insert();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_INSERT, table.timestamp_field_type);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_UPDATE;
+ table.start_insert();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_FALSE(field.set_time_called);
+ table.end_insert();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_UPDATE, table.timestamp_field_type);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_BOTH;
+ table.start_insert();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_TRUE(field.set_time_called);
+ table.end_insert();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_BOTH, table.timestamp_field_type);
+}
+
+TEST(TableTest, start_update)
+{
+ TABLE table;
+ Mock_field_timestamp field;
+ table.timestamp_field= &field;
+
+ table.timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
+ table.start_update();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_FALSE(field.set_time_called);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_INSERT;
+ table.start_update();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_FALSE(field.set_time_called);
+ table.end_update();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_INSERT, table.timestamp_field_type);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_UPDATE;
+ table.start_update();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_TRUE(field.set_time_called);
+ table.end_update();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_UPDATE, table.timestamp_field_type);
+
+ field.reset_mock();
+ table.timestamp_field_type= TIMESTAMP_AUTO_SET_ON_BOTH;
+ table.start_update();
+ ASSERT_EQ(TIMESTAMP_NO_AUTO_SET, table.timestamp_field_type);
+ ASSERT_TRUE(field.set_time_called);
+ table.end_update();
+ ASSERT_EQ(TIMESTAMP_AUTO_SET_ON_BOTH, table.timestamp_field_type);
+}
+
+}
Attachment: [text/bzr-bundle] bzr/martin.hansson@oracle.com-20110324102322-zads1x9usovg2rla.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (martin.hansson:3318) | Martin Hansson | 24 Mar |