Skip to content

Commit e6dbb7d

Browse files
author
Samar Pratap Singh
committed
Bug#35868410 ER_ROW_IS_REFERENCED vs ER_ROW_IS_REFERENCED_2 breaks
backwards compatibility 1) Fixed to use a single error code (*_2) for foreign key errors irrespective of whether error details are displayed or not. 2) Fixed to display parent/child table details in error message also when user is granted access to it via db level grant. Change-Id: I8fd980864e73ab269dda4c8b1df63730939dfa86
1 parent 2d9dca0 commit e6dbb7d

File tree

6 files changed

+129
-33
lines changed

6 files changed

+129
-33
lines changed

mysql-test/r/foreign_key.result

+50-7
Original file line numberDiff line numberDiff line change
@@ -4091,6 +4091,10 @@ CREATE TABLE t1(fld1 INT PRIMARY KEY, fld2 INT) ENGINE=INNODB;
40914091
CREATE TABLE t2(fld1 INT PRIMARY KEY, fld2 INT, CONSTRAINT fk2
40924092
FOREIGN KEY (fld1) REFERENCES t1 (fld1)) ENGINE=InnoDB;
40934093
CREATE TABLE t3(fld1 INT PRIMARY KEY, fld2 INT) ENGINE=InnoDB;
4094+
CREATE TABLE parent (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
4095+
CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id)) ENGINE=INNODB;
4096+
INSERT INTO parent (id) VALUES(1);
4097+
INSERT INTO child (id,parent_id) VALUES(1,1);
40944098
# Set up stored routines
40954099
CREATE PROCEDURE p1() SQL SECURITY INVOKER INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
40964100
CREATE PROCEDURE p2() SQL SECURITY DEFINER INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
@@ -4111,6 +4115,10 @@ CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT * FROM t2;
41114115
CREATE USER user1@localhost;
41124116
CREATE USER user2@localhost;
41134117
CREATE USER user3@localhost;
4118+
CREATE USER user4@localhost;
4119+
CREATE USER user5@localhost;
4120+
CREATE USER user6@localhost;
4121+
CREATE USER user7@localhost;
41144122
GRANT INSERT (fld1, fld2) ON t2 TO user1@localhost;
41154123
GRANT INSERT ON v1 TO user2@localhost;
41164124
GRANT INSERT ON v2 TO user2@localhost;
@@ -4122,17 +4130,23 @@ GRANT EXECUTE ON PROCEDURE p1 TO user2@localhost;
41224130
GRANT EXECUTE ON PROCEDURE p2 TO user2@localhost;
41234131
GRANT EXECUTE ON FUNCTION f1 TO user2@localhost;
41244132
GRANT EXECUTE ON FUNCTION f2 TO user2@localhost;
4133+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.* to user4@localhost;
4134+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.parent to user5@localhost;
4135+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.parent to user6@localhost;
4136+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.child to user6@localhost;
4137+
GRANT SELECT ON wl8910db.* TO user7@localhost;
4138+
GRANT DELETE ON wl8910db.parent TO user7@localhost;
41254139
connect con1, localhost, user1,,wl8910db;
41264140
# Without patch, reveals parent table's information.
41274141
INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
41284142
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails
41294143
# Warning displayed does not reveal parent table information.
41304144
INSERT IGNORE INTO t2 (fld1, fld2) VALUES (1, 2);
41314145
Warnings:
4132-
Warning 1216 Cannot add or update a child row: a foreign key constraint fails
4146+
Warning 1452 Cannot add or update a child row: a foreign key constraint fails
41334147
SHOW WARNINGS;
41344148
Level Code Message
4135-
Warning 1216 Cannot add or update a child row: a foreign key constraint fails
4149+
Warning 1452 Cannot add or update a child row: a foreign key constraint fails
41364150
connection default;
41374151
GRANT SELECT ON t1 TO user1@localhost;
41384152
connection con1;
@@ -4147,10 +4161,10 @@ ERROR 23000: Cannot add or update a child row: a foreign key constraint fails
41474161
# Warning displayed does not reveal parent table information.
41484162
INSERT IGNORE INTO t2 (fld1, fld2) VALUES (1, 2);
41494163
Warnings:
4150-
Warning 1216 Cannot add or update a child row: a foreign key constraint fails
4164+
Warning 1452 Cannot add or update a child row: a foreign key constraint fails
41514165
SHOW WARNINGS;
41524166
Level Code Message
4153-
Warning 1216 Cannot add or update a child row: a foreign key constraint fails
4167+
Warning 1452 Cannot add or update a child row: a foreign key constraint fails
41544168
connection default;
41554169
GRANT SELECT ON t3 TO user1@localhost;
41564170
connection con1;
@@ -4159,7 +4173,6 @@ ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`
41594173
connection default;
41604174
GRANT INSERT (fld1, fld2) ON t2 TO user2@localhost;
41614175
GRANT CREATE ROUTINE ON wl8910db.* TO user2@localhost;
4162-
GRANT CREATE VIEW ON wl8910db.* TO user2@localhost;
41634176
# Tests where DML reports FK constraint failure within Stored Routines.
41644177
connect con2, localhost, user2,,wl8910db;
41654178
# The SQL security for p1 is invoker where invoker lacks permission
@@ -4191,7 +4204,9 @@ ERROR 23000: Cannot add or update a child row: a foreign key constraint fails
41914204
connection default;
41924205
GRANT SELECT ON t1 TO user2@localhost;
41934206
GRANT SELECT ON t3 TO user2@localhost;
4194-
connection con2;
4207+
GRANT CREATE VIEW ON wl8910db.* TO user2@localhost;
4208+
disconnect con2;
4209+
connect con2, localhost, user2,,wl8910db;
41954210
# DML on view executed within the definer context where the invoker
41964211
# has access to the parent table, hence the parent table information
41974212
# is displayed.
@@ -4226,16 +4241,44 @@ SELECT f3();
42264241
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`wl8910db`.`t2`, CONSTRAINT `fk2` FOREIGN KEY (`fld1`) REFERENCES `t1` (`fld1`))
42274242
INSERT INTO v3 VALUES(4, 5);
42284243
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`wl8910db`.`t2`, CONSTRAINT `fk2` FOREIGN KEY (`fld1`) REFERENCES `t1` (`fld1`))
4244+
# user4 have access to the child table, hence the child table
4245+
# information is displayed.
4246+
connect con4, localhost, user4,,wl8910db;
4247+
DELETE FROM parent WHERE id = 1;
4248+
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`wl8910db`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`))
4249+
# user5 do not have access to the child table, hence the child table
4250+
# information is not displayed.
4251+
connect con5, localhost, user5,,wl8910db;
4252+
DELETE FROM parent WHERE id = 1;
4253+
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
4254+
# user6 have access to the child table, hence the child table
4255+
# information is displayed.
4256+
connect con6, localhost, user6,,wl8910db;
4257+
DELETE FROM parent WHERE id = 1;
4258+
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`wl8910db`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`))
4259+
# user7 have access to the child table, hence the child table
4260+
# information is displayed.
4261+
connect con7, localhost, user7,,wl8910db;
4262+
DELETE FROM parent WHERE id = 1;
4263+
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`wl8910db`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`))
42294264
# Cleanup
42304265
connection default;
42314266
disconnect con1;
42324267
disconnect con2;
42334268
disconnect con3;
4269+
disconnect con4;
4270+
disconnect con5;
4271+
disconnect con6;
4272+
disconnect con7;
42344273
DROP VIEW v1, v2, v3;
4235-
DROP TABLE t2, t3, t1;
4274+
DROP TABLE t2, t3, t1, parent, child;
42364275
DROP USER user1@localhost;
42374276
DROP USER user2@localhost;
42384277
DROP USER user3@localhost;
4278+
DROP USER user4@localhost;
4279+
DROP USER user5@localhost;
4280+
DROP USER user6@localhost;
4281+
DROP USER user7@localhost;
42394282
DROP PROCEDURE p1;
42404283
DROP PROCEDURE p2;
42414284
DROP PROCEDURE p3;

