mysql5/mysql-5.7.27/unittest/gunit/field_datetime-t.cc

373 lines
11 KiB
C++

/* 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 <gtest/gtest.h>
#include "field_temporal_utils.h"
#include "test_utils.h"
#include "fake_table.h"
#include "field.h"
namespace field_datetime_unittests {
using my_testing::Server_initializer;
using my_testing::Mock_error_handler;
class FieldDatetimeTest : 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);
};
class Mock_field_datetime : public Field_datetime
{
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_datetime()
: Field_datetime(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(FieldDatetimeTest, StoreLegalStringValues)
{
char buff[MAX_FIELD_WIDTH];
String str(buff, sizeof(buff), &my_charset_bin);
String unused;
Mock_field_datetime field_dt;
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-01-01 00:00:01"),
"2001-01-01 00:00:01", 0, TYPE_OK);
}
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("0000-00-00 00:00:00"),
"0000-00-00 00:00:00", 0, TYPE_OK);
}
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("0001-00-00 00:00:00"),
"0001-00-00 00:00:00", 0, TYPE_OK);
}
}
TEST_F(FieldDatetimeTest, StoreIllegalStringValues)
{
Mock_field_datetime field_dt;
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// Bad year
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("99999-01-01 00:00:01"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Bad month
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-13-01 00:00:01"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Bad day
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-01-32 00:00:01"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Bad hour
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-01-01 72:00:01"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Bad minute
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-01-01 00:72:01"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Bad second
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("2001-01-01 00:00:72"),
"0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
// Not a day
{
SCOPED_TRACE("");
test_store_string(&field_dt, STRING_WITH_LEN("foo"), "0000-00-00 00:00:00",
WARN_DATA_TRUNCATED, TYPE_ERR_BAD_VALUE);
}
}
// Store zero date using different combinations of SQL modes
static const int no_modes= 3;
static const sql_mode_t strict_modes[no_modes]=
{
MODE_STRICT_TRANS_TABLES,
MODE_STRICT_ALL_TABLES,
MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES
};
/**
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(FieldDatetimeTest, StoreZeroDateSqlModeNoZeroRestrictions)
{
Mock_field_datetime field_dt;
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
field_dt.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_dt,
STRING_WITH_LEN("0000-00-00 00:00:00"),
"0000-00-00 00:00:00",
TYPE_OK, strict_modes[i], 0);
}
for (int i= 0; i < no_modes; i++)
{
SCOPED_TRACE("");
store_zero_in_sql_mode(&field_dt,
STRING_WITH_LEN("0000-01-01 00:00:00"),
"0000-01-01 00:00:00",
TYPE_OK, strict_modes[i], 0);
}
for (int i= 0; i < no_modes; i++)
{
SCOPED_TRACE("");
store_zero_in_sql_mode(&field_dt,
STRING_WITH_LEN("2001-00-01 00:00:00"),
"2001-00-01 00:00:00",
TYPE_OK, strict_modes[i], 0);
}
for (int i= 0; i < no_modes; i++)
{
SCOPED_TRACE("");
store_zero_in_sql_mode(&field_dt,
STRING_WITH_LEN("2001-01-00 00:00:00"),
"2001-01-00 00:00:00",
TYPE_OK, strict_modes[i], 0);
}
}
static const type_conversion_status nozero_expected_status[]=
{
TYPE_ERR_BAD_VALUE,
TYPE_ERR_BAD_VALUE,
TYPE_ERR_BAD_VALUE
};
/**
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(FieldDatetimeTest, StoreZeroDateSqlModeNoZeroDate)
{
Mock_field_datetime field_dt;
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
field_dt.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_dt,
STRING_WITH_LEN("0000-00-00 00:00:00"),
"0000-00-00 00: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_dt,
STRING_WITH_LEN("0000-01-01 00:00:00"),
"0000-01-01 00:00:00",
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_dt,
STRING_WITH_LEN("2001-00-01 00:00:00"),
"2001-00-01 00:00:00",
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_dt,
STRING_WITH_LEN("2001-01-00 00:00:00"),
"2001-01-00 00:00: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(FieldDatetimeTest, StoreZeroDateSqlModeNoZeroInDate)
{
Mock_field_datetime field_dt;
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
field_dt.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_dt,
STRING_WITH_LEN("0000-00-00 00:00:00"),
"0000-00-00 00: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_dt,
STRING_WITH_LEN("0000-01-01 00:00:00"),
"0000-01-01 00:00:00",
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_dt,
STRING_WITH_LEN("2001-00-01 00:00:00"),
"0000-00-00 00: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_dt,
STRING_WITH_LEN("2001-01-00 00:00:00"),
"0000-00-00 00:00:00",
nozero_expected_status[i],
MODE_NO_ZERO_IN_DATE | strict_modes[i],
ER_TRUNCATED_WRONG_VALUE);
}
}
}