summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2019-05-28 15:50:11 +0400
committerAlexander Barkov <bar@mariadb.com>2019-05-28 15:50:11 +0400
commitf021317ae1bceb1a70fd6b72a9e4afd72e5e5fbe (patch)
treedc98c989edd63a886444d6b2f2d17469579ddb91
parentd1d6fe9abf6dc11745ee4432ab97a46cbb244bf5 (diff)
downloadmariadb-git-f021317ae1bceb1a70fd6b72a9e4afd72e5e5fbe.tar.gz
MDEV-19612 Split ALTER related data type specific code in sql_table.cc to Type_handler
-rw-r--r--mysql-test/main/alter_table_debug.result26
-rw-r--r--mysql-test/main/alter_table_debug.test31
-rw-r--r--sql/sql_alter.cc18
-rw-r--r--sql/sql_alter.h3
-rw-r--r--sql/sql_table.cc36
-rw-r--r--sql/sql_type.cc71
-rw-r--r--sql/sql_type.h22
7 files changed, 174 insertions, 33 deletions
diff --git a/mysql-test/main/alter_table_debug.result b/mysql-test/main/alter_table_debug.result
new file mode 100644
index 00000000000..3366f1721cd
--- /dev/null
+++ b/mysql-test/main/alter_table_debug.result
@@ -0,0 +1,26 @@
+#
+# 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
+#
diff --git a/mysql-test/main/alter_table_debug.test b/mysql-test/main/alter_table_debug.test
new file mode 100644
index 00000000000..43a1f1bcbd8
--- /dev/null
+++ b/mysql-test/main/alter_table_debug.test
@@ -0,0 +1,31 @@
+--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 #
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index fd39113a44b..2a87d8069bc 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -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;
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index a40c980b692..113df10054b 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -287,8 +287,9 @@ public:
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;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 95bc483bc39..a5c6f1336c5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -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 @@ err_new_table_cleanup:
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)
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 2b042cc38bd..ee5a20a08cf 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -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
{
/*
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 06b72dd7d27..2a96e7ca654 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -3207,6 +3207,7 @@ public:
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 @@ public:
{
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 @@ protected:
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 @@ public:
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 @@ public:
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 @@ protected:
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; }