From: Martin Hansson Date: March 24 2011 10:23am Subject: bzr commit into mysql-trunk branch (martin.hansson:3318) List-Archive: http://lists.mysql.com/commits/133749 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1812546469==" --===============1812546469== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #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 + +#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); +} + +} --===============1812546469== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.hansson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.hansson@stripped\ # zads1x9usovg2rla # target_branch: file:///data0/martin/bzrroot/bug11746628/t-\ # enginestuff/ # testament_sha1: 5ca7754931fd843be820b6f22b5478d165516dda # timestamp: 2011-03-24 11:23:28 +0100 # base_revision_id: tor.didriksen@stripped\ # 1i917d6g1zh0fjly # # Begin bundle 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 woSDRmlCcA== --===============1812546469==--