mysql-test/t/foreign_key.test

+57-9
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,10 @@ CREATE TABLE t1(fld1 INT PRIMARY KEY, fld2 INT) ENGINE=INNODB;
40104010
CREATE TABLE t2(fld1 INT PRIMARY KEY, fld2 INT, CONSTRAINT fk2
40114011
FOREIGN KEY (fld1) REFERENCES t1 (fld1)) ENGINE=InnoDB;
40124012
CREATE TABLE t3(fld1 INT PRIMARY KEY, fld2 INT) ENGINE=InnoDB;
4013+
CREATE TABLE parent (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB;
4014+
CREATE TABLE child (id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id)) ENGINE=INNODB;
4015+
INSERT INTO parent (id) VALUES(1);
4016+
INSERT INTO child (id,parent_id) VALUES(1,1);
40134017

40144018
--echo # Set up stored routines
40154019
CREATE PROCEDURE p1() SQL SECURITY INVOKER INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
@@ -4037,6 +4041,10 @@ CREATE SQL SECURITY DEFINER VIEW v2 AS SELECT * FROM t2;
40374041
CREATE USER user1@localhost;
40384042
CREATE USER user2@localhost;
40394043
CREATE USER user3@localhost;
4044+
CREATE USER user4@localhost;
4045+
CREATE USER user5@localhost;
4046+
CREATE USER user6@localhost;
4047+
CREATE USER user7@localhost;
40404048
GRANT INSERT (fld1, fld2) ON t2 TO user1@localhost;
40414049
GRANT INSERT ON v1 TO user2@localhost;
40424050
GRANT INSERT ON v2 TO user2@localhost;
@@ -4046,12 +4054,18 @@ GRANT EXECUTE ON PROCEDURE p1 TO user2@localhost;
40464054
GRANT EXECUTE ON PROCEDURE p2 TO user2@localhost;
40474055
GRANT EXECUTE ON FUNCTION f1 TO user2@localhost;
40484056
GRANT EXECUTE ON FUNCTION f2 TO user2@localhost;
4057+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.* to user4@localhost;
4058+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.parent to user5@localhost;
4059+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.parent to user6@localhost;
4060+
GRANT SELECT, DELETE, INSERT, UPDATE on wl8910db.child to user6@localhost;
4061+
GRANT SELECT ON wl8910db.* TO user7@localhost;
4062+
GRANT DELETE ON wl8910db.parent TO user7@localhost;
40494063

40504064
--enable_connect_log
40514065

40524066
connect (con1, localhost, user1,,wl8910db);
40534067
--echo # Without patch, reveals parent table's information.
4054-
--error ER_NO_REFERENCED_ROW
4068+
--error ER_NO_REFERENCED_ROW_2
40554069
INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
40564070

40574071
--echo # Warning displayed does not reveal parent table information.
@@ -4070,7 +4084,7 @@ ALTER TABLE t2 ADD CONSTRAINT fk3 FOREIGN KEY (fld2) REFERENCES t3(fld1);
40704084

40714085
connection con1;
40724086
--echo # Without patch, reveals parent table's information.
4073-
--error ER_NO_REFERENCED_ROW
4087+
--error ER_NO_REFERENCED_ROW_2
40744088
INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
40754089

40764090
--echo # Warning displayed does not reveal parent table information.
@@ -4087,14 +4101,13 @@ INSERT INTO t2 (fld1, fld2) VALUES (1, 2);
40874101
connection default;
40884102
GRANT INSERT (fld1, fld2) ON t2 TO user2@localhost;
40894103
GRANT CREATE ROUTINE ON wl8910db.* TO user2@localhost;
4090-
GRANT CREATE VIEW ON wl8910db.* TO user2@localhost;
40914104

40924105
--echo # Tests where DML reports FK constraint failure within Stored Routines.
40934106
connect (con2, localhost, user2,,wl8910db);
40944107

40954108
--echo # The SQL security for p1 is invoker where invoker lacks permission
40964109
--echo # to parent table, hence parent table information is not displayed.
4097-
--error ER_NO_REFERENCED_ROW
4110+
--error ER_NO_REFERENCED_ROW_2
40984111
CALL p1();
40994112

41004113
--echo # The SQL security p2 is definer, where the definer has access privilege
@@ -4104,7 +4117,7 @@ CALL p2();
41044117

41054118
--echo # The SQL security for f1 is invoker where invoker lacks permission
41064119
--echo # to parent table, hence parent table information is not displayed.
4107-
--error ER_NO_REFERENCED_ROW
4120+
--error ER_NO_REFERENCED_ROW_2
41084121
SELECT f1();
41094122

41104123
--echo # The SQL security f2 is definer, where the definer has access privilege
@@ -4116,20 +4129,23 @@ SELECT f2();
41164129

41174130
--echo # The invoker does not have access to the parent table, hence the parent
41184131
--echo # table information is not displayed.
4119-
--error ER_NO_REFERENCED_ROW
4132+
--error ER_NO_REFERENCED_ROW_2
41204133
INSERT INTO v1 VALUES (1, 2);
41214134

41224135
--echo # DML on view executed within the definer context where the invoker does
41234136
--echo # not have access to the parent table, hence the parent table information
41244137
--echo # is not displayed.
4125-
--error ER_NO_REFERENCED_ROW
4138+
--error ER_NO_REFERENCED_ROW_2
41264139
INSERT INTO v2 VALUES (1, 2);
41274140

41284141
connection default;
41294142
GRANT SELECT ON t1 TO user2@localhost;
41304143
GRANT SELECT ON t3 TO user2@localhost;
4144+
GRANT CREATE VIEW ON wl8910db.* TO user2@localhost;
4145+
4146+
disconnect con2;
4147+
connect (con2, localhost, user2,,wl8910db);
41314148

4132-
connection con2;
41334149
--echo # DML on view executed within the definer context where the invoker
41344150
--echo # has access to the parent table, hence the parent table information
41354151
--echo # is displayed.
@@ -4178,16 +4194,48 @@ SELECT f3();
41784194
--error ER_NO_REFERENCED_ROW_2
41794195
INSERT INTO v3 VALUES(4, 5);
41804196

4197+
--echo # user4 have access to the child table, hence the child table
4198+
--echo # information is displayed.
4199+
connect (con4, localhost, user4,,wl8910db);
4200+
--error ER_ROW_IS_REFERENCED_2
4201+
DELETE FROM parent WHERE id = 1;
4202+
4203+
--echo # user5 do not have access to the child table, hence the child table
4204+
--echo # information is not displayed.
4205+
connect (con5, localhost, user5,,wl8910db);
4206+
--error ER_ROW_IS_REFERENCED_2
4207+
DELETE FROM parent WHERE id = 1;
4208+
4209+
--echo # user6 have access to the child table, hence the child table
4210+
--echo # information is displayed.
4211+
connect (con6, localhost, user6,,wl8910db);
4212+
--error ER_ROW_IS_REFERENCED_2
4213+
DELETE FROM parent WHERE id = 1;
4214+
4215+
--echo # user7 have access to the child table, hence the child table
4216+
--echo # information is displayed.
4217+
connect (con7, localhost, user7,,wl8910db);
4218+
--error ER_ROW_IS_REFERENCED_2
4219+
DELETE FROM parent WHERE id = 1;
4220+
41814221
--echo # Cleanup
41824222
connection default;
41834223
disconnect con1;
41844224
disconnect con2;
41854225
disconnect con3;
4226+
disconnect con4;
4227+
disconnect con5;
4228+
disconnect con6;
4229+
disconnect con7;
41864230
DROP VIEW v1, v2, v3;
4187-
DROP TABLE t2, t3, t1;
4231+
DROP TABLE t2, t3, t1, parent, child;
41884232
DROP USER user1@localhost;
41894233
DROP USER user2@localhost;
41904234
DROP USER user3@localhost;
4235+
DROP USER user4@localhost;
4236+
DROP USER user5@localhost;
4237+
DROP USER user6@localhost;
4238+
DROP USER user7@localhost;
41914239
DROP PROCEDURE p1;
41924240
DROP PROCEDURE p2;
41934241
DROP PROCEDURE p3;

share/messages_to_clients.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -5674,11 +5674,11 @@ ER_FORBID_SCHEMA_CHANGE
56745674
eng "Changing schema from '%-.192s' to '%-.192s' is not allowed."
56755675
ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt"
56765676
ER_ROW_IS_REFERENCED_2 23000
5677-
eng "Cannot delete or update a parent row: a foreign key constraint fails (%.192s)"
5678-
ger "Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
5677+
eng "Cannot delete or update a parent row: a foreign key constraint fails%.192s"
5678+
ger "Kann Eltern-Zeile nicht löschen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl%.192s"
56795679
ER_NO_REFERENCED_ROW_2 23000
5680-
eng "Cannot add or update a child row: a foreign key constraint fails (%.192s)"
5681-
ger "Kann Kind-Zeile nicht hinzufügen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl (%.192s)"
5680+
eng "Cannot add or update a child row: a foreign key constraint fails%.192s"
5681+
ger "Kann Kind-Zeile nicht hinzufügen oder aktualisieren: eine Fremdschlüsselbedingung schlägt fehl%.192s"
56825682
ER_SP_BAD_VAR_SHADOW 42000
56835683
eng "Variable '%-.64s' must be quoted with `...`, or renamed"
56845684
ger "Variable '%-.64s' muss mit `...` geschützt oder aber umbenannt werden"

sql/error_handler.cc

+9-5
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,9 @@ bool Info_schema_error_handler::handle_condition(
496496

497497
bool Foreign_key_error_handler::handle_condition(
498498
THD *, uint sql_errno, const char *, Sql_condition::enum_severity_level *,
499-
const char *) {
499+
const char *msg) {
500+
std::string message{msg};
501+
if (!message.ends_with(')')) return false;
500502
const TABLE_SHARE *share = m_table_handler->get_table_share();
501503

502504
if (sql_errno == ER_NO_REFERENCED_ROW_2) {
@@ -506,8 +508,9 @@ bool Foreign_key_error_handler::handle_condition(
506508
fk->referenced_table_db.length,
507509
fk->referenced_table_name.str,
508510
fk->referenced_table_name.length, TL_READ);
509-
if (check_table_access(m_thd, TABLE_OP_ACLS, &table, true, 1, true)) {
510-
my_error(ER_NO_REFERENCED_ROW, MYF(0));
511+
if (check_some_access(m_thd, TABLE_OP_ACLS, &table) ||
512+
((&table)->grant.privilege & TABLE_OP_ACLS) == 0) {
513+
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), "");
511514
return true;
512515
}
513516
}
@@ -519,8 +522,9 @@ bool Foreign_key_error_handler::handle_condition(
519522
fk_p->referencing_table_db.length,
520523
fk_p->referencing_table_name.str,
521524
fk_p->referencing_table_name.length, TL_READ);
522-
if (check_table_access(m_thd, TABLE_OP_ACLS, &table, true, 1, true)) {
523-
my_error(ER_ROW_IS_REFERENCED, MYF(0));
525+
if (check_some_access(m_thd, TABLE_OP_ACLS, &table) ||
526+
((&table)->grant.privilege & TABLE_OP_ACLS) == 0) {
527+
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), "");
524528
return true;
525529
}
526530
}

sql/error_handler.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,9 @@ class Info_schema_error_handler : public Internal_error_handler {
404404
};
405405

406406
/**
407-
An Internal_error_handler that converts errors related to foreign key
408-
constraint checks 'ER_NO_REFERENCED_ROW_2' and 'ER_ROW_IS_REFERENCED_2'
409-
to ER_NO_REFERENCED_ROW and ER_ROW_IS_REFERENCED based on privilege checks.
410-
This prevents from revealing parent and child tables information respectively
411-
when the foreign key constraint check fails and user does not have privileges
412-
to access those tables.
407+
An Internal_error_handler that prevents revealing parent and child tables
408+
information when the foreign key constraint check fails and user does not
409+
have privileges to access those tables.
413410
*/
414411
class Foreign_key_error_handler : public Internal_error_handler {
415412
handler *m_table_handler;

sql/handler.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -4366,7 +4366,9 @@ void handler::print_error(int error, myf errflag) {
43664366
*/
43674367
thd->push_internal_handler(&foreign_key_error_handler);
43684368
get_error_message(error, &str);
4369-
my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe());
4369+
std::string err_msg = str.c_ptr_safe();
4370+
err_msg = " (" + err_msg + ")";
4371+
my_error(ER_ROW_IS_REFERENCED_2, errflag, err_msg.c_str());
43704372
thd->pop_internal_handler();
43714373
return;
43724374
}
@@ -4378,7 +4380,9 @@ void handler::print_error(int error, myf errflag) {
43784380
*/
43794381
thd->push_internal_handler(&foreign_key_error_handler);
43804382
get_error_message(error, &str);
4381-
my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe());
4383+
std::string err_msg = str.c_ptr_safe();
4384+
err_msg = " (" + err_msg + ")";
4385+
my_error(ER_NO_REFERENCED_ROW_2, errflag, err_msg.c_str());
43824386
thd->pop_internal_handler();
43834387
return;
43844388
}

0 commit comments

Comments
 (0)