diff --git a/test/storage-luatest/storage_1_test.lua b/test/storage-luatest/storage_1_test.lua index d84f25f7..4d671de7 100644 --- a/test/storage-luatest/storage_1_test.lua +++ b/test/storage-luatest/storage_1_test.lua @@ -674,3 +674,28 @@ test_group.test_info_disable_consistency = function(g) ilt.assert(res.is_enabled) end, {global_cfg}) end + +local function test_error_msg_is_preserved_template(g, add_to_schema) + g.replica_1_a:exec(function(add_to_schema) + rawset(_G, 'test_fail', function() + box.begin() + error('test_error') + end) + if add_to_schema then + box.schema.func.create('test_fail') + end + local status, err = ivshard.storage.call(1, 'read', 'test_fail', {}) + ilt.assert_not(status) + ilt.assert_str_contains(err.message, 'test_error') + ilt.assert_not_str_contains(err.message, 'Transaction is active') + rawset(_G, 'test_fail', nil) + if add_to_schema then + box.schema.func.drop('test_fail') + end + end, {add_to_schema}) +end + +test_group.test_error_msg_is_preserved = function(g) + test_error_msg_is_preserved_template(g, false) + test_error_msg_is_preserved_template(g, true) +end diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua index 30951e09..f62d150f 100644 --- a/vshard/storage/init.lua +++ b/vshard/storage/init.lua @@ -260,6 +260,20 @@ else end end +-- +-- If the function is called directly, fails, and leaves an uncommitted +-- transaction, the original error is replaced by the "Transaction is active" +-- error. We manually check if the function returned an error. If so, we +-- rollback the transaction to reveal the original error. +-- +local function handle_results(status, ...) + if not status then + box.rollback() + return status, box.error.new(box.error.PROC_LUA, (...)) + end + return status, ... +end + -- -- Invoke a function on this instance. Arguments are unpacked into the function -- as arguments. @@ -284,7 +298,7 @@ local_call = function(func_name, args) if not func then return pcall(netbox_self_call, netbox_self, func_name, args) end - return pcall(func.call, func, args) + return handle_results(pcall(func.call, func, args)) end end