Commit 8c389393 authored by Daniel Black's avatar Daniel Black

MDEV-29540 Incorrect sequence values in INSERT SELECT

The population of default values in INSERT SELECT was being
performed twice. With sequences, this resulted in every
second sequence value being used.

With SELECT INSERT we remove the second invokation of
table->update_default_fields(). This was already performed
in store_values() invoking fill_record_n_invoke_before_triggers()
which invoked update_default_fields() previously.

We do need to return an error on duplicate values, so the
::store_values is extended to take the ignore option.
parent d6707ab1
...@@ -195,3 +195,105 @@ INSERT INTO t1 () values (); ...@@ -195,3 +195,105 @@ INSERT INTO t1 () values ();
EXECUTE stmt; EXECUTE stmt;
DROP TABLE t1; DROP TABLE t1;
DROP SEQUENCE s; DROP SEQUENCE s;
#
# MDEV-29540 Incorrect sequence values in INSERT SELECT
#
CREATE SEQUENCE s1;
CREATE TABLE t1 (
a BIGINT UNSIGNED NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR s1),
b CHAR(1) NOT NULL
);
INSERT INTO t1 (b) VALUES ('a');
INSERT INTO t1 (b) VALUES ('b'), ('c');
INSERT INTO t1 (b) VALUES ('d');
INSERT INTO t1 (b) SELECT c FROM (
SELECT 'e' as c
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
SELECT a, b FROM t1;
a b
1 a
2 b
3 c
4 d
5 e
6 f
7 g
ALTER SEQUENCE s1 RESTART;
INSERT INTO t1 (b) SELECT c FROM (
SELECT 'a' as c
UNION
SELECT 'b'
UNION
SELECT 'c'
UNION
SELECT 'd'
UNION
SELECT 'e'
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
ALTER SEQUENCE s1 RESTART;
INSERT IGNORE INTO t1 (b) SELECT c FROM (
SELECT 'a' as c
UNION
SELECT 'b'
UNION
SELECT 'c'
UNION
SELECT 'd'
UNION
SELECT 'e'
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
Warnings:
Warning 1062 Duplicate entry '1' for key 'PRIMARY'
Warning 1062 Duplicate entry '2' for key 'PRIMARY'
Warning 1062 Duplicate entry '3' for key 'PRIMARY'
Warning 1062 Duplicate entry '4' for key 'PRIMARY'
Warning 1062 Duplicate entry '5' for key 'PRIMARY'
Warning 1062 Duplicate entry '6' for key 'PRIMARY'
Warning 1062 Duplicate entry '7' for key 'PRIMARY'
SELECT a, b FROM t1;
a b
1 a
2 b
3 c
4 d
5 e
6 f
7 g
INSERT IGNORE INTO t1 (b) SELECT c FROM (
SELECT 'h' as c
UNION
SELECT 'i'
UNION
SELECT 'j'
) der;
SELECT a, b FROM t1;
a b
1 a
2 b
3 c
4 d
5 e
6 f
7 g
8 h
9 i
10 j
DROP TABLE t1;
DROP SEQUENCE s1;
#
# End of 10.3 tests
#
...@@ -135,3 +135,83 @@ EXECUTE stmt; ...@@ -135,3 +135,83 @@ EXECUTE stmt;
# Cleanup # Cleanup
DROP TABLE t1; DROP TABLE t1;
DROP SEQUENCE s; DROP SEQUENCE s;
--echo #
--echo # MDEV-29540 Incorrect sequence values in INSERT SELECT
--echo #
CREATE SEQUENCE s1;
CREATE TABLE t1 (
a BIGINT UNSIGNED NOT NULL PRIMARY KEY
DEFAULT (NEXT VALUE FOR s1),
b CHAR(1) NOT NULL
);
INSERT INTO t1 (b) VALUES ('a');
INSERT INTO t1 (b) VALUES ('b'), ('c');
INSERT INTO t1 (b) VALUES ('d');
INSERT INTO t1 (b) SELECT c FROM (
SELECT 'e' as c
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
SELECT a, b FROM t1;
ALTER SEQUENCE s1 RESTART;
--error ER_DUP_ENTRY
INSERT INTO t1 (b) SELECT c FROM (
SELECT 'a' as c
UNION
SELECT 'b'
UNION
SELECT 'c'
UNION
SELECT 'd'
UNION
SELECT 'e'
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
ALTER SEQUENCE s1 RESTART;
INSERT IGNORE INTO t1 (b) SELECT c FROM (
SELECT 'a' as c
UNION
SELECT 'b'
UNION
SELECT 'c'
UNION
SELECT 'd'
UNION
SELECT 'e'
UNION
SELECT 'f'
UNION
SELECT 'g'
) der;
SELECT a, b FROM t1;
INSERT IGNORE INTO t1 (b) SELECT c FROM (
SELECT 'h' as c
UNION
SELECT 'i'
UNION
SELECT 'j'
) der;
SELECT a, b FROM t1;
DROP TABLE t1;
DROP SEQUENCE s1;
--echo #
--echo # End of 10.3 tests
--echo #
...@@ -5455,7 +5455,7 @@ class select_insert :public select_result_interceptor { ...@@ -5455,7 +5455,7 @@ class select_insert :public select_result_interceptor {
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
virtual int prepare2(JOIN *join); virtual int prepare2(JOIN *join);
virtual int send_data(List<Item> &items); virtual int send_data(List<Item> &items);
virtual void store_values(List<Item> &values); virtual bool store_values(List<Item> &values, bool ignore_errors);
virtual bool can_rollback_data() { return 0; } virtual bool can_rollback_data() { return 0; }
bool prepare_eof(); bool prepare_eof();
bool send_ok_packet(); bool send_ok_packet();
...@@ -5497,7 +5497,7 @@ class select_create: public select_insert { ...@@ -5497,7 +5497,7 @@ class select_create: public select_insert {
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int binlog_show_create_table(TABLE **tables, uint count); int binlog_show_create_table(TABLE **tables, uint count);
void store_values(List<Item> &values); bool store_values(List<Item> &values, bool ignore_errors);
bool send_eof(); bool send_eof();
virtual void abort_result_set(); virtual void abort_result_set();
virtual bool can_rollback_data() { return 1; } virtual bool can_rollback_data() { return 1; }
......
...@@ -3928,9 +3928,7 @@ int select_insert::send_data(List<Item> &values) ...@@ -3928,9 +3928,7 @@ int select_insert::send_data(List<Item> &values)
DBUG_RETURN(0); DBUG_RETURN(0);
thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields
store_values(values); if (store_values(values, info.ignore))
if (table->default_field &&
unlikely(table->update_default_fields(info.ignore)))
DBUG_RETURN(1); DBUG_RETURN(1);
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
if (unlikely(thd->is_error())) if (unlikely(thd->is_error()))
...@@ -3988,18 +3986,19 @@ int select_insert::send_data(List<Item> &values) ...@@ -3988,18 +3986,19 @@ int select_insert::send_data(List<Item> &values)
} }
void select_insert::store_values(List<Item> &values) bool select_insert::store_values(List<Item> &values, bool ignore_errors)
{ {
DBUG_ENTER("select_insert::store_values"); DBUG_ENTER("select_insert::store_values");
bool error;
if (fields->elements) if (fields->elements)
fill_record_n_invoke_before_triggers(thd, table, *fields, values, 1, error= fill_record_n_invoke_before_triggers(thd, table, *fields, values,
TRG_EVENT_INSERT); ignore_errors, TRG_EVENT_INSERT);
else else
fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(), error= fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(),
values, 1, TRG_EVENT_INSERT); values, ignore_errors, TRG_EVENT_INSERT);
DBUG_VOID_RETURN; DBUG_RETURN(error);
} }
bool select_insert::prepare_eof() bool select_insert::prepare_eof()
...@@ -4670,10 +4669,10 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) ...@@ -4670,10 +4669,10 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
return result; return result;
} }
void select_create::store_values(List<Item> &values) bool select_create::store_values(List<Item> &values, bool ignore_errors)
{ {
fill_record_n_invoke_before_triggers(thd, table, field, values, 1, return fill_record_n_invoke_before_triggers(thd, table, field, values,
TRG_EVENT_INSERT); ignore_errors, TRG_EVENT_INSERT);
} }
......
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