From d0e1612f87682f921951946372cbe242aea0d633 Mon Sep 17 00:00:00 2001
From: Nikita Pettik <korablev@tarantool.org>
Date: Fri, 13 Sep 2019 19:35:26 +0300
Subject: [PATCH] sql: swap FK masks during altering of space

It was forgotten to swap old and new mask (holding fields involved into
foreign key relation) during space alteration (lists of object
representing FK metadata are swapped successfully). Since mask is vital
and depending on its value different byte-codes implementing SQL query
can be produced, this mistake resulted in assertion fault in debug build
and wrong constraint check in release build. Let's fix this bug and swap
masks as well as foreign key lists.

Closes #4495

(cherry picked from commit 33236ecc73f8946c825dd053feb75413a319c76e)
---
 src/box/alter.cc               |  1 +
 test/sql/foreign-keys.result   | 38 ++++++++++++++++++++++++++++++++++
 test/sql/foreign-keys.test.lua | 15 ++++++++++++++
 3 files changed, 54 insertions(+)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 92f1d5b221..0f8ba082a3 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -581,6 +581,7 @@ space_swap_fk_constraints(struct space *new_space, struct space *old_space)
 		   &old_space->child_fk_constraint);
 	rlist_swap(&new_space->parent_fk_constraint,
 		   &old_space->parent_fk_constraint);
+	SWAP(new_space->fk_constraint_mask, old_space->fk_constraint_mask);
 }
 
 /**
diff --git a/test/sql/foreign-keys.result b/test/sql/foreign-keys.result
index b8ff8f1452..29538e8160 100644
--- a/test/sql/foreign-keys.result
+++ b/test/sql/foreign-keys.result
@@ -457,5 +457,43 @@ t1:drop()
 t2:drop()
 ---
 ...
+-- gh-4495: space alter resulted in foreign key mask reset.
+-- Which in turn led to wrong byte-code generation. Make sure
+-- that alter of space doesn't affect result of query execution.
+--
+box.execute("CREATE TABLE t (id TEXT PRIMARY KEY, a INTEGER NOT NULL);")
+---
+- row_count: 1
+...
+box.execute("CREATE TABLE s (t_id TEXT PRIMARY KEY, a INTEGER NOT NULL, FOREIGN KEY(t_id) REFERENCES t(id) ON DELETE CASCADE);")
+---
+- row_count: 1
+...
+box.space.T:insert({'abc', 1})
+---
+- ['abc', 1]
+...
+box.space.S:insert({'abc', 1})
+---
+- ['abc', 1]
+...
+box.execute("CREATE INDEX i ON s (t_id);")
+---
+- row_count: 1
+...
+box.execute("DELETE FROM t WHERE id = 'abc';")
+---
+- row_count: 1
+...
+box.space.T:select()
+---
+- []
+...
+box.space.S:drop()
+---
+...
+box.space.T:drop()
+---
+...
 --- Clean-up SQL DD hash.
 -test_run:cmd('restart server default with cleanup=1')
diff --git a/test/sql/foreign-keys.test.lua b/test/sql/foreign-keys.test.lua
index 4ac5999d7c..d2dd88d280 100644
--- a/test/sql/foreign-keys.test.lua
+++ b/test/sql/foreign-keys.test.lua
@@ -194,5 +194,20 @@ box.execute("ALTER TABLE t2 ADD CONSTRAINT fk FOREIGN KEY (id) REFERENCES t1;")
 t1:drop()
 t2:drop()
 
+-- gh-4495: space alter resulted in foreign key mask reset.
+-- Which in turn led to wrong byte-code generation. Make sure
+-- that alter of space doesn't affect result of query execution.
+--
+box.execute("CREATE TABLE t (id TEXT PRIMARY KEY, a INTEGER NOT NULL);")
+box.execute("CREATE TABLE s (t_id TEXT PRIMARY KEY, a INTEGER NOT NULL, FOREIGN KEY(t_id) REFERENCES t(id) ON DELETE CASCADE);")
+box.space.T:insert({'abc', 1})
+box.space.S:insert({'abc', 1})
+box.execute("CREATE INDEX i ON s (t_id);")
+box.execute("DELETE FROM t WHERE id = 'abc';")
+box.space.T:select()
+
+box.space.S:drop()
+box.space.T:drop()
+
 --- Clean-up SQL DD hash.
 -test_run:cmd('restart server default with cleanup=1')
-- 
GitLab