/* Copyright (c) 2012, 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ // First include (the generated) my_config.h, to get correct platform defines. #include "my_config.h" #include #include "field_temporal_utils.h" #include "test_utils.h" #include "fake_table.h" #include "field.h" namespace field_date_unittests { using my_testing::Server_initializer; using my_testing::Mock_error_handler; class FieldDateTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } THD *thd() { return initializer.thd(); } Server_initializer initializer; Field_set *create_field_set(TYPELIB *tl); // Store zero date using different combinations of SQL modes static const int no_modes= 3; static const sql_mode_t strict_modes[no_modes]; static const type_conversion_status nozero_expected_status[]; }; const sql_mode_t FieldDateTest::strict_modes[no_modes]= { MODE_STRICT_TRANS_TABLES, MODE_STRICT_ALL_TABLES, MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES }; const type_conversion_status FieldDateTest::nozero_expected_status[]= { TYPE_ERR_BAD_VALUE, TYPE_ERR_BAD_VALUE, TYPE_ERR_BAD_VALUE }; class Mock_field_date : public Field_newdate { private: uchar buffer[PACK_LENGTH]; uchar null_byte; void initialize() { ptr= buffer; memset(buffer, 0, PACK_LENGTH); null_byte= '\0'; set_null_ptr(&null_byte, 1); } public: Mock_field_date() : Field_newdate(0, // ptr_arg NULL, // null_ptr_arg 1, // null_bit_arg Field::NONE, // unireg_check_arg "field_name") // field_name_arg { initialize(); } void make_writable() { bitmap_set_bit(table->write_set, field_index); } void make_readable() { bitmap_set_bit(table->read_set, field_index); } }; TEST_F(FieldDateTest, StoreLegalStringValues) { Mock_field_date field_date; Fake_TABLE table(&field_date); table.in_use= thd(); field_date.make_writable(); field_date.make_readable(); { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("2001-01-01"), "2001-01-01", 0, TYPE_OK); } { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("0000-00-00"), "0000-00-00", 0, TYPE_OK); } { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("0001-00-00"), "0001-00-00", 0, TYPE_OK); } } TEST_F(FieldDateTest, StoreIllegalStringValues) { Mock_field_date field_date; Fake_TABLE table(&field_date); table.in_use= thd(); field_date.make_writable(); field_date.make_readable(); thd()->count_cuted_fields= CHECK_FIELD_WARN; // Truncates time { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("2001-01-01 00:00:01"), "2001-01-01", WARN_DATA_TRUNCATED, TYPE_NOTE_TIME_TRUNCATED); } // Bad year { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("99999-01-01"), "0000-00-00", WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE); } // Bad month { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("2001-13-01"), "0000-00-00", WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE); } // Bad day { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("2001-01-32"), "0000-00-00", WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE); } // Not a date { SCOPED_TRACE(""); test_store_string(&field_date, STRING_WITH_LEN("foo"), "0000-00-00", WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE); } } /** Strictness mode test 1: Try storing dates with zeroes when no zero-restrictions apply (neither NO_ZERO_DATE or NO_ZERO_IN_DATE are set). There should be no errors, warnings or notes. */ TEST_F(FieldDateTest, StoreZeroDateSqlModeNoZeroRestrictions) { Mock_field_date field_date; Fake_TABLE table(&field_date); table.in_use= thd(); field_date.make_writable(); field_date.make_readable(); thd()->count_cuted_fields= CHECK_FIELD_WARN; for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-00-00"), "0000-00-00", TYPE_OK, strict_modes[i], 0); } for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-01-01"), "0000-01-01", TYPE_OK, strict_modes[i], 0); } for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-00-01"), "2001-00-01", TYPE_OK, strict_modes[i], 0); } for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-01-00"), "2001-01-00", TYPE_OK, strict_modes[i], 0); } } /** Strictness mode test 2: Try storing dates with zeroes when NO_ZERO_DATE flag is set. There should be no errors, warnings or notes unless the entire date is zero: "0000-00-00" */ TEST_F(FieldDateTest, StoreZeroDateSqlModeNoZeroDate) { Mock_field_date field_date; Fake_TABLE table(&field_date); table.in_use= thd(); field_date.make_writable(); field_date.make_readable(); thd()->count_cuted_fields= CHECK_FIELD_WARN; // With "MODE_NO_ZERO_DATE" set - Errors if date is all null for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-00-00"), "0000-00-00", nozero_expected_status[i], MODE_NO_ZERO_DATE | strict_modes[i], ER_TRUNCATED_WRONG_VALUE); } // Zero year, month or day is fine for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-01-01"), "0000-01-01", TYPE_OK, MODE_NO_ZERO_DATE | strict_modes[i], 0); } for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-00-01"), "2001-00-01", TYPE_OK, MODE_NO_ZERO_DATE | strict_modes[i], 0); } for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-01-00"), "2001-01-00", TYPE_OK, MODE_NO_ZERO_DATE | strict_modes[i], 0); } } /** Strictness mode test 3: Try storing dates with zeroes when NO_ZERO_IN_DATE flag is set. There should be no errors unless either month or day is zero. */ TEST_F(FieldDateTest, StoreZeroDateSqlModeNoZeroInDate) { Mock_field_date field_date; Fake_TABLE table(&field_date); table.in_use= thd(); field_date.make_writable(); field_date.make_readable(); thd()->count_cuted_fields= CHECK_FIELD_WARN; // With "MODE_NO_ZERO_IN_DATE" set - Entire date zero is ok for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-00-00"), "0000-00-00", TYPE_OK, MODE_NO_ZERO_IN_DATE | strict_modes[i], 0); } // Year 0 is valid in strict mode too for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("0000-01-01"), "0000-01-01", TYPE_OK, MODE_NO_ZERO_IN_DATE | strict_modes[i], 0); } // Month 0 is NOT valid in strict mode, stores all-zero date for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-00-01"), "0000-00-00", nozero_expected_status[i], MODE_NO_ZERO_IN_DATE | strict_modes[i], ER_TRUNCATED_WRONG_VALUE); } // Day 0 is NOT valid in strict mode, stores all-zero date for (int i= 0; i < no_modes; i++) { SCOPED_TRACE(""); store_zero_in_sql_mode(&field_date, STRING_WITH_LEN("2001-01-00"), "0000-00-00", nozero_expected_status[i], MODE_NO_ZERO_IN_DATE | strict_modes[i], ER_TRUNCATED_WRONG_VALUE); } } }