# Test for Bug 13867871 - ROW_INS_CHECK_FOREIGN_CONSTRAINT() ACCESSES
# FREED DICT_INDEX_T
--source include/have_innodb.inc
--source include/have_debug_sync.inc

# Save the initial number of concurrent sessions.
--source include/count_sessions.inc

CREATE TABLE parent (
a INT, d INT, b VARCHAR(20), c VARCHAR(75),
PRIMARY KEY (a, d, b), INDEX (b, c), INDEX (c))
ENGINE = INNODB;

CREATE TABLE child (
a INT, d INT, b VARCHAR(20), c VARCHAR(75),
PRIMARY KEY (a, d, b), INDEX (b, c), INDEX (c),
FOREIGN KEY (a, d) REFERENCES parent (a, d)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT kukkuu FOREIGN KEY (b, c) REFERENCES parent (b, c)
ON DELETE CASCADE ON UPDATE CASCADE)
ENGINE = INNODB;

INSERT INTO parent VALUES (1, 5, 'khD','khD');
SET innodb_lock_wait_timeout=1;

connect (con1,localhost,root,,);

connection con1;
--echo # connection con1: blocked before FOREIGN KEY check during INSERT

SET DEBUG_SYNC = 'foreign_constraint_check_for_ins WAIT_FOR drop_done';
--send
/* con1 send */ INSERT INTO child VALUES (1, 5, 'khD','khD');

connection default;
--echo # connection default: replace the underlying index of FOREIGN KEY
let $wait_condition=
  SELECT COUNT(*) = 1 FROM information_schema.processlist
  WHERE state = 'debug sync point: foreign_constraint_check_for_ins'
  AND info = '/* con1 send */ INSERT INTO child VALUES (1, 5, ''khD'',''khD'')';
--source include/wait_condition.inc

CREATE INDEX idx1 ON parent(b, c);
DROP INDEX b ON parent;
SET DEBUG_SYNC = 'now SIGNAL drop_done';

connection con1;
--echo /* con1 reap */ INSERT INTO child VALUES (1, 5, 'khD','khD');
reap;
--echo # connection con1: test ON UPDATE CASCADE
BEGIN;
SET DEBUG_SYNC = 'foreign_constraint_update_cascade WAIT_FOR create_index';
SET DEBUG_SYNC = 'now SIGNAL start_test';
--send
/* con1 send */ DELETE FROM parent WHERE a = 1;

connection default;
--echo # connection default: con1 already IX-locked table child

let $wait_condition=
  SELECT COUNT(*) = 1 FROM information_schema.processlist
  WHERE state = 'debug sync point: foreign_constraint_update_cascade'
  AND info = '/* con1 send */ DELETE FROM parent WHERE a = 1';
--source include/wait_condition.inc

--error ER_LOCK_DEADLOCK
--send
/* default send */ CREATE INDEX idx ON child(b, c);

connect (con2,localhost,root,,);
SET DEBUG_SYNC = 'now WAIT_FOR start_test';
--echo # connection con2: unblock connection default
SET DEBUG_SYNC = 'now SIGNAL create_index';

connection default;
--echo /* default reap */ CREATE INDEX idx ON child(b, c);
--error 0, ER_LOCK_WAIT_TIMEOUT
reap;

connection con1;
--echo /* con1 reap */ DELETE FROM parent WHERE a = 1;
reap;

connection default;
--echo # connection default: con1 is holding IX-lock on table child
--error ER_LOCK_WAIT_TIMEOUT
CREATE INDEX idx ON child(b, c);
--error ER_DROP_INDEX_FK
DROP INDEX b ON child;

connection con1;
--echo # connection con1
COMMIT;

connection default;
--echo # connection default: no locks on table child
CREATE INDEX idx ON child(b, c);
DROP INDEX b ON child;

SELECT * FROM child;
SELECT * FROM parent;

connection con1;
--echo # connection con1: test ON UPDATE CASCADE

INSERT INTO parent VALUES (1, 5, 'khD','khD');

INSERT INTO child VALUES (1, 5, 'khD','khD');

BEGIN;
SET DEBUG_SYNC = 'foreign_constraint_check_for_update_done WAIT_FOR alter';
--send
/* con1 send */ UPDATE parent SET a = 2;

connection default;
--echo # connection default: con1 is holding IX-lock on table child

let $wait_condition=
  SELECT COUNT(*) = 1 FROM information_schema.processlist
  WHERE state = 'debug sync point: foreign_constraint_check_for_update_done'
  AND info = '/* con1 send */ UPDATE parent SET a = 2';
--source include/wait_condition.inc

--error ER_LOCK_WAIT_TIMEOUT
ALTER TABLE child ADD INDEX idx_2(B, C), DROP INDEX idx, LOCK=NONE;

SET DEBUG_SYNC = 'now SIGNAL alter';

connection con1;
--echo /* con1 reap */ UPDATE parent SET a = 2;
reap;
connection default;
--echo # connection default: con1 is holding IX-lock on table child
--error ER_LOCK_WAIT_TIMEOUT
ALTER TABLE child ADD INDEX idx_2(B, C), DROP INDEX idx, ALGORITHM=INPLACE;
connection con1;
--echo # connection con1
ROLLBACK;

BEGIN;
SET DEBUG_SYNC = 'foreign_constraint_check_for_update WAIT_FOR altered';
SET DEBUG_SYNC = 'now SIGNAL start_test';
--send
/* con1 send */ UPDATE parent SET a = 3;

connection default;
--echo # connection default: con1 is not yet holding locks on table child

let $wait_condition=
  SELECT COUNT(*) = 1 FROM information_schema.processlist
  WHERE state = 'debug sync point: foreign_constraint_check_for_update'
  AND info = '/* con1 send */ UPDATE parent SET a = 3';
--source include/wait_condition.inc

# This should be blocked in commit_inplace_alter_table
--send
/* default send */ ALTER TABLE child ADD INDEX idx_2(B, C), DROP INDEX idx;

connection con2;

SET DEBUG_SYNC = 'now WAIT_FOR start_test';

--echo # connection con2: unblock connection con1
SET DEBUG_SYNC = 'now SIGNAL altered';
disconnect con2;

connection con1;
--echo /* con1 reap */ UPDATE parent SET a = 3;
reap;

connection default;
--echo /* default reap */ ALTER TABLE child ADD INDEX idx_2(B, C), DROP INDEX idx;
# TODO (Bug#14529475): investigate why this is nondeterministic
# Progress report: Added a new sync point 'start_test', chtest.sh does
# not report problem any more. However, it needs some more confirmation
# before this go arounds can be removed.
--error 0, ER_LOCK_WAIT_TIMEOUT
reap;
SELECT * FROM child;

connection con1;
--echo # connection con1
SELECT * FROM child;
COMMIT;
disconnect con1;

connection default;

SELECT * FROM child;
SELECT * FROM parent;

DROP TABLE child;
DROP TABLE parent;

SET DEBUG_SYNC = 'RESET';

# Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc
