summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2018-05-15 17:02:08 +0300
committerMonty <monty@mariadb.org>2018-05-15 17:10:40 +0300
commit4ab180ad5e9c67427b561035e4b8e193d429fe5a (patch)
treef61abf25921b112e58ec68cbfcf9a6d0ae392d60
parent0e296947db503eed2db5b995676f4d9a454c9001 (diff)
downloadmariadb-git-4ab180ad5e9c67427b561035e4b8e193d429fe5a.tar.gz
MDEV-15461 Check Constraints with binary logging makes insert inconsistent
Problem was that verify_constraints() didn't check if there was an error as part of evaluating constraints (can happen in strict mode). In one-row-insert the error was ignored when using binary logging as binary logging clear errors if insert succeeded. In multi-row-insert the error was noticed for the second row. After this fix one will get an error for both one and multi-row inserts if the constraints generates a warning in strict mode.
-rw-r--r--mysql-test/r/check_constraint.result41
-rw-r--r--mysql-test/t/check_constraint.test24
-rw-r--r--sql/table.cc21
3 files changed, 83 insertions, 3 deletions
diff --git a/mysql-test/r/check_constraint.result b/mysql-test/r/check_constraint.result
index 70d64cd6ff7..9a32e6f12bc 100644
--- a/mysql-test/r/check_constraint.result
+++ b/mysql-test/r/check_constraint.result
@@ -156,3 +156,44 @@ create table t1 (id int auto_increment primary key, datecol datetime, check (dat
insert into t1 (datecol) values (now());
insert into t1 (datecol) values (now());
drop table t1;
+CREATE TABLE t1 (
+EmployeeID SMALLINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+FirstName VARCHAR(30) NOT NULL CHECK (CHAR_LENGTH(FirstName > 2))
+);
+INSERT INTO t1 VALUES (NULL, 'Ken');
+ERROR 22007: Truncated incorrect DOUBLE value: 'Ken'
+SHOW WARNINGS;
+Level Code Message
+Error 1292 Truncated incorrect DOUBLE value: 'Ken'
+Error 4025 CONSTRAINT `FirstName` failed for `test`.`t1`
+INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+ERROR 22007: Truncated incorrect DOUBLE value: 'Ken'
+SHOW WARNINGS;
+Level Code Message
+Error 1292 Truncated incorrect DOUBLE value: 'Ken'
+Error 4025 CONSTRAINT `FirstName` failed for `test`.`t1`
+INSERT IGNORE INTO t1 VALUES (NULL, 'Ken');
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'Ken'
+INSERT IGNORE INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'Ken'
+Warning 1292 Truncated incorrect DOUBLE value: 'Brian'
+set sql_mode="";
+INSERT INTO t1 VALUES (NULL, 'Ken');
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'Ken'
+INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'Ken'
+Warning 1292 Truncated incorrect DOUBLE value: 'Brian'
+set sql_mode=default;
+select * from t1;
+EmployeeID FirstName
+1 Ken
+2 Ken
+3 Brian
+4 Ken
+5 Ken
+6 Brian
+drop table t1;
diff --git a/mysql-test/t/check_constraint.test b/mysql-test/t/check_constraint.test
index 9a77736acd7..02081071bd4 100644
--- a/mysql-test/t/check_constraint.test
+++ b/mysql-test/t/check_constraint.test
@@ -111,3 +111,27 @@ create table t1 (id int auto_increment primary key, datecol datetime, check (dat
insert into t1 (datecol) values (now());
insert into t1 (datecol) values (now());
drop table t1;
+
+#
+# MDEV-15461 Check Constraints with binary logging makes insert inconsistent
+#
+
+CREATE TABLE t1 (
+ EmployeeID SMALLINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+ FirstName VARCHAR(30) NOT NULL CHECK (CHAR_LENGTH(FirstName > 2))
+);
+
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES (NULL, 'Ken');
+SHOW WARNINGS;
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+SHOW WARNINGS;
+INSERT IGNORE INTO t1 VALUES (NULL, 'Ken');
+INSERT IGNORE INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+set sql_mode="";
+INSERT INTO t1 VALUES (NULL, 'Ken');
+INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
+set sql_mode=default;
+select * from t1;
+drop table t1;
diff --git a/sql/table.cc b/sql/table.cc
index fff2be4f154..d7cbf555b72 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5116,14 +5116,25 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure)
int TABLE::verify_constraints(bool ignore_failure)
{
+ /*
+ We have to check is_error() first as we are checking it for each
+ constraint to catch fatal warnings.
+ */
+ if (in_use->is_error())
+ return (VIEW_CHECK_ERROR);
+
/* go trough check option clauses for fields and table */
if (check_constraints &&
!(in_use->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS))
{
for (Virtual_column_info **chk= check_constraints ; *chk ; chk++)
{
- /* yes! NULL is ok, see 4.23.3.4 Table check constraints, part 2, SQL:2016 */
- if ((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value)
+ /*
+ yes! NULL is ok.
+ see 4.23.3.4 Table check constraints, part 2, SQL:2016
+ */
+ if (((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) ||
+ in_use->is_error())
{
my_error(ER_CONSTRAINT_FAILED,
MYF(ignore_failure ? ME_JUST_WARNING : 0), (*chk)->name.str,
@@ -5132,7 +5143,11 @@ int TABLE::verify_constraints(bool ignore_failure)
}
}
}
- return(VIEW_CHECK_OK);
+ /*
+ We have to check in_use() as checking constraints may have generated
+ warnings that should be treated as errors
+ */
+ return(!in_use->is_error() ? VIEW_CHECK_OK : VIEW_CHECK_ERROR);
}