From 50a4a87a63cc9db9a162db8993548f3a473f6157 Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov.dev@gmail.com>
Date: Tue, 20 Jun 2017 13:41:33 +0300
Subject: [PATCH] alter: proscribe space truncate in transaction

Space truncation is implemented as recreation of a space and all its
indexes. On success the original space is deleted by the commit trigger,
while on failure the new space is deleted by the rollback trigger. The
commit/rollback triggers are always called before commit/rollback engine
methods, which makes space truncation incompatible with transactions:
engine commit/rollback may access a space that have already been deleted
by commit/rollback trigger installed by space truncation, resulting in a
crash. So let's forbid to use space.truncate from a transaction until
triggers are made transaction-friendly.

Closes #2525
---
 src/box/alter.cc              |  1 +
 test/engine/truncate.result   | 29 +++++++++++++++++++++++++++++
 test/engine/truncate.test.lua | 12 ++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 95027043e8..32d3cea5f0 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -1397,6 +1397,7 @@ on_replace_dd_truncate(struct trigger * /* trigger */, void *event)
 {
 	struct txn *txn = (struct txn *) event;
 	struct txn_stmt *stmt = txn_current_stmt(txn);
+	txn_check_autocommit(txn, "Space _truncate");
 	struct tuple *old_tuple = stmt->old_tuple;
 	struct tuple *new_tuple = stmt->new_tuple;
 
diff --git a/test/engine/truncate.result b/test/engine/truncate.result
index 91153e2f17..01be5ffecb 100644
--- a/test/engine/truncate.result
+++ b/test/engine/truncate.result
@@ -8,6 +8,35 @@ fiber =  require('fiber')
 ---
 ...
 --
+-- Check that space truncation is forbidden in a transaction.
+--
+s = box.schema.create_space('test', {engine = engine})
+---
+...
+_ = s:create_index('pk')
+---
+...
+_ = s:insert{123}
+---
+...
+box.begin()
+---
+...
+s:truncate()
+---
+- error: Space _truncate does not support multi-statement transactions
+...
+box.commit()
+---
+...
+s:select()
+---
+- - [123]
+...
+s:drop()
+---
+...
+--
 -- Truncate space with no indexes.
 --
 s = box.schema.create_space('test', {engine = engine})
diff --git a/test/engine/truncate.test.lua b/test/engine/truncate.test.lua
index 41f5694d19..0f6addd58a 100644
--- a/test/engine/truncate.test.lua
+++ b/test/engine/truncate.test.lua
@@ -3,6 +3,18 @@ engine = test_run:get_cfg('engine')
 
 fiber =  require('fiber')
 
+--
+-- Check that space truncation is forbidden in a transaction.
+--
+s = box.schema.create_space('test', {engine = engine})
+_ = s:create_index('pk')
+_ = s:insert{123}
+box.begin()
+s:truncate()
+box.commit()
+s:select()
+s:drop()
+
 --
 -- Truncate space with no indexes.
 --
-- 
GitLab