MDEV-16365 Setting a column NOT NULL fails to return error for

		NULL values when there is no DEFAULT

Copy and inplace algorithm works similarly for
NULL to NOT NULL conversion for the following cases:
(1) strict sql mode - Should give error.
(2) non-strict sql mode - Should give warnings alone
(3) alter ignore table command. - Should give warnings alone.
parent 1abd877e
...@@ -1150,6 +1150,7 @@ alter table t1 change column a a int; ...@@ -1150,6 +1150,7 @@ alter table t1 change column a a int;
analyze table t1; analyze table t1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t1 analyze status OK test.t1 analyze status OK
flush table t1; flush table t1;
explain extended select * from t1 where a between 5 and 7; explain extended select * from t1 where a between 5 and 7;
......
...@@ -1086,6 +1086,9 @@ test t2 idx4 3 1.1304 ...@@ -1086,6 +1086,9 @@ test t2 idx4 3 1.1304
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t2 analyze status Engine-independent statistics collected test.t2 analyze status Engine-independent statistics collected
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze status OK test.t2 analyze status OK
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
db_name table_name index_name prefix_arity avg_frequency db_name table_name index_name prefix_arity avg_frequency
...@@ -1146,6 +1149,11 @@ test t2 idx4 4 1.0000 ...@@ -1146,6 +1149,11 @@ test t2 idx4 4 1.0000
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL; ANALYZE TABLE t2 PERSISTENT FOR COLUMNS ALL INDEXES ALL;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t2 analyze status Engine-independent statistics collected test.t2 analyze status Engine-independent statistics collected
test.t2 analyze Note Data truncated for column 'avg_length' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze status OK test.t2 analyze status OK
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
db_name table_name index_name prefix_arity avg_frequency db_name table_name index_name prefix_arity avg_frequency
...@@ -1171,6 +1179,8 @@ test t2 idx3 1 8.5000 ...@@ -1171,6 +1179,8 @@ test t2 idx3 1 8.5000
ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL; ANALYZE TABLE t2 PERSISTENT FOR COLUMNS() INDEXES ALL;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t2 analyze status Engine-independent statistics collected test.t2 analyze status Engine-independent statistics collected
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze Note Data truncated for column 'avg_frequency' at row 1
test.t2 analyze status OK test.t2 analyze status OK
SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name; SELECT * FROM mysql.index_stats ORDER BY index_name, prefix_arity, table_name;
db_name table_name index_name prefix_arity avg_frequency db_name table_name index_name prefix_arity avg_frequency
......
...@@ -691,9 +691,13 @@ a b c ...@@ -691,9 +691,13 @@ a b c
1 127 0 1 127 0
SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
ALTER TABLE t ADD UNIQUE INDEX (c(1)); ALTER TABLE t ADD UNIQUE INDEX (c(1));
Warnings:
Warning 1264 Out of range value for column 'b' at row 1
SELECT * FROM t WHERE c = '0'; SELECT * FROM t WHERE c = '0';
a b c a b c
1 127 0 1 127 0
Warnings:
Warning 1264 Out of range value for column 'b' at row 1
DROP TABLE t; DROP TABLE t;
# #
# Bug#21688115 VIRTUAL COLUMN COMPUTATION SAVE_IN_FIELD() # Bug#21688115 VIRTUAL COLUMN COMPUTATION SAVE_IN_FIELD()
......
--source include/have_innodb.inc
CREATE TABLE t1(f1 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE f1 f1 INT NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 CHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE f1 f1 CHAR(10) NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 VARCHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE f1 f1 VARCHAR(20) NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 TEXT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE f1 f1 TEXT NOT NULL DEFAULT 'abc';
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, f3 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(2, 2, NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2);
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL DEFAULT 0, b TINYINT)ENGINE=InnoDB;
INSERT INTO t1 VALUES(10, NULL);
SELECT * FROM t1;
--enable_info
--error $error_code
ALTER TABLE t1 CHANGE b b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0);
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
# Alter ignore should work irrespective of sql mode
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL);
--enable_info
ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
...@@ -2,66 +2,61 @@ ...@@ -2,66 +2,61 @@
--source include/have_debug.inc --source include/have_debug.inc
--source include/have_debug_sync.inc --source include/have_debug_sync.inc
# Alter table should fail for strict sql mode
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB; CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL); INSERT INTO t1 VALUES(1, 1);
--enable_info
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
send ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE; send ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
connect (con1,localhost,root); connect (con1,localhost,root);
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
INSERT INTO t1 VALUES(2, NULL); INSERT INTO t1 VALUES(2, NULL);
UPDATE t1 SET c1 = 3 WHERE c2 = 1;
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
connection default; connection default;
--error ER_INVALID_USE_OF_NULL --error $error_code
reap; reap;
--disable_info
SELECT * FROM t1; SELECT * FROM t1;
UPDATE t1 SET c2 = 0 WHERE c1 = 2; DROP TABLE t1;
# Alter table should successfully apply the log for the alter operation
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, 1);
--enable_info
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
--echo # Alter ignore can convert the NULL values from send ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
--echo # CONCURRENT DML to constants
send ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE;
connection con1; connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
UPDATE t1 SET c2 = NULL WHERE c1 = 2; INSERT INTO t1 VALUES(2, 3);
INSERT INTO t1 VALUES (3, NULL); UPDATE t1 SET c1 = 3 WHERE c2 = 1;
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
connection default; connection default;
reap; reap;
--disable_info
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
# Alter ignore should not give error
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, c3 INT, PRIMARY KEY(c1))ENGINE=INNODB; CREATE TABLE t1(c1 INT NOT NULL, c2 INT, c3 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL, NULL); INSERT INTO t1 VALUES(1, 2, 3);
--enable_info
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
--echo # Alter Successfully converts from null to not null send ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
send ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE;
connection con1; connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
UPDATE t1 SET c2= 2 WHERE c1 = 1; UPDATE t1 SET c2= 2 WHERE c1 = 1;
INSERT INTO t1 VALUES (2, 3, 4); INSERT INTO t1 VALUES (2, NULL, 4);
SET DEBUG_SYNC= 'now SIGNAL flushed';
connection default;
reap;
SELECT * FROM t1;
SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed';
--echo # Alter fails because concurrent dml inserts null value
send ALTER TABLE t1 CHANGE c3 c3 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE;
connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened';
UPDATE t1 SET c3= 2 WHERE c1 = 2;
INSERT INTO t1 VALUES (4, 3, NULL);
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
connection default; connection default;
--error ER_INVALID_USE_OF_NULL
reap; reap;
--disable_info
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
disconnect con1; disconnect con1;
......
7,8c7,8
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
21,22c21,22
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
35,36c35,36
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
49,50c49,50
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
63,64c63,64
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
77,78c77,78
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
88,89c88,89
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
7,10c7
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
13c10
< 0
---
> NULL
21,24c18
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
27c21
<
---
> NULL
35,38c29
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
41c32
<
---
> NULL
49,52c40
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
55c43
<
---
> NULL
63,66c51
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f3' at row 1
---
> ERROR 01000: Data truncated for column 'f3' at row 1
69c54
< 2 2 0
---
> 2 2 NULL
77,80c62
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'b' at row 1
---
> ERROR 01000: Data truncated for column 'b' at row 1
83c65
< 10 0
---
> 10 NULL
88,89c70,71
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
---
> affected rows: 1
> info: Records: 1 Duplicates: 0 Warnings: 1
7,10c7
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
13c10
< 0
---
> NULL
21,24c18
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
27c21
<
---
> NULL
35,38c29
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
41c32
<
---
> NULL
49,52c40
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f1' at row 1
---
> ERROR 01000: Data truncated for column 'f1' at row 1
55c43
<
---
> NULL
63,66c51
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'f3' at row 1
---
> ERROR 01000: Data truncated for column 'f3' at row 1
69c54
< 2 2 0
---
> 2 2 NULL
77,80c62
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'b' at row 1
---
> ERROR 01000: Data truncated for column 'b' at row 1
83c65
< 10 0
---
> 10 NULL
CREATE TABLE t1(f1 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 INT NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
SELECT * FROM t1;
f1
0
DROP TABLE t1;
CREATE TABLE t1(f1 CHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 CHAR(10) NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
SELECT * FROM t1;
f1
DROP TABLE t1;
CREATE TABLE t1(f1 VARCHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 VARCHAR(20) NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
SELECT * FROM t1;
f1
DROP TABLE t1;
CREATE TABLE t1(f1 TEXT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 TEXT NOT NULL DEFAULT 'abc';
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'f1' at row 1
SELECT * FROM t1;
f1
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, f3 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(2, 2, NULL);
SELECT * FROM t1;
f1 f2 f3
2 2 NULL
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2);
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'f3' at row 1
SELECT * FROM t1;
f1 f2 f3
2 2 0
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL DEFAULT 0, b TINYINT)ENGINE=InnoDB;
INSERT INTO t1 VALUES(10, NULL);
SELECT * FROM t1;
f1 b
10 NULL
ALTER TABLE t1 CHANGE b b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0);
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'b' at row 1
SELECT * FROM t1;
f1 b
10 0
DROP TABLE t1;
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL);
ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'c2' at row 1
SELECT * FROM t1;
c1 c2
1 0
DROP TABLE t1;
18,21c18
< affected rows: 0
< info: Records: 0 Duplicates: 0 Warnings: 1
< Warnings:
< Warning 1265 Data truncated for column 'c2' at row 3
---
> ERROR 01000: Data truncated for column 'c2' at row 3
24c21
< 2 0
---
> 2 NULL
71c68
< Warning 1265 Data truncated for column 'c2' at row 7
---
> Warning 1265 Data truncated for column 'c2' at row 6
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB; CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL); INSERT INTO t1 VALUES(1, 1);
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE; affected rows: 0
ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
connect con1,localhost,root; connect con1,localhost,root;
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
affected rows: 0
INSERT INTO t1 VALUES(2, NULL); INSERT INTO t1 VALUES(2, NULL);
affected rows: 1
UPDATE t1 SET c1 = 3 WHERE c2 = 1;
affected rows: 1
info: Rows matched: 1 Changed: 1 Warnings: 0
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
affected rows: 0
connection default; connection default;
ERROR 22004: Invalid use of NULL value affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'c2' at row 3
SELECT * FROM t1; SELECT * FROM t1;
c1 c2 c1 c2
1 NULL 2 0
2 NULL 3 1
UPDATE t1 SET c2 = 0 WHERE c1 = 2; DROP TABLE t1;
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, 1);
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
# Alter ignore can convert the NULL values from affected rows: 0
# CONCURRENT DML to constants ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE;
connection con1; connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
UPDATE t1 SET c2 = NULL WHERE c1 = 2; affected rows: 0
INSERT INTO t1 VALUES (3, NULL); INSERT INTO t1 VALUES(2, 3);
affected rows: 1
UPDATE t1 SET c1 = 3 WHERE c2 = 1;
affected rows: 1
info: Rows matched: 1 Changed: 1 Warnings: 0
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
affected rows: 0
connection default; connection default;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1; SELECT * FROM t1;
c1 c2 c1 c2
1 2 2 3
2 2 3 1
3 2
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1(c1 INT NOT NULL, c2 INT, c3 INT, PRIMARY KEY(c1))ENGINE=INNODB; CREATE TABLE t1(c1 INT NOT NULL, c2 INT, c3 INT, PRIMARY KEY(c1))ENGINE=INNODB;
INSERT INTO t1 VALUES(1, NULL, NULL); INSERT INTO t1 VALUES(1, 2, 3);
SET DEBUG_SYNC= 'row_merge_after_scan SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed'; SIGNAL opened WAIT_FOR flushed';
# Alter Successfully converts from null to not null affected rows: 0
ALTER TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE; ALTER IGNORE TABLE t1 CHANGE c2 c2 INT NOT NULL DEFAULT 2;
connection con1; connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET DEBUG_SYNC= 'now WAIT_FOR opened';
affected rows: 0
UPDATE t1 SET c2= 2 WHERE c1 = 1; UPDATE t1 SET c2= 2 WHERE c1 = 1;
INSERT INTO t1 VALUES (2, 3, 4); affected rows: 0
SET DEBUG_SYNC= 'now SIGNAL flushed'; info: Rows matched: 1 Changed: 0 Warnings: 0
connection default; INSERT INTO t1 VALUES (2, NULL, 4);
SELECT * FROM t1; affected rows: 1
c1 c2 c3
1 2 NULL
2 3 4
SET DEBUG_SYNC= 'row_merge_after_scan
SIGNAL opened WAIT_FOR flushed';
# Alter fails because concurrent dml inserts null value
ALTER TABLE t1 CHANGE c3 c3 INT NOT NULL DEFAULT 2, ALGORITHM=INPLACE;
connection con1;
SET DEBUG_SYNC= 'now WAIT_FOR opened';
UPDATE t1 SET c3= 2 WHERE c1 = 2;
INSERT INTO t1 VALUES (4, 3, NULL);
SET DEBUG_SYNC= 'now SIGNAL flushed'; SET DEBUG_SYNC= 'now SIGNAL flushed';
affected rows: 0
connection default; connection default;
ERROR 22004: Invalid use of NULL value affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'c2' at row 7
SELECT * FROM t1; SELECT * FROM t1;
c1 c2 c3 c1 c2 c3
1 2 NULL 1 2 3
2 3 2 2 0 4
4 3 NULL
DROP TABLE t1; DROP TABLE t1;
disconnect con1; disconnect con1;
SET DEBUG_SYNC='RESET'; SET DEBUG_SYNC='RESET';
set @@sql_mode = 'STRICT_TRANS_TABLES'; set @@sql_mode = 'STRICT_TRANS_TABLES';
CREATE TABLE t1(f1 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 INT NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
f1
0
DROP TABLE t1;
CREATE TABLE t1(f1 CHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 CHAR(10) NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
f1
DROP TABLE t1;
CREATE TABLE t1(f1 VARCHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 VARCHAR(20) NOT NULL;
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
f1
DROP TABLE t1;
CREATE TABLE t1(f1 TEXT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
f1
NULL
ALTER TABLE t1 CHANGE f1 f1 TEXT NOT NULL DEFAULT 'abc';
affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
f1
abc
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, f3 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(2, 2, NULL);
SELECT * FROM t1;
f1 f2 f3
2 2 NULL
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2), ALGORITHM=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: cannot convert NULL to non-constant DEFAULT. Try ALGORITHM=COPY
UPDATE t1 SET f3 = 0;
SELECT * FROM t1;
f1 f2 f3
2 2 0
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2);
affected rows: 1
info: Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM t1;
f1 f2 f3
2 2 0
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL DEFAULT 0, b TINYINT)ENGINE=InnoDB;
INSERT INTO t1 VALUES(10, NULL);
SELECT * FROM t1;
f1 b
10 NULL
ALTER TABLE t1 CHANGE b b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0), algorithm=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: cannot convert NULL to non-constant DEFAULT. Try ALGORITHM=COPY
DROP TABLE t1;
CREATE TABLE t1(a INT, v INT AS (a), c INT, d INT NOT NULL, e INT) ENGINE=InnoDB; CREATE TABLE t1(a INT, v INT AS (a), c INT, d INT NOT NULL, e INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP COLUMN c, CHANGE COLUMN e e INT NOT NULL, ALGORITHM=INPLACE; ALTER TABLE t1 DROP COLUMN c, CHANGE COLUMN e e INT NOT NULL, ALGORITHM=INPLACE;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -2,16 +2,18 @@ CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb; ...@@ -2,16 +2,18 @@ CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES(NULL);
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(), ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=INPLACE; ALGORITHM=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: cannot convert NULL to non-constant DEFAULT. Try ALGORITHM=COPY ERROR 01000: Data truncated for column 'i1' at row 1
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(), ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=COPY; ALGORITHM=COPY;
ERROR 01000: Data truncated for column 'i1' at row 1 ERROR 01000: Data truncated for column 'i1' at row 1
ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT, ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY(id), ALGORITHM=INPLACE; ADD PRIMARY KEY(id), ALGORITHM=INPLACE;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY 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; ALTER IGNORE TABLE t1 ADD PRIMARY KEY(i1), ALGORITHM=INPLACE;
affected rows: 0 affected rows: 0
info: Records: 0 Duplicates: 0 Warnings: 0 info: Records: 0 Duplicates: 0 Warnings: 1
Warnings:
Warning 1265 Data truncated for column 'i1' at row 1
ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT; ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT;
affected rows: 1 affected rows: 1
info: Records: 1 Duplicates: 0 Warnings: 0 info: Records: 1 Duplicates: 0 Warnings: 0
......
...@@ -409,7 +409,7 @@ ALTER TABLE t1 DROP COLUMN c22f, ADD PRIMARY KEY c3p5(c3(5)); ...@@ -409,7 +409,7 @@ ALTER TABLE t1 DROP COLUMN c22f, ADD PRIMARY KEY c3p5(c3(5));
ERROR 42000: Key column 'c22f' doesn't exist in table ERROR 42000: Key column 'c22f' doesn't exist in table
SET @old_sql_mode = @@sql_mode; SET @old_sql_mode = @@sql_mode;
SET @@sql_mode = 'STRICT_TRANS_TABLES'; SET @@sql_mode = 'STRICT_TRANS_TABLES';
ALTER TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)), ALTER IGNORE TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)),
ALGORITHM = INPLACE; ALGORITHM = INPLACE;
ERROR 23000: Duplicate entry '' for key 'PRIMARY' ERROR 23000: Duplicate entry '' for key 'PRIMARY'
SET @@sql_mode = @old_sql_mode; SET @@sql_mode = @old_sql_mode;
...@@ -428,7 +428,7 @@ INSERT INTO t1 VALUES(33101,347,NULL,''); ...@@ -428,7 +428,7 @@ INSERT INTO t1 VALUES(33101,347,NULL,'');
SET DEBUG_SYNC = 'now SIGNAL ins_done0'; SET DEBUG_SYNC = 'now SIGNAL ins_done0';
# session con1 # session con1
connection con1; connection con1;
ERROR 22004: Invalid use of NULL value ERROR 01000: Data truncated for column 'c3' at row 1
SET @@sql_mode = @old_sql_mode; SET @@sql_mode = @old_sql_mode;
# session default # session default
connection default; connection default;
......
[COPY]
--alter_algorithm=copy
[INPLACE]
--alter_algorithm=inplace
# See also alter_non_null.combinations
--source include/have_innodb.inc
--source alter_sql_mode.inc
let $sql_mode = `SELECT @@SQL_MODE`;
let $error_code = 0;
if ($sql_mode == "STRICT_TRANS_TABLES") {
let $error_code = WARN_DATA_TRUNCATED;
}
--source include/alter_non_null.inc
--source alter_sql_mode.inc
let $sql_mode = `SELECT @@SQL_MODE`;
let $error_code = 0;
if ($sql_mode == "STRICT_TRANS_TABLES") {
let $error_code = WARN_DATA_TRUNCATED;
}
--source include/alter_non_null_debug.inc
--source include/have_innodb.inc --source include/have_innodb.inc
set @@sql_mode = 'STRICT_TRANS_TABLES'; set @@sql_mode = 'STRICT_TRANS_TABLES';
CREATE TABLE t1(f1 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
ALTER TABLE t1 CHANGE f1 f1 INT NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 CHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
ALTER TABLE t1 CHANGE f1 f1 CHAR(10) NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 VARCHAR(10))ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
ALTER TABLE t1 CHANGE f1 f1 VARCHAR(20) NOT NULL;
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 TEXT)ENGINE=INNODB;
INSERT INTO t1 VALUES(NULL);
SELECT * FROM t1;
--enable_info
ALTER TABLE t1 CHANGE f1 f1 TEXT NOT NULL DEFAULT 'abc';
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL, f3 INT)ENGINE=INNODB;
INSERT INTO t1 VALUES(2, 2, NULL);
SELECT * FROM t1;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2), ALGORITHM=INPLACE;
UPDATE t1 SET f3 = 0;
SELECT * FROM t1;
--enable_info
ALTER TABLE t1 CHANGE f3 f3 INT NOT NULL DEFAULT (f1 + f2);
--disable_info
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1(f1 INT NOT NULL DEFAULT 0, b TINYINT)ENGINE=InnoDB;
INSERT INTO t1 VALUES(10, NULL);
SELECT * FROM t1;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 CHANGE b b TINYINT NOT NULL DEFAULT if(unix_timestamp()>1,1000,0), algorithm=INPLACE;
DROP TABLE t1;
CREATE TABLE t1(a INT, v INT AS (a), c INT, d INT NOT NULL, e INT) ENGINE=InnoDB; CREATE TABLE t1(a INT, v INT AS (a), c INT, d INT NOT NULL, e INT) ENGINE=InnoDB;
ALTER TABLE t1 DROP COLUMN c, CHANGE COLUMN e e INT NOT NULL, ALGORITHM=INPLACE; ALTER TABLE t1 DROP COLUMN c, CHANGE COLUMN e e INT NOT NULL, ALGORITHM=INPLACE;
DROP TABLE t1; DROP TABLE t1;
......
[STRICT]
--sql_mode=STRICT_TRANS_TABLES
[NON-STRICT]
--sql_mode=
# See also alter_sql_mode.combinations
--source include/have_innodb.inc
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb; CREATE TABLE t1 (i1 INT UNSIGNED NULL DEFAULT 42) ENGINE=innodb;
INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES(NULL);
--enable_info --enable_info
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON --error WARN_DATA_TRUNCATED
ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(), ALTER TABLE t1 CHANGE i1 i1 INT UNSIGNED NOT NULL DEFAULT rand(),
ALGORITHM=INPLACE; ALGORITHM=INPLACE;
--error WARN_DATA_TRUNCATED --error WARN_DATA_TRUNCATED
...@@ -12,7 +12,7 @@ ALGORITHM=COPY; ...@@ -12,7 +12,7 @@ ALGORITHM=COPY;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON --error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT, ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY(id), ALGORITHM=INPLACE; ADD PRIMARY KEY(id), ALGORITHM=INPLACE;
ALTER TABLE t1 ADD PRIMARY KEY(i1), ALGORITHM=INPLACE; ALTER IGNORE TABLE t1 ADD PRIMARY KEY(i1), ALGORITHM=INPLACE;
ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT; ALTER TABLE t1 CHANGE i1 id INT UNSIGNED NOT NULL AUTO_INCREMENT;
--disable_info --disable_info
SELECT * FROM t1; SELECT * FROM t1;
......
...@@ -359,7 +359,7 @@ SET @old_sql_mode = @@sql_mode; ...@@ -359,7 +359,7 @@ SET @old_sql_mode = @@sql_mode;
# And adding a PRIMARY KEY will also add NOT NULL implicitly! # And adding a PRIMARY KEY will also add NOT NULL implicitly!
SET @@sql_mode = 'STRICT_TRANS_TABLES'; SET @@sql_mode = 'STRICT_TRANS_TABLES';
--error ER_DUP_ENTRY --error ER_DUP_ENTRY
ALTER TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)), ALTER IGNORE TABLE t1 DROP COLUMN c22f, DROP PRIMARY KEY, ADD PRIMARY KEY c3p5(c3(5)),
ALGORITHM = INPLACE; ALGORITHM = INPLACE;
SET @@sql_mode = @old_sql_mode; SET @@sql_mode = @old_sql_mode;
...@@ -384,7 +384,7 @@ SET DEBUG_SYNC = 'now SIGNAL ins_done0'; ...@@ -384,7 +384,7 @@ SET DEBUG_SYNC = 'now SIGNAL ins_done0';
--echo # session con1 --echo # session con1
connection con1; connection con1;
--error ER_INVALID_USE_OF_NULL --error WARN_DATA_TRUNCATED
reap; reap;
SET @@sql_mode = @old_sql_mode; SET @@sql_mode = @old_sql_mode;
......
...@@ -11135,6 +11135,7 @@ uint32 Field_blob::max_display_length() const ...@@ -11135,6 +11135,7 @@ uint32 Field_blob::max_display_length() const
@param level - level of message (Note/Warning/Error) @param level - level of message (Note/Warning/Error)
@param code - error code of message to be produced @param code - error code of message to be produced
@param cut_increment - whenever we should increase cut fields count @param cut_increment - whenever we should increase cut fields count
@current_row - current row number
@note @note
This function won't produce warning or notes or increase cut fields counter This function won't produce warning or notes or increase cut fields counter
...@@ -11152,7 +11153,7 @@ uint32 Field_blob::max_display_length() const ...@@ -11152,7 +11153,7 @@ uint32 Field_blob::max_display_length() const
bool bool
Field::set_warning(Sql_condition::enum_warning_level level, uint code, Field::set_warning(Sql_condition::enum_warning_level level, uint code,
int cut_increment) const int cut_increment, ulong current_row) const
{ {
/* /*
If this field was created only for type conversion purposes it If this field was created only for type conversion purposes it
...@@ -11163,7 +11164,8 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code, ...@@ -11163,7 +11164,8 @@ Field::set_warning(Sql_condition::enum_warning_level level, uint code,
{ {
thd->cuted_fields+= cut_increment; thd->cuted_fields+= cut_increment;
push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str, push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str,
thd->get_stmt_da()->current_row_for_warning()); current_row ? current_row
: thd->get_stmt_da()->current_row_for_warning());
return 0; return 0;
} }
return level >= Sql_condition::WARN_LEVEL_WARN; return level >= Sql_condition::WARN_LEVEL_WARN;
......
...@@ -1368,7 +1368,7 @@ class Field: public Value_source ...@@ -1368,7 +1368,7 @@ class Field: public Value_source
virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; }
virtual int set_time() { return 1; } virtual int set_time() { return 1; }
bool set_warning(Sql_condition::enum_warning_level, unsigned int code, bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
int cuted_increment) const; int cuted_increment, ulong current_row=0) const;
protected: protected:
bool set_warning(unsigned int code, int cuted_increment) const bool set_warning(unsigned int code, int cuted_increment) const
{ {
......
...@@ -7412,6 +7412,11 @@ static bool mysql_inplace_alter_table(THD *thd, ...@@ -7412,6 +7412,11 @@ static bool mysql_inplace_alter_table(THD *thd,
bool reopen_tables= false; bool reopen_tables= false;
bool res; bool res;
/*
Set the truncated column values of thd as warning
for alter table.
*/
thd->count_cuted_fields = CHECK_FIELD_WARN;
DBUG_ENTER("mysql_inplace_alter_table"); DBUG_ENTER("mysql_inplace_alter_table");
/* /*
......
...@@ -203,8 +203,12 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx ...@@ -203,8 +203,12 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
/** original column names of the table */ /** original column names of the table */
const char* const old_col_names; const char* const old_col_names;
/** Whether alter ignore issued. */ /** Allow non-null conversion.
const bool ignore; (1) Alter ignore should allow the conversion
irrespective of sql mode.
(2) Don't allow the conversion in strict mode
(3) Allow the conversion only in non-strict mode. */
const bool allow_not_null;
ha_innobase_inplace_ctx(row_prebuilt_t*& prebuilt_arg, ha_innobase_inplace_ctx(row_prebuilt_t*& prebuilt_arg,
dict_index_t** drop_arg, dict_index_t** drop_arg,
...@@ -222,7 +226,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx ...@@ -222,7 +226,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
ulint add_autoinc_arg, ulint add_autoinc_arg,
ulonglong autoinc_col_min_value_arg, ulonglong autoinc_col_min_value_arg,
ulonglong autoinc_col_max_value_arg, ulonglong autoinc_col_max_value_arg,
bool ignore_flag) : bool allow_not_null_flag) :
inplace_alter_handler_ctx(), inplace_alter_handler_ctx(),
prebuilt (prebuilt_arg), prebuilt (prebuilt_arg),
add_index (0), add_key_numbers (0), num_to_add_index (0), add_index (0), add_key_numbers (0), num_to_add_index (0),
...@@ -250,7 +254,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx ...@@ -250,7 +254,7 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
old_n_cols(prebuilt_arg->table->n_cols), old_n_cols(prebuilt_arg->table->n_cols),
old_cols(prebuilt_arg->table->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) allow_not_null(allow_not_null_flag)
{ {
ut_ad(old_n_cols >= DATA_N_SYS_COLS); ut_ad(old_n_cols >= DATA_N_SYS_COLS);
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
...@@ -919,18 +923,6 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -919,18 +923,6 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_INSTANT); DBUG_RETURN(HA_ALTER_INPLACE_INSTANT);
} }
/* Only support NULL -> NOT NULL change if strict table sql_mode
is set. Fall back to COPY for conversion if not strict tables.
In-Place will fail with an error when trying to convert
NULL to a NOT NULL value. */
if ((ha_alter_info->handler_flags
& ALTER_COLUMN_NOT_NULLABLE)
&& !thd_is_strict_mode(m_user_thd)) {
ha_alter_info->unsupported_reason = my_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
/* DROP PRIMARY KEY is only allowed in combination with ADD /* DROP PRIMARY KEY is only allowed in combination with ADD
PRIMARY KEY. */ PRIMARY KEY. */
if ((ha_alter_info->handler_flags if ((ha_alter_info->handler_flags
...@@ -1253,20 +1245,6 @@ ha_innobase::check_if_supported_inplace_alter( ...@@ -1253,20 +1245,6 @@ ha_innobase::check_if_supported_inplace_alter(
} }
break; break;
default: 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 /* For any other data type, NULL
values are not converted. values are not converted.
(An AUTO_INCREMENT attribute cannot (An AUTO_INCREMENT attribute cannot
...@@ -3252,20 +3230,23 @@ innobase_check_foreigns( ...@@ -3252,20 +3230,23 @@ innobase_check_foreigns(
} }
/** Convert a default value for ADD COLUMN. /** Convert a default value for ADD COLUMN.
@param[in,out] heap Memory heap where allocated
@param heap Memory heap where allocated @param[out] dfield InnoDB data field to copy to
@param dfield InnoDB data field to copy to @param[in] field MySQL value for the column
@param field MySQL value for the column @param[in] old_field Old field or NULL if new col is added
@param comp nonzero if in compact format */ @param[in] comp nonzero if in compact format. */
static MY_ATTRIBUTE((nonnull)) static void innobase_build_col_map_add(
void
innobase_build_col_map_add(
/*=======================*/
mem_heap_t* heap, mem_heap_t* heap,
dfield_t* dfield, dfield_t* dfield,
const Field* field, const Field* field,
const Field* old_field,
ulint comp) ulint comp)
{ {
if (old_field && old_field->real_maybe_null()
&& field->real_maybe_null()) {
return;
}
if (field->is_real_null()) { if (field->is_real_null()) {
dfield_set_null(dfield); dfield_set_null(dfield);
return; return;
...@@ -3275,7 +3256,7 @@ innobase_build_col_map_add( ...@@ -3275,7 +3256,7 @@ innobase_build_col_map_add(
byte* buf = static_cast<byte*>(mem_heap_alloc(heap, size)); byte* buf = static_cast<byte*>(mem_heap_alloc(heap, size));
const byte* mysql_data = field->ptr; const byte* mysql_data = old_field ? old_field->ptr : field->ptr;
row_mysql_store_col_in_innobase_format( row_mysql_store_col_in_innobase_format(
dfield, buf, true, mysql_data, size, comp); dfield, buf, true, mysql_data, size, comp);
...@@ -3362,16 +3343,15 @@ innobase_build_col_map( ...@@ -3362,16 +3343,15 @@ innobase_build_col_map(
const Field* altered_field = const Field* altered_field =
altered_table->field[i + num_v]; altered_table->field[i + num_v];
if (field->real_maybe_null() if (defaults) {
&& !altered_field->real_maybe_null()) {
/* Don't consider virtual column.
NULL to NOT NULL is not applicable
for virtual column. */
innobase_build_col_map_add( innobase_build_col_map_add(
heap, dtuple_get_nth_field( heap,
dtuple_get_nth_field(
defaults, i), defaults, i),
altered_field, altered_field,
dict_table_is_comp(new_table)); field,
dict_table_is_comp(
new_table));
} }
col_map[old_i - num_old_v] = i; col_map[old_i - num_old_v] = i;
...@@ -3383,6 +3363,7 @@ innobase_build_col_map( ...@@ -3383,6 +3363,7 @@ innobase_build_col_map(
innobase_build_col_map_add( innobase_build_col_map_add(
heap, dtuple_get_nth_field(defaults, i), heap, dtuple_get_nth_field(defaults, i),
altered_table->field[i + num_v], altered_table->field[i + num_v],
NULL,
dict_table_is_comp(new_table)); dict_table_is_comp(new_table));
found_col: found_col:
if (is_v) { if (is_v) {
...@@ -5611,7 +5592,8 @@ prepare_inplace_alter_table_dict( ...@@ -5611,7 +5592,8 @@ prepare_inplace_alter_table_dict(
!(ha_alter_info->handler_flags !(ha_alter_info->handler_flags
& ALTER_ADD_PK_INDEX), & ALTER_ADD_PK_INDEX),
ctx->defaults, ctx->col_map, path, ctx->defaults, ctx->col_map, path,
ctx->ignore); old_table,
ctx->allow_not_null);
rw_lock_x_unlock(&clust_index->lock); rw_lock_x_unlock(&clust_index->lock);
if (!ok) { if (!ok) {
...@@ -5669,7 +5651,9 @@ prepare_inplace_alter_table_dict( ...@@ -5669,7 +5651,9 @@ prepare_inplace_alter_table_dict(
ctx->prebuilt->trx, ctx->prebuilt->trx,
index, index,
NULL, true, NULL, NULL, NULL, true, NULL, NULL,
path, ctx->ignore); path, old_table,
ctx->allow_not_null);
rw_lock_x_unlock(&index->lock); rw_lock_x_unlock(&index->lock);
if (!ok) { if (!ok) {
...@@ -6850,7 +6834,8 @@ ha_innobase::prepare_inplace_alter_table( ...@@ -6850,7 +6834,8 @@ ha_innobase::prepare_inplace_alter_table(
ha_alter_info->online, ha_alter_info->online,
heap, indexed_table, heap, indexed_table,
col_names, ULINT_UNDEFINED, 0, 0, col_names, ULINT_UNDEFINED, 0, 0,
ha_alter_info->ignore); (ha_alter_info->ignore
|| !thd_is_strict_mode(m_user_thd)));
} }
DBUG_ASSERT(m_prebuilt->trx->dict_operation_lock_mode == 0); DBUG_ASSERT(m_prebuilt->trx->dict_operation_lock_mode == 0);
...@@ -6978,7 +6963,8 @@ ha_innobase::prepare_inplace_alter_table( ...@@ -6978,7 +6963,8 @@ ha_innobase::prepare_inplace_alter_table(
heap, m_prebuilt->table, col_names, heap, m_prebuilt->table, col_names,
add_autoinc_col_no, add_autoinc_col_no,
ha_alter_info->create_info->auto_increment_value, ha_alter_info->create_info->auto_increment_value,
autoinc_col_max_value, ha_alter_info->ignore); autoinc_col_max_value,
ha_alter_info->ignore || !thd_is_strict_mode(m_user_thd));
DBUG_RETURN(prepare_inplace_alter_table_dict( DBUG_RETURN(prepare_inplace_alter_table_dict(
ha_alter_info, altered_table, table, ha_alter_info, altered_table, table,
...@@ -7210,7 +7196,7 @@ ha_innobase::inplace_alter_table( ...@@ -7210,7 +7196,7 @@ ha_innobase::inplace_alter_table(
ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index, ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index,
altered_table, ctx->defaults, ctx->col_map, altered_table, ctx->defaults, ctx->col_map,
ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort, ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort,
ctx->m_stage, add_v, eval_table); ctx->m_stage, add_v, eval_table, ctx->allow_not_null);
#ifndef DBUG_OFF #ifndef DBUG_OFF
oom: oom:
......
...@@ -61,7 +61,9 @@ row_log_allocate( ...@@ -61,7 +61,9 @@ row_log_allocate(
const ulint* col_map,/*!< in: mapping of old column const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */ 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 */ const TABLE* old_table, /*!< in:table definition before alter */
bool allow_not_null) /*!< in: allow null to non-null
conversion */
MY_ATTRIBUTE((nonnull(1), warn_unused_result)); MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/******************************************************//** /******************************************************//**
......
...@@ -322,6 +322,7 @@ this function and it will be passed to other functions for further accounting. ...@@ -322,6 +322,7 @@ this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes @param[in] add_v new virtual columns added along with indexes
@param[in] eval_table mysql table used to evaluate virtual column @param[in] eval_table mysql table used to evaluate virtual column
value, see innobase_get_computed_value(). value, see innobase_get_computed_value().
@param[in] allow_non_null allow the conversion from null to not-null
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
dberr_t dberr_t
row_merge_build_indexes( row_merge_build_indexes(
...@@ -340,7 +341,8 @@ row_merge_build_indexes( ...@@ -340,7 +341,8 @@ row_merge_build_indexes(
bool skip_pk_sort, bool skip_pk_sort,
ut_stage_alter_t* stage, ut_stage_alter_t* stage,
const dict_add_v_col_t* add_v, const dict_add_v_col_t* add_v,
struct TABLE* eval_table) struct TABLE* eval_table,
bool allow_non_null)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//** /********************************************************************//**
......
...@@ -39,6 +39,7 @@ Created 2011-05-26 Marko Makela ...@@ -39,6 +39,7 @@ Created 2011-05-26 Marko Makela
#include "ut0stage.h" #include "ut0stage.h"
#include "trx0rec.h" #include "trx0rec.h"
#include <sql_class.h>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
...@@ -226,9 +227,11 @@ struct row_log_t { ...@@ -226,9 +227,11 @@ struct row_log_t {
table could be emptied, so that table->is_instant() no longer holds, table could be emptied, so that table->is_instant() no longer holds,
but all log records must be in the "instant" format. */ but all log records must be in the "instant" format. */
unsigned n_core_fields; unsigned n_core_fields;
bool ignore; /*!< Whether the alter ignore is being used; bool allow_not_null; /*!< Whether the alter ignore is being
used or if the sql mode is non-strict mode;
if not, NULL values will not be converted to if not, NULL values will not be converted to
defaults */ defaults */
const TABLE* old_table; /*< Use old table in case of error. */
/** Determine whether the log should be in the 'instant ADD' format /** Determine whether the log should be in the 'instant ADD' format
@param[in] index the clustered index of the source table @param[in] index the clustered index of the source table
...@@ -1107,6 +1110,7 @@ table ...@@ -1107,6 +1110,7 @@ table
@param[in] i rec field corresponding to col @param[in] i rec field corresponding to col
@param[in] page_size page size of the old table @param[in] page_size page size of the old table
@param[in] max_len maximum length of dfield @param[in] max_len maximum length of dfield
@param[in] log row log for the table
@retval DB_INVALID_NULL if a NULL value is encountered @retval DB_INVALID_NULL if a NULL value is encountered
@retval DB_TOO_BIG_INDEX_COL if the maximum prefix length is exceeded */ @retval DB_TOO_BIG_INDEX_COL if the maximum prefix length is exceeded */
static static
...@@ -1120,8 +1124,7 @@ row_log_table_get_pk_col( ...@@ -1120,8 +1124,7 @@ row_log_table_get_pk_col(
ulint i, ulint i,
const page_size_t& page_size, const page_size_t& page_size,
ulint max_len, ulint max_len,
bool ignore, const row_log_t* log)
const dtuple_t* defaults)
{ {
const byte* field; const byte* field;
ulint len; ulint len;
...@@ -1129,12 +1132,16 @@ row_log_table_get_pk_col( ...@@ -1129,12 +1132,16 @@ row_log_table_get_pk_col(
field = rec_get_nth_field(rec, offsets, i, &len); field = rec_get_nth_field(rec, offsets, i, &len);
if (len == UNIV_SQL_NULL) { if (len == UNIV_SQL_NULL) {
if (!ignore || !defaults->fields[i].data) {
if (!log->allow_not_null) {
return(DB_INVALID_NULL); return(DB_INVALID_NULL);
} }
field = static_cast<const byte*>(defaults->fields[i].data); ulint n_default_cols = i - DATA_N_SYS_COLS;
len = defaults->fields[i].len;
field = static_cast<const byte*>(
log->defaults->fields[n_default_cols].data);
len = log->defaults->fields[i - DATA_N_SYS_COLS].len;
} }
if (rec_offs_nth_extern(offsets, i)) { if (rec_offs_nth_extern(offsets, i)) {
...@@ -1298,8 +1305,7 @@ row_log_table_get_pk( ...@@ -1298,8 +1305,7 @@ row_log_table_get_pk(
log->error = row_log_table_get_pk_col( log->error = row_log_table_get_pk_col(
ifield, dfield, *heap, ifield, dfield, *heap,
rec, offsets, i, page_size, max_len, rec, offsets, i, page_size, max_len, log);
log->ignore, log->defaults);
if (log->error != DB_SUCCESS) { if (log->error != DB_SUCCESS) {
err_exit: err_exit:
...@@ -1484,7 +1490,9 @@ row_log_table_apply_convert_mrec( ...@@ -1484,7 +1490,9 @@ row_log_table_apply_convert_mrec(
reason of failure */ reason of failure */
{ {
dtuple_t* row; dtuple_t* row;
static ulong n_rows = index->table->stat_n_rows;
n_rows++;
*error = DB_SUCCESS; *error = DB_SUCCESS;
/* This is based on row_build(). */ /* This is based on row_build(). */
...@@ -1613,8 +1621,12 @@ row_log_table_apply_convert_mrec( ...@@ -1613,8 +1621,12 @@ row_log_table_apply_convert_mrec(
const dfield_t& default_field const dfield_t& default_field
= log->defaults->fields[col_no]; = log->defaults->fields[col_no];
Field* field = log->old_table->field[col_no];
field->set_warning(Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1, n_rows);
if (!log->ignore || !default_field.data) { if (!log->allow_not_null) {
/* We got a NULL value for a NOT NULL column. */ /* We got a NULL value for a NOT NULL column. */
*error = DB_INVALID_NULL; *error = DB_INVALID_NULL;
return NULL; return NULL;
...@@ -3109,7 +3121,9 @@ row_log_allocate( ...@@ -3109,7 +3121,9 @@ row_log_allocate(
const ulint* col_map,/*!< in: mapping of old column const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */ 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 */ const TABLE* old_table, /*!< in: table definition before alter */
const bool allow_not_null) /*!< in: allow null to not-null
conversion */
{ {
row_log_t* log; row_log_t* log;
DBUG_ENTER("row_log_allocate"); DBUG_ENTER("row_log_allocate");
...@@ -3150,7 +3164,8 @@ row_log_allocate( ...@@ -3150,7 +3164,8 @@ row_log_allocate(
log->path = path; log->path = path;
log->n_core_fields = index->n_core_fields; log->n_core_fields = index->n_core_fields;
ut_ad(!table || log->is_instant(index) == index->is_instant()); ut_ad(!table || log->is_instant(index) == index->is_instant());
log->ignore=ignore; log->allow_not_null = allow_not_null;
log->old_table = old_table;
dict_index_set_online_status(index, ONLINE_INDEX_CREATION); dict_index_set_online_status(index, ONLINE_INDEX_CREATION);
index->online_log = log; index->online_log = log;
......
...@@ -1674,6 +1674,7 @@ stage->inc() will be called for each page read. ...@@ -1674,6 +1674,7 @@ stage->inc() will be called for each page read.
@param[in,out] crypt_block crypted file buffer @param[in,out] crypt_block crypted file buffer
@param[in] eval_table mysql table used to evaluate virtual column @param[in] eval_table mysql table used to evaluate virtual column
value, see innobase_get_computed_value(). value, see innobase_get_computed_value().
@param[in] allow_not_null allow null to not-null conversion
@return DB_SUCCESS or error */ @return DB_SUCCESS or error */
static MY_ATTRIBUTE((warn_unused_result)) static MY_ATTRIBUTE((warn_unused_result))
dberr_t dberr_t
...@@ -1700,7 +1701,8 @@ row_merge_read_clustered_index( ...@@ -1700,7 +1701,8 @@ row_merge_read_clustered_index(
ut_stage_alter_t* stage, ut_stage_alter_t* stage,
double pct_cost, double pct_cost,
row_merge_block_t* crypt_block, row_merge_block_t* crypt_block,
struct TABLE* eval_table) struct TABLE* eval_table,
bool allow_not_null)
{ {
dict_index_t* clust_index; /* Clustered index */ dict_index_t* clust_index; /* Clustered index */
mem_heap_t* row_heap; /* Heap memory to create mem_heap_t* row_heap; /* Heap memory to create
...@@ -1914,6 +1916,7 @@ row_merge_read_clustered_index( ...@@ -1914,6 +1916,7 @@ row_merge_read_clustered_index(
mach_write_to_8(new_sys_trx_start, trx->id); mach_write_to_8(new_sys_trx_start, trx->id);
mach_write_to_8(new_sys_trx_end, TRX_ID_MAX); mach_write_to_8(new_sys_trx_end, TRX_ID_MAX);
ulong n_rows = 0;
/* Scan the clustered index. */ /* Scan the clustered index. */
for (;;) { for (;;) {
...@@ -2046,6 +2049,8 @@ row_merge_read_clustered_index( ...@@ -2046,6 +2049,8 @@ row_merge_read_clustered_index(
rec = page_cur_get_rec(cur); rec = page_cur_get_rec(cur);
n_rows++;
if (online) { if (online) {
offsets = rec_get_offsets(rec, clust_index, NULL, true, offsets = rec_get_offsets(rec, clust_index, NULL, true,
ULINT_UNDEFINED, &row_heap); ULINT_UNDEFINED, &row_heap);
...@@ -2174,15 +2179,23 @@ row_merge_read_clustered_index( ...@@ -2174,15 +2179,23 @@ row_merge_read_clustered_index(
ut_ad(dfield_get_type(field)->prtype & DATA_NOT_NULL); ut_ad(dfield_get_type(field)->prtype & DATA_NOT_NULL);
if (dfield_is_null(field)) { if (dfield_is_null(field)) {
const dfield_t& default_field
= defaults->fields[nonnull[i]];
if (default_field.data == NULL) { Field* null_field =
table->field[nonnull[i]];
null_field->set_warning(
Sql_condition::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, 1, n_rows);
if (!allow_not_null) {
err = DB_INVALID_NULL; err = DB_INVALID_NULL;
trx->error_key_num = 0; trx->error_key_num = 0;
goto func_exit; goto func_exit;
} }
const dfield_t& default_field
= defaults->fields[nonnull[i]];
*field = default_field; *field = default_field;
} }
} }
...@@ -4547,6 +4560,7 @@ this function and it will be passed to other functions for further accounting. ...@@ -4547,6 +4560,7 @@ this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes @param[in] add_v new virtual columns added along with indexes
@param[in] eval_table mysql table used to evaluate virtual column @param[in] eval_table mysql table used to evaluate virtual column
value, see innobase_get_computed_value(). value, see innobase_get_computed_value().
@param[in] allow_not_null allow the conversion from null to not-null
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
dberr_t dberr_t
row_merge_build_indexes( row_merge_build_indexes(
...@@ -4565,7 +4579,8 @@ row_merge_build_indexes( ...@@ -4565,7 +4579,8 @@ row_merge_build_indexes(
bool skip_pk_sort, bool skip_pk_sort,
ut_stage_alter_t* stage, ut_stage_alter_t* stage,
const dict_add_v_col_t* add_v, const dict_add_v_col_t* add_v,
struct TABLE* eval_table) struct TABLE* eval_table,
bool allow_not_null)
{ {
merge_file_t* merge_files; merge_file_t* merge_files;
row_merge_block_t* block; row_merge_block_t* block;
...@@ -4729,7 +4744,7 @@ row_merge_build_indexes( ...@@ -4729,7 +4744,7 @@ row_merge_build_indexes(
fts_sort_idx, psort_info, merge_files, key_numbers, fts_sort_idx, psort_info, merge_files, key_numbers,
n_indexes, defaults, add_v, col_map, add_autoinc, n_indexes, defaults, add_v, col_map, add_autoinc,
sequence, block, skip_pk_sort, &tmpfd, stage, sequence, block, skip_pk_sort, &tmpfd, stage,
pct_cost, crypt_block, eval_table); pct_cost, crypt_block, eval_table, allow_not_null);
stage->end_phase_read_pk(); stage->end_phase_read_pk();
......
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