Commit f021317a authored by Alexander Barkov's avatar Alexander Barkov

MDEV-19612 Split ALTER related data type specific code in sql_table.cc to Type_handler

parent d1d6fe9a
#
# Start of 10.5 tests
#
#
# MDEV-19612 Split ALTER related data type specific code in sql_table.cc to Type_handler
#
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
DROP TABLE t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0);
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
DROP TABLE t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0);
SET debug_dbug='+d,validate_implicit_default_value_error';
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
ERROR 22007: Incorrect int value: '0' for column `test`.`t1`.`b` at row 1
SET debug_dbug='-d,validate_implicit_default_value_error';
DROP TABLE t1;
#
# End of 10.5 tests
#
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-19612 Split ALTER related data type specific code in sql_table.cc to Type_handler
--echo #
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
DROP TABLE t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0);
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
DROP TABLE t1;
SET sql_mode='STRICT_ALL_TABLES,STRICT_TRANS_TABLES,NO_ZERO_DATE';
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0);
SET debug_dbug='+d,validate_implicit_default_value_error';
--error ER_TRUNCATED_WRONG_VALUE
ALTER TABLE t1 ALGORITHM=COPY, ADD b INT NOT NULL;
SET debug_dbug='-d,validate_implicit_default_value_error';
DROP TABLE t1;
--echo #
--echo # End of 10.5 tests
--echo #
......@@ -239,7 +239,8 @@ bool Alter_info::vers_prohibited(THD *thd) const
Alter_table_ctx::Alter_table_ctx()
: datetime_field(NULL), error_if_not_empty(false),
: implicit_default_value_error_field(NULL),
error_if_not_empty(false),
tables_opened(0),
db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str),
......@@ -260,7 +261,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
uint tables_opened_arg,
const LEX_CSTRING *new_db_arg,
const LEX_CSTRING *new_name_arg)
: datetime_field(NULL), error_if_not_empty(false),
: implicit_default_value_error_field(NULL), error_if_not_empty(false),
tables_opened(tables_opened_arg),
new_db(*new_db_arg), new_name(*new_name_arg),
fk_error_if_delete_row(false), fk_error_id(NULL),
......@@ -352,6 +353,19 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
}
void Alter_table_ctx::report_implicit_default_value_error(THD *thd,
const TABLE_SHARE *s)
const
{
Create_field *error_field= implicit_default_value_error_field;
const Type_handler *h= error_field->type_handler();
thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
h->name().ptr(),
h->default_value().ptr(),
s, error_field->field_name.str);
}
bool Sql_cmd_alter_table::execute(THD *thd)
{
LEX *lex= thd->lex;
......
......@@ -287,8 +287,9 @@ class Alter_table_ctx
fk_error_table= fk->foreign_table->str;
}
void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const;
public:
Create_field *datetime_field;
Create_field *implicit_default_value_error_field;
bool error_if_not_empty;
uint tables_opened;
LEX_CSTRING db;
......
......@@ -8197,15 +8197,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
flag to allow ALTER TABLE only if the table to be altered is empty.
*/
if ((def->real_field_type() == MYSQL_TYPE_DATE ||
def->real_field_type() == MYSQL_TYPE_NEWDATE ||
def->real_field_type() == MYSQL_TYPE_DATETIME ||
def->real_field_type() == MYSQL_TYPE_DATETIME2) &&
!alter_ctx->datetime_field &&
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
thd->variables.sql_mode & MODE_NO_ZERO_DATE)
{
alter_ctx->datetime_field= def;
if (!alter_ctx->implicit_default_value_error_field &&
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
def->type_handler()->validate_implicit_default_value(thd, *def))
{
alter_ctx->implicit_default_value_error_field= def;
alter_ctx->error_if_not_empty= TRUE;
}
if (def->flags & VERS_SYSTEM_FIELD &&
......@@ -10392,28 +10388,8 @@ do_continue:;
if (unlikely(alter_ctx.error_if_not_empty &&
thd->get_stmt_da()->current_row_for_warning()))
{
const char *f_val= "0000-00-00";
const char *f_type= "date";
switch (alter_ctx.datetime_field->real_field_type())
{
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_NEWDATE:
break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_DATETIME2:
f_val= "0000-00-00 00:00:00";
f_type= "datetime";
break;
default:
/* Shouldn't get here. */
DBUG_ASSERT(0);
}
Abort_on_warning_instant_set aws(thd, true);
thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
f_type, f_val,
new_table->s,
alter_ctx.datetime_field->
field_name.str);
alter_ctx.report_implicit_default_value_error(thd, new_table->s);
}
if (new_table)
......
......@@ -8514,6 +8514,77 @@ Type_handler_timestamp_common::Item_param_val_native(THD *thd,
}
/***************************************************************************/
bool Type_handler::validate_implicit_default_value(THD *thd,
const Column_definition &def) const
{
DBUG_EXECUTE_IF("validate_implicit_default_value_error", return true;);
return false;
}
bool Type_handler_date_common::validate_implicit_default_value(THD *thd,
const Column_definition &def) const
{
return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
}
bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
const Column_definition &def) const
{
return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
}
/***************************************************************************/
const Name & Type_handler_row::default_value() const
{
DBUG_ASSERT(0);
static Name def(STRING_WITH_LEN(""));
return def;
}
const Name & Type_handler_numeric::default_value() const
{
static Name def(STRING_WITH_LEN("0"));
return def;
}
const Name & Type_handler_string_result::default_value() const
{
static Name def(STRING_WITH_LEN(""));
return def;
}
const Name & Type_handler_time_common::default_value() const
{
static Name def(STRING_WITH_LEN("00:00:00"));
return def;
}
const Name & Type_handler_date_common::default_value() const
{
static Name def(STRING_WITH_LEN("0000-00-00"));
return def;
}
const Name & Type_handler_datetime_common::default_value() const
{
static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
return def;
}
const Name & Type_handler_timestamp_common::default_value() const
{
static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
return def;
}
/***************************************************************************/
LEX_CSTRING Charset::collation_specific_name() const
{
/*
......
......@@ -3207,6 +3207,7 @@ class Type_handler
virtual const Name name() const= 0;
virtual const Name version() const { return m_version_default; }
virtual const Name &default_value() const= 0;
virtual enum_field_types field_type() const= 0;
virtual enum_field_types real_field_type() const { return field_type(); }
/**
......@@ -3395,6 +3396,10 @@ class Type_handler
{
return false;
}
// Check if the implicit default value is Ok in the current sql_mode
virtual bool validate_implicit_default_value(THD *thd,
const Column_definition &def)
const;
// Automatic upgrade, e.g. for ALTER TABLE t1 FORCE
virtual void Column_definition_implicit_upgrade(Column_definition *c) const
{ }
......@@ -3758,6 +3763,13 @@ class Type_handler_row: public Type_handler
public:
virtual ~Type_handler_row() {}
const Name name() const { return m_name_row; }
const Name &default_value() const;
bool validate_implicit_default_value(THD *thd,
const Column_definition &def) const
{
DBUG_ASSERT(0);
return true;
}
bool is_scalar_type() const { return false; }
bool can_return_int() const { return false; }
bool can_return_decimal() const { return false; }
......@@ -4111,6 +4123,7 @@ class Type_handler_numeric: public Type_handler
const Type_handler *handler)
const;
public:
const Name &default_value() const;
String *print_item_value(THD *thd, Item *item, String *str) const;
double Item_func_min_max_val_real(Item_func_min_max *) const;
longlong Item_func_min_max_val_int(Item_func_min_max *) const;
......@@ -4612,6 +4625,7 @@ class Type_handler_string_result: public Type_handler
{
uint Item_temporal_precision(THD *thd, Item *item, bool is_time) const;
public:
const Name &default_value() const;
protocol_send_type_t protocol_send_type() const
{
return PROTOCOL_SEND_STRING;
......@@ -5244,6 +5258,7 @@ class Type_handler_time_common: public Type_handler_temporal_result
public:
virtual ~Type_handler_time_common() { }
const Name name() const { return m_name_time; }
const Name &default_value() const;
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
protocol_send_type_t protocol_send_type() const
{
......@@ -5408,6 +5423,7 @@ class Type_handler_date_common: public Type_handler_temporal_with_date
public:
virtual ~Type_handler_date_common() {}
const Name name() const { return m_name_date; }
const Name &default_value() const;
const Type_handler *type_handler_for_comparison() const;
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
protocol_send_type_t protocol_send_type() const
......@@ -5430,6 +5446,8 @@ class Type_handler_date_common: public Type_handler_temporal_with_date
CHARSET_INFO *cs, bool send_error) const;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
bool validate_implicit_default_value(THD *thd,
const Column_definition &def) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
uint Item_decimal_precision(const Item *item) const;
String *print_item_value(THD *thd, Item *item, String *str) const;
......@@ -5505,6 +5523,7 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date
public:
virtual ~Type_handler_datetime_common() {}
const Name name() const { return m_name_datetime; }
const Name &default_value() const;
const Type_handler *type_handler_for_comparison() const;
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
protocol_send_type_t protocol_send_type() const
......@@ -5525,6 +5544,8 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date
bool show_field) const;
Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const;
bool validate_implicit_default_value(THD *thd,
const Column_definition &def) const;
void Column_definition_implicit_upgrade(Column_definition *c) const;
bool Column_definition_fix_attributes(Column_definition *c) const;
uint Item_decimal_scale(const Item *item) const
......@@ -5621,6 +5642,7 @@ class Type_handler_timestamp_common: public Type_handler_temporal_with_date
public:
virtual ~Type_handler_timestamp_common() {}
const Name name() const { return m_name_timestamp; }
const Name &default_value() const;
const Type_handler *type_handler_for_comparison() const;
const Type_handler *type_handler_for_native_format() const;
enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment