summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2018-04-24 10:06:31 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2018-04-24 10:06:31 +0200
commitf79c5a658cc33a10d7744a748a4328254e2cbaf7 (patch)
tree44a28accf68a623dcad14e96ca18aca71eecfb68
parent47ac7252ff2be9a07b669ce3365953cd9a207654 (diff)
parent4f9977d8d3292caf509227154dafc416a178d17d (diff)
downloadmariadb-git-f79c5a658cc33a10d7744a748a4328254e2cbaf7.tar.gz
Merge branch '10.3' into bb-10.3-MDEV-10814
-rw-r--r--mysql-test/suite/innodb/r/innodb-alter-timestamp.result12
-rw-r--r--mysql-test/suite/innodb/r/innodb-table-online.result4
-rw-r--r--mysql-test/suite/innodb/t/innodb-alter-timestamp.test6
-rw-r--r--mysql-test/suite/innodb/t/innodb-table-online.test5
-rw-r--r--sql/share/errmsg-utf8.txt2
-rw-r--r--storage/innobase/handler/handler0alter.cc165
-rw-r--r--storage/innobase/include/row0log.h7
-rw-r--r--storage/innobase/include/row0merge.h4
-rw-r--r--storage/innobase/include/row0row.h8
-rw-r--r--storage/innobase/row/row0log.cc56
-rw-r--r--storage/innobase/row/row0merge.cc31
-rw-r--r--storage/innobase/row/row0row.cc22
12 files changed, 200 insertions, 122 deletions
diff --git a/mysql-test/suite/innodb/r/innodb-alter-timestamp.result b/mysql-test/suite/innodb/r/innodb-alter-timestamp.result
index 9659b03d6b2..b8686d6812e 100644
--- a/mysql-test/suite/innodb/r/innodb-alter-timestamp.result
+++ b/mysql-test/suite/innodb/r/innodb-alter-timestamp.result
@@ -2,7 +2,7 @@ CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
INSERT INTO t1 VALUES(NULL);
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=INPLACE;
-ERROR 22004: Invalid use of NULL value
+ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: cannot convert NULL to non-constant DEFAULT. Try ALGORITHM=COPY
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=COPY;
ERROR 01000: Data truncated for column 'i1' at row 1
@@ -10,20 +10,20 @@ ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY(id), ALGORITHM=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY
ALTER TABLE t1 ADD PRIMARY KEY(i1), ALGORITHM=INPLACE;
-ERROR 22004: Invalid use of NULL value
-ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
-ADD PRIMARY KEY(id);
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT;
affected rows: 1
info: Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
id
-1
+42
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (i1 INT UNSIGNED NOT NULL, d1 TIMESTAMP NULL) ENGINE=InnoDB;
SHOW CREATE TABLE t1;
diff --git a/mysql-test/suite/innodb/r/innodb-table-online.result b/mysql-test/suite/innodb/r/innodb-table-online.result
index 3ac00436e07..d8482ebb23a 100644
--- a/mysql-test/suite/innodb/r/innodb-table-online.result
+++ b/mysql-test/suite/innodb/r/innodb-table-online.result
@@ -411,9 +411,7 @@ SET @old_sql_mode = @@sql_mode;
SET @@sql_mode = 'STRICT_TRANS_TABLES';
ALTER TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)),
ALGORITHM = INPLACE;
-ERROR 22004: Invalid use of NULL value
-ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL;
-ERROR 22004: Invalid use of NULL value
+ERROR 23000: Duplicate entry '' for key 'PRIMARY'
SET @@sql_mode = @old_sql_mode;
UPDATE t1 SET c3=LEFT(CONCAT(c1,REPEAT('foo',c1)),255) WHERE c3 IS NULL;
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL c3p5_created0 WAIT_FOR ins_done0';
diff --git a/mysql-test/suite/innodb/t/innodb-alter-timestamp.test b/mysql-test/suite/innodb/t/innodb-alter-timestamp.test
index d8acc02cbdb..32a54354016 100644
--- a/mysql-test/suite/innodb/t/innodb-alter-timestamp.test
+++ b/mysql-test/suite/innodb/t/innodb-alter-timestamp.test
@@ -3,7 +3,7 @@
CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
INSERT INTO t1 VALUES(NULL);
--enable_info
---error ER_INVALID_USE_OF_NULL
+--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=INPLACE;
--error WARN_DATA_TRUNCATED
@@ -12,10 +12,8 @@ ALGORITHM=COPY;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY(id), ALGORITHM=INPLACE;
---error ER_INVALID_USE_OF_NULL
ALTER TABLE t1 ADD PRIMARY KEY(i1), ALGORITHM=INPLACE;
-ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
-ADD PRIMARY KEY(id);
+ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT;
--disable_info
SELECT * FROM t1;
SHOW CREATE TABLE t1;
diff --git a/mysql-test/suite/innodb/t/innodb-table-online.test b/mysql-test/suite/innodb/t/innodb-table-online.test
index 1bb4b686b56..538e4b68762 100644
--- a/mysql-test/suite/innodb/t/innodb-table-online.test
+++ b/mysql-test/suite/innodb/t/innodb-table-online.test
@@ -358,12 +358,10 @@ SET @old_sql_mode = @@sql_mode;
# NULL -> NOT NULL only allowed INPLACE if strict sql_mode is on.
# And adding a PRIMARY KEY will also add NOT NULL implicitly!
SET @@sql_mode = 'STRICT_TRANS_TABLES';
---error ER_INVALID_USE_OF_NULL
+--error ER_DUP_ENTRY
ALTER TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)),
ALGORITHM = INPLACE;
---error ER_INVALID_USE_OF_NULL
-ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL;
SET @@sql_mode = @old_sql_mode;
UPDATE t1 SET c3=LEFT(CONCAT(c1,REPEAT('foo',c1)),255) WHERE c3 IS NULL;
@@ -397,6 +395,7 @@ ROLLBACK;
--echo # session con1
connection con1;
ALTER TABLE t1 MODIFY c3 CHAR(255) NOT NULL;
+
SET DEBUG_SYNC = 'row_log_table_apply1_before SIGNAL c3p5_created WAIT_FOR ins_done';
--send
ALTER TABLE t1 DROP PRIMARY KEY, DROP COLUMN c22f,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 17192663381..20e42214e93 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7089,7 +7089,7 @@ ER_IDENT_CAUSES_TOO_LONG_PATH
eng "Long database name and identifier for object resulted in path length exceeding %d characters. Path: '%s'"
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL
- eng "cannot silently convert NULL values, as required in this SQL_MODE"
+ eng "cannot convert NULL to non-constant DEFAULT"
ER_MUST_CHANGE_PASSWORD_LOGIN
eng "Your password has expired. To log in you must change it using a client that supports expired passwords"
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 64a41e25632..85b1febf478 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -127,6 +127,10 @@ static const alter_table_operations INNOBASE_ALTER_NOREBUILD
| ALTER_DROP_VIRTUAL_COLUMN
| ALTER_VIRTUAL_COLUMN_ORDER;
+static const alter_table_operations INNOBASE_DEFAULTS
+ = ALTER_COLUMN_NOT_NULLABLE
+ | ALTER_ADD_COLUMN;
+
struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
{
/** Dummy query graph */
@@ -173,8 +177,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
const char** col_names;
/** added AUTO_INCREMENT column position, or ULINT_UNDEFINED */
const ulint add_autoinc;
- /** default values of ADD COLUMN, or NULL */
- const dtuple_t* add_cols;
+ /** default values of ADD and CHANGE COLUMN, or NULL */
+ const dtuple_t* defaults;
/** autoinc sequence to use */
ib_sequence_t sequence;
/** temporary table name to use for old table when renaming tables */
@@ -200,6 +204,9 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
/** original column names of the table */
const char* const old_col_names;
+ /** Whether alter ignore issued. */
+ const bool ignore;
+
ha_innobase_inplace_ctx(row_prebuilt_t*& prebuilt_arg,
dict_index_t** drop_arg,
ulint num_to_drop_arg,
@@ -216,7 +223,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
ulint add_autoinc_arg,
ulonglong autoinc_col_min_value_arg,
ulonglong autoinc_col_max_value_arg,
- ulint num_to_drop_vcol_arg) :
+ ulint num_to_drop_vcol_arg,
+ bool ignore_flag) :
inplace_alter_handler_ctx(),
prebuilt (prebuilt_arg),
add_index (0), add_key_numbers (0), num_to_add_index (0),
@@ -229,7 +237,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
new_table (new_table_arg), instant_table (0),
col_map (0), col_names (col_names_arg),
add_autoinc (add_autoinc_arg),
- add_cols (0),
+ defaults (0),
sequence(prebuilt->trx->mysql_thd,
autoinc_col_min_value_arg, autoinc_col_max_value_arg),
tmp_name (0),
@@ -243,7 +251,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
m_stage(NULL),
old_n_cols(prebuilt_arg->table->n_cols),
old_cols(prebuilt_arg->table->cols),
- old_col_names(prebuilt_arg->table->col_names)
+ old_col_names(prebuilt_arg->table->col_names),
+ ignore(ignore_flag)
{
ut_ad(old_n_cols >= DATA_N_SYS_COLS);
#ifdef UNIV_DEBUG
@@ -674,6 +683,46 @@ instant_alter_column_possible(
|| !create_option_need_rebuild(ha_alter_info, table);
}
+/** Check whether the non-const default value for the field
+@param[in] field field which could be added or changed
+@return true if the non-const default is present. */
+static bool is_non_const_value(Field* field)
+{
+ return field->default_value
+ && field->default_value->flags & ~(VCOL_SESSION_FUNC
+ | VCOL_TIME_FUNC);
+}
+
+/** Set default value for the field.
+@param[in] field field which could be added or changed
+@return true if the default value is set. */
+static bool set_default_value(Field* field)
+{
+ /* The added/changed NOT NULL column lacks a DEFAULT value,
+ or the DEFAULT is the same for all rows.
+ (Time functions, such as CURRENT_TIMESTAMP(),
+ are evaluated from a timestamp that is assigned
+ at the start of the statement. Session
+ functions, such as USER(), always evaluate the
+ same within a statement.) */
+
+ ut_ad(!is_non_const_value(field));
+
+ /* Compute the DEFAULT values of non-constant columns
+ (VCOL_SESSION_FUNC | VCOL_TIME_FUNC). */
+ switch (field->set_default()) {
+ case 0: /* OK */
+ case 3: /* DATETIME to TIME or DATE conversion */
+ return true;
+ case -1: /* OOM, or GEOMETRY type mismatch */
+ case 1: /* A number adjusted to the min/max value */
+ case 2: /* String truncation, or conversion problem */
+ break;
+ }
+
+ return false;
+}
+
/** Check if InnoDB supports a particular alter table in-place
@param altered_table TABLE object for new version of table.
@param ha_alter_info Structure describing changes to be done
@@ -1080,20 +1129,26 @@ ha_innobase::check_if_supported_inplace_alter(
/* No DEFAULT value is
specified. We can report
errors for any NULL values for
- the TIMESTAMP.
-
- FIXME: Allow any DEFAULT
- expression whose value does
- not change during ALTER TABLE.
- This would require a fix in
- row_merge_read_clustered_index()
- to try to replace the DEFAULT
- value before reporting
- DB_INVALID_NULL. */
+ the TIMESTAMP. */
+
goto next_column;
}
break;
default:
+ /* Changing from NULL to NOT NULL and
+ set the default constant values. */
+ if (f->real_maybe_null()
+ && !(*af)->real_maybe_null()) {
+
+ if (is_non_const_value(*af)) {
+ break;
+ }
+
+ if (!set_default_value(*af)) {
+ break;
+ }
+ }
+
/* For any other data type, NULL
values are not converted.
(An AUTO_INCREMENT attribute cannot
@@ -1109,32 +1164,16 @@ ha_innobase::check_if_supported_inplace_alter(
ha_alter_info->unsupported_reason
= innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
- } else if (!(*af)->default_value
- || !((*af)->default_value->flags
- & ~(VCOL_SESSION_FUNC | VCOL_TIME_FUNC))) {
+ } else if (!is_non_const_value(*af)) {
+
n_add_cols++;
if (af < &altered_table->field[table_share->fields]) {
add_column_not_last = true;
}
- /* The added NOT NULL column lacks a DEFAULT value,
- or the DEFAULT is the same for all rows.
- (Time functions, such as CURRENT_TIMESTAMP(),
- are evaluated from a timestamp that is assigned
- at the start of the statement. Session
- functions, such as USER(), always evaluate the
- same within a statement.) */
-
- /* Compute the DEFAULT values of non-constant columns
- (VCOL_SESSION_FUNC | VCOL_TIME_FUNC). */
- switch ((*af)->set_default()) {
- case 0: /* OK */
- case 3: /* DATETIME to TIME or DATE conversion */
+
+ if (set_default_value(*af)) {
goto next_column;
- case -1: /* OOM, or GEOMETRY type mismatch */
- case 1: /* A number adjusted to the min/max value */
- case 2: /* String truncation, or conversion problem */
- break;
}
}
@@ -3181,7 +3220,7 @@ adding columns.
@param table MySQL table as it is before the ALTER operation
@param new_table InnoDB table corresponding to MySQL altered_table
@param old_table InnoDB table corresponding to MYSQL table
-@param add_cols Default values for ADD COLUMN, or NULL if no ADD COLUMN
+@param defaults Default values for ADD COLUMN, or NULL if no ADD COLUMN
@param heap Memory heap where allocated
@return array of integers, mapping column numbers in the table
to column numbers in altered_table */
@@ -3194,7 +3233,7 @@ innobase_build_col_map(
const TABLE* table,
const dict_table_t* new_table,
const dict_table_t* old_table,
- dtuple_t* add_cols,
+ dtuple_t* defaults,
mem_heap_t* heap)
{
DBUG_ENTER("innobase_build_col_map");
@@ -3206,9 +3245,10 @@ innobase_build_col_map(
DBUG_ASSERT(dict_table_get_n_cols(old_table)
+ dict_table_get_n_v_cols(old_table)
>= table->s->fields + DATA_N_SYS_COLS);
- DBUG_ASSERT(!!add_cols == !!(ha_alter_info->handler_flags
- & ALTER_ADD_COLUMN));
- DBUG_ASSERT(!add_cols || dtuple_get_n_fields(add_cols)
+ DBUG_ASSERT(!!defaults == !!(ha_alter_info->handler_flags
+ & (ALTER_ADD_COLUMN
+ | ALTER_COLUMN_NOT_NULLABLE)));
+ DBUG_ASSERT(!defaults || dtuple_get_n_fields(defaults)
== dict_table_get_n_cols(new_table));
ulint* col_map = static_cast<ulint*>(
@@ -3250,6 +3290,19 @@ innobase_build_col_map(
}
if (new_field->field == field) {
+
+ const Field* altered_field =
+ altered_table->field[i];
+
+ if (field->real_maybe_null()
+ && !altered_field->real_maybe_null()) {
+ innobase_build_col_map_add(
+ heap, dtuple_get_nth_field(
+ defaults, i),
+ altered_field,
+ dict_table_is_comp(new_table));
+ }
+
col_map[old_i - num_old_v] = i;
goto found_col;
}
@@ -3257,7 +3310,7 @@ innobase_build_col_map(
ut_ad(!is_v);
innobase_build_col_map_add(
- heap, dtuple_get_nth_field(add_cols, i),
+ heap, dtuple_get_nth_field(defaults, i),
altered_table->field[i + num_v],
dict_table_is_comp(new_table));
found_col:
@@ -4765,7 +4818,7 @@ prepare_inplace_alter_table_dict(
DBUG_ASSERT(!add_fts_doc_id || add_fts_doc_id_idx);
DBUG_ASSERT(!add_fts_doc_id_idx
|| innobase_fulltext_exist(altered_table));
- DBUG_ASSERT(!ctx->add_cols);
+ DBUG_ASSERT(!ctx->defaults);
DBUG_ASSERT(!ctx->add_index);
DBUG_ASSERT(!ctx->add_key_numbers);
DBUG_ASSERT(!ctx->num_to_add_index);
@@ -4933,7 +4986,7 @@ new_clustered_failed:
part ? part : "", partlen + 1);
ulint n_cols = 0;
ulint n_v_cols = 0;
- dtuple_t* add_cols;
+ dtuple_t* defaults;
ulint z = 0;
for (uint i = 0; i < altered_table->s->fields; i++) {
@@ -5101,23 +5154,21 @@ new_clustered_failed:
dict_table_add_system_columns(ctx->new_table, ctx->heap);
- if (ha_alter_info->handler_flags
- & ALTER_ADD_COLUMN) {
- add_cols = dtuple_create_with_vcol(
+ if (ha_alter_info->handler_flags & INNOBASE_DEFAULTS) {
+ defaults = dtuple_create_with_vcol(
ctx->heap,
dict_table_get_n_cols(ctx->new_table),
dict_table_get_n_v_cols(ctx->new_table));
- dict_table_copy_types(add_cols, ctx->new_table);
+ dict_table_copy_types(defaults, ctx->new_table);
} else {
- add_cols = NULL;
+ defaults = NULL;
}
ctx->col_map = innobase_build_col_map(
ha_alter_info, altered_table, old_table,
- ctx->new_table, user_table,
- add_cols, ctx->heap);
- ctx->add_cols = add_cols;
+ ctx->new_table, user_table, defaults, ctx->heap);
+ ctx->defaults = defaults;
} else {
DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info, old_table));
DBUG_ASSERT(old_table->s->primary_key
@@ -5490,7 +5541,8 @@ new_table_failed:
clust_index, ctx->new_table,
!(ha_alter_info->handler_flags
& ALTER_ADD_PK_INDEX),
- ctx->add_cols, ctx->col_map, path);
+ ctx->defaults, ctx->col_map, path,
+ ctx->ignore);
rw_lock_x_unlock(&clust_index->lock);
if (!ok) {
@@ -5548,7 +5600,7 @@ error_handling_drop_uncached:
ctx->prebuilt->trx,
index,
NULL, true, NULL, NULL,
- path);
+ path, ctx->ignore);
rw_lock_x_unlock(&index->lock);
if (!ok) {
@@ -6720,7 +6772,8 @@ err_exit:
add_fk, n_add_fk,
ha_alter_info->online,
heap, indexed_table,
- col_names, ULINT_UNDEFINED, 0, 0, 0);
+ col_names, ULINT_UNDEFINED, 0, 0, 0,
+ ha_alter_info->ignore);
}
DBUG_ASSERT(m_prebuilt->trx->dict_operation_lock_mode == 0);
@@ -6855,7 +6908,7 @@ found_col:
heap, m_prebuilt->table, col_names,
add_autoinc_col_no,
ha_alter_info->create_info->auto_increment_value,
- autoinc_col_max_value, 0);
+ autoinc_col_max_value, 0, ha_alter_info->ignore);
DBUG_RETURN(prepare_inplace_alter_table_dict(
ha_alter_info, altered_table, table,
@@ -7086,7 +7139,7 @@ ok_exit:
m_prebuilt->table, ctx->new_table,
ctx->online,
ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index,
- altered_table, ctx->add_cols, ctx->col_map,
+ altered_table, ctx->defaults, ctx->col_map,
ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort,
ctx->m_stage, add_v, eval_table,
ha_alter_info->handler_flags & ALTER_DROP_HISTORICAL);
diff --git a/storage/innobase/include/row0log.h b/storage/innobase/include/row0log.h
index df9920d9bcc..6974ce1b56b 100644
--- a/storage/innobase/include/row0log.h
+++ b/storage/innobase/include/row0log.h
@@ -55,12 +55,13 @@ row_log_allocate(
or NULL when creating a secondary index */
bool same_pk,/*!< in: whether the definition of the
PRIMARY KEY has remained the same */
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
/*!< in: default values of
- added columns, or NULL */
+ added, changed columns, or NULL */
const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */
- const char* path) /*!< in: where to create temporary file */
+ const char* path, /*!< in: where to create temporary file */
+ bool ignore) /*!< in: Whether alter ignore issued */
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/******************************************************//**
diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h
index 2fbc443dc21..207fb5b6564 100644
--- a/storage/innobase/include/row0merge.h
+++ b/storage/innobase/include/row0merge.h
@@ -308,7 +308,7 @@ old_table unless creating a PRIMARY KEY
@param[in] n_indexes size of indexes[]
@param[in,out] table MySQL table, for reporting erroneous key value
if applicable
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added, changed columns, or NULL
@param[in] col_map mapping of old column numbers to new ones, or
NULL if old_table == new_table
@param[in] add_autoinc number of added AUTO_INCREMENT columns, or
@@ -334,7 +334,7 @@ row_merge_build_indexes(
const ulint* key_numbers,
ulint n_indexes,
struct TABLE* table,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const ulint* col_map,
ulint add_autoinc,
ib_sequence_t& sequence,
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
index 4f329f0d675..90e35195365 100644
--- a/storage/innobase/include/row0row.h
+++ b/storage/innobase/include/row0row.h
@@ -153,9 +153,9 @@ row_build(
consulted instead; the user
columns in this table should be
the same columns as in index->table */
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
/*!< in: default values of
- added columns, or NULL */
+ added, changed columns, or NULL */
const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL */
row_ext_t** ext, /*!< out, own: cache of
@@ -177,7 +177,7 @@ addition of new virtual columns.
of an index, or NULL if
index->table should be
consulted instead
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added, changed columns, or NULL
@param[in] add_v new virtual columns added
along with new indexes
@param[in] col_map mapping of old column
@@ -194,7 +194,7 @@ row_build_w_add_vcol(
const rec_t* rec,
const ulint* offsets,
const dict_table_t* col_table,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const dict_add_v_col_t* add_v,
const ulint* col_map,
row_ext_t** ext,
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index 670367d42d4..9364f37890a 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -183,8 +183,9 @@ struct row_log_t {
index that is being created online */
bool same_pk;/*!< whether the definition of the PRIMARY KEY
has remained the same */
- const dtuple_t* add_cols;
- /*!< default values of added columns, or NULL */
+ const dtuple_t* defaults;
+ /*!< default values of added, changed columns,
+ or NULL */
const ulint* col_map;/*!< mapping of old column numbers to
new ones, or NULL if !table */
dberr_t error; /*!< error that occurred during online
@@ -220,6 +221,9 @@ struct row_log_t {
decryption or NULL */
const char* path; /*!< where to create temporary file during
log operation */
+ bool ignore; /*!< Whether the alter ignore is being used;
+ if not, NULL values will not be converted to
+ defaults */
};
/** Create the file or online log if it does not exist.
@@ -1151,7 +1155,9 @@ row_log_table_get_pk_col(
const ulint* offsets,
ulint i,
const page_size_t& page_size,
- ulint max_len)
+ ulint max_len,
+ bool ignore,
+ const dtuple_t* defaults)
{
const byte* field;
ulint len;
@@ -1159,7 +1165,12 @@ row_log_table_get_pk_col(
field = rec_get_nth_field(rec, offsets, i, &len);
if (len == UNIV_SQL_NULL) {
- return(DB_INVALID_NULL);
+ if (!ignore || !defaults->fields[i].data) {
+ return(DB_INVALID_NULL);
+ }
+
+ field = static_cast<const byte*>(defaults->fields[i].data);
+ len = defaults->fields[i].len;
}
if (rec_offs_nth_extern(offsets, i)) {
@@ -1323,7 +1334,8 @@ row_log_table_get_pk(
log->error = row_log_table_get_pk_col(
col, ifield, dfield, *heap,
- rec, offsets, i, page_size, max_len);
+ rec, offsets, i, page_size, max_len,
+ log->ignore, log->defaults);
if (log->error != DB_SUCCESS) {
err_exit:
@@ -1338,10 +1350,10 @@ err_exit:
/* No matching column was found in the old
table, so this must be an added column.
Copy the default value. */
- ut_ad(log->add_cols);
+ ut_ad(log->defaults);
dfield_copy(dfield, dtuple_get_nth_field(
- log->add_cols, col_no));
+ log->defaults, col_no));
mbminlen = dfield->type.mbminlen;
mbmaxlen = dfield->type.mbmaxlen;
prtype = dfield->type.prtype;
@@ -1512,8 +1524,8 @@ row_log_table_apply_convert_mrec(
*error = DB_SUCCESS;
/* This is based on row_build(). */
- if (log->add_cols) {
- row = dtuple_copy(log->add_cols, heap);
+ if (log->defaults) {
+ row = dtuple_copy(log->defaults, heap);
/* dict_table_copy_types() would set the fields to NULL */
for (ulint i = 0; i < dict_table_get_n_cols(log->table); i++) {
dict_col_copy_type(
@@ -1634,9 +1646,17 @@ blob_done:
if ((new_col->prtype & DATA_NOT_NULL)
&& dfield_is_null(dfield)) {
- /* We got a NULL value for a NOT NULL column. */
- *error = DB_INVALID_NULL;
- return(NULL);
+
+ const dfield_t& default_field
+ = log->defaults->fields[col_no];
+
+ if (!log->ignore || !default_field.data) {
+ /* We got a NULL value for a NOT NULL column. */
+ *error = DB_INVALID_NULL;
+ return NULL;
+ }
+
+ *dfield = default_field;
}
/* Adjust the DATA_NOT_NULL flag in the parsed row. */
@@ -3147,12 +3167,13 @@ row_log_allocate(
or NULL when creating a secondary index */
bool same_pk,/*!< in: whether the definition of the
PRIMARY KEY has remained the same */
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
/*!< in: default values of
- added columns, or NULL */
+ added, changed columns, or NULL */
const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */
- const char* path) /*!< in: where to create temporary file */
+ const char* path, /*!< in: where to create temporary file */
+ const bool ignore) /*!< in: alter ignore issued */
{
row_log_t* log;
DBUG_ENTER("row_log_allocate");
@@ -3162,7 +3183,7 @@ row_log_allocate(
ut_ad(!table || index->table != table);
ut_ad(same_pk || table);
ut_ad(!table || col_map);
- ut_ad(!add_cols || col_map);
+ ut_ad(!defaults || col_map);
ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_X));
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
ut_ad(trx->id);
@@ -3179,7 +3200,7 @@ row_log_allocate(
log->blobs = NULL;
log->table = table;
log->same_pk = same_pk;
- log->add_cols = add_cols;
+ log->defaults = defaults;
log->col_map = col_map;
log->error = DB_SUCCESS;
log->min_trx = trx->id;
@@ -3191,6 +3212,7 @@ row_log_allocate(
log->head.blocks = log->head.bytes = 0;
log->head.total = 0;
log->path = path;
+ log->ignore=ignore;
dict_index_set_online_status(index, ONLINE_INDEX_CREATION);
index->online_log = log;
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 264651bfaa3..669bbd59a0e 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -1656,7 +1656,7 @@ containing the index entries for the indexes to be built.
@param[in] files temporary files
@param[in] key_numbers MySQL key numbers to create
@param[in] n_index number of indexes to create
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added, changed columns, or NULL
@param[in] add_v newly added virtual columns along with indexes
@param[in] col_map mapping of old column numbers to new ones, or
NULL if old_table == new_table
@@ -1689,7 +1689,7 @@ row_merge_read_clustered_index(
merge_file_t* files,
const ulint* key_numbers,
ulint n_index,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const dict_add_v_col_t* add_v,
const ulint* col_map,
ulint add_autoinc,
@@ -1743,7 +1743,7 @@ row_merge_read_clustered_index(
DBUG_ENTER("row_merge_read_clustered_index");
ut_ad((old_table == new_table) == !col_map);
- ut_ad(!add_cols || col_map);
+ ut_ad(!defaults || col_map);
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
ut_ad(trx->id);
@@ -2187,19 +2187,26 @@ end_of_index:
row = row_build_w_add_vcol(ROW_COPY_POINTERS, clust_index,
rec, offsets, new_table,
- add_cols, add_v, col_map, &ext,
+ defaults, add_v, col_map, &ext,
row_heap);
ut_ad(row);
for (ulint i = 0; i < n_nonnull; i++) {
- const dfield_t* field = &row->fields[nonnull[i]];
+ dfield_t* field = &row->fields[nonnull[i]];
ut_ad(dfield_get_type(field)->prtype & DATA_NOT_NULL);
if (dfield_is_null(field)) {
- err = DB_INVALID_NULL;
- trx->error_key_num = 0;
- goto func_exit;
+ const dfield_t& default_field
+ = defaults->fields[nonnull[i]];
+
+ if (default_field.data == NULL) {
+ err = DB_INVALID_NULL;
+ trx->error_key_num = 0;
+ goto func_exit;
+ }
+
+ *field = default_field;
}
}
@@ -4548,7 +4555,7 @@ old_table unless creating a PRIMARY KEY
@param[in] n_indexes size of indexes[]
@param[in,out] table MySQL table, for reporting erroneous key value
if applicable
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added, changed columns, or NULL
@param[in] col_map mapping of old column numbers to new ones, or
NULL if old_table == new_table
@param[in] add_autoinc number of added AUTO_INCREMENT columns, or
@@ -4574,7 +4581,7 @@ row_merge_build_indexes(
const ulint* key_numbers,
ulint n_indexes,
struct TABLE* table,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const ulint* col_map,
ulint add_autoinc,
ib_sequence_t& sequence,
@@ -4610,7 +4617,7 @@ row_merge_build_indexes(
ut_ad(!srv_read_only_mode);
ut_ad((old_table == new_table) == !col_map);
- ut_ad(!add_cols || col_map);
+ ut_ad(!defaults || col_map);
stage->begin_phase_read_pk(skip_pk_sort && new_table != old_table
? n_indexes - 1
@@ -4744,7 +4751,7 @@ row_merge_build_indexes(
error = row_merge_read_clustered_index(
trx, table, old_table, new_table, online, indexes,
fts_sort_idx, psort_info, merge_files, key_numbers,
- n_indexes, add_cols, add_v, col_map, add_autoinc,
+ n_indexes, defaults, add_v, col_map, add_autoinc,
sequence, block, skip_pk_sort, &tmpfd, stage,
pct_cost, crypt_block, eval_table, drop_historical);
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index f9aa4fadacc..2664f8a3d9e 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -357,7 +357,7 @@ addition of new virtual columns.
of an index, or NULL if
index->table should be
consulted instead
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added/changed columns, or NULL
@param[in] add_v new virtual columns added
along with new indexes
@param[in] col_map mapping of old column
@@ -375,7 +375,7 @@ row_build_low(
const rec_t* rec,
const ulint* offsets,
const dict_table_t* col_table,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const dict_add_v_col_t* add_v,
const ulint* col_map,
row_ext_t** ext,
@@ -441,13 +441,13 @@ row_build_low(
if (!col_table) {
ut_ad(!col_map);
- ut_ad(!add_cols);
+ ut_ad(!defaults);
col_table = index->table;
}
- if (add_cols) {
+ if (defaults) {
ut_ad(col_map);
- row = dtuple_copy(add_cols, heap);
+ row = dtuple_copy(defaults, heap);
/* dict_table_copy_types() would set the fields to NULL */
for (ulint i = 0; i < dict_table_get_n_cols(col_table); i++) {
dict_col_copy_type(
@@ -594,9 +594,9 @@ row_build(
of an index, or NULL if
index->table should be
consulted instead */
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
/*!< in: default values of
- added columns, or NULL */
+ added and changed columns, or NULL */
const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL */
row_ext_t** ext, /*!< out, own: cache of
@@ -606,7 +606,7 @@ row_build(
the memory needed is allocated */
{
return(row_build_low(type, index, rec, offsets, col_table,
- add_cols, NULL, col_map, ext, heap));
+ defaults, NULL, col_map, ext, heap));
}
/** An inverse function to row_build_index_entry. Builds a row from a
@@ -622,7 +622,7 @@ addition of new virtual columns.
of an index, or NULL if
index->table should be
consulted instead
-@param[in] add_cols default values of added columns, or NULL
+@param[in] defaults default values of added, changed columns, or NULL
@param[in] add_v new virtual columns added
along with new indexes
@param[in] col_map mapping of old column
@@ -639,14 +639,14 @@ row_build_w_add_vcol(
const rec_t* rec,
const ulint* offsets,
const dict_table_t* col_table,
- const dtuple_t* add_cols,
+ const dtuple_t* defaults,
const dict_add_v_col_t* add_v,
const ulint* col_map,
row_ext_t** ext,
mem_heap_t* heap)
{
return(row_build_low(type, index, rec, offsets, col_table,
- add_cols, add_v, col_map, ext, heap));
+ defaults, add_v, col_map, ext, heap));
}
/** Convert an index record to a data tuple.