From 198178101da6263f5d37d496afd1955431b09fc4 Mon Sep 17 00:00:00 2001 From: Magomed Kostoev <mkostoevr@yandex.ru> Date: Thu, 27 Jul 2023 11:33:57 +0300 Subject: [PATCH] box: make box.schema DDL functions transactional Wraps multistatement DDL functions into begin/commit block if no transaction is active. The functions are: - `box.schema.space.drop` - `box.schema.index.create` - `box.schema.index.drop` - `box.schema.index.alter` - `box.schema.sequence.drop` - `box.schema.func.drop` - `box.schema.user.create` - `box.schema.user.drop` - `box.schema.role.drop` Added tests for atomicity of each transactioned function except the `box.schema.role.drop`, which is implicitly tested with the `box.schema.user.drop` test, and the `box.schema.index.drop`, which is impossible to test in this flavor without using error injection. Updated the tests modified in tarantool/tarantool#8947, because the space drop is atomic now. Closes #4348 NO_DOC=bugfix --- .../unreleased/gh-4348-transactional-ddl.md | 4 + src/box/lua/schema.lua | 70 +++-- test/box-luatest/builtin_events_test.lua | 2 +- .../gh_4348_transactional_ddl_test.lua | 271 ++++++++++++++++++ test/box/errinj.result | 10 + test/box/errinj.test.lua | 6 + test/box/sequence.result | 2 +- test/box/sequence.test.lua | 2 +- .../gh_6436_complex_foreign_key_test.lua | 6 +- .../gh_6436_field_foreign_key_test.lua | 6 +- test/engine/func_index.result | 3 - test/engine/func_index.test.lua | 1 - test/sql/no-pk-space.result | 27 -- test/sql/no-pk-space.test.lua | 11 - 14 files changed, 340 insertions(+), 81 deletions(-) create mode 100644 changelogs/unreleased/gh-4348-transactional-ddl.md create mode 100644 test/box-luatest/gh_4348_transactional_ddl_test.lua diff --git a/changelogs/unreleased/gh-4348-transactional-ddl.md b/changelogs/unreleased/gh-4348-transactional-ddl.md new file mode 100644 index 0000000000..7bb0c04685 --- /dev/null +++ b/changelogs/unreleased/gh-4348-transactional-ddl.md @@ -0,0 +1,4 @@ +## bugfix/box + +* All DDL functions from the `box.schema` module are now wrapped into a + transaction to avoid database inconsistency on failed operations (gh-4348). diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 87f931ca43..d7043b0674 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -382,6 +382,18 @@ box.atomic = function(arg0, arg1, ...) end end +-- Wrap a function into transaction if none is active. +local function atomic_wrapper(func) + return function(...) + -- No reason to start a transaction if one is active already. + if box.is_in_txn() then + return func(...) + else + return box.atomic(func, ...) + end + end +end + -- box.commit yields, so it's defined as Lua/C binding -- box.rollback and box.rollback_to_savepoint yields as well @@ -820,7 +832,7 @@ end box.schema.create_space = box.schema.space.create -box.schema.space.drop = function(space_id, space_name, opts) +box.schema.space.drop = atomic_wrapper(function(space_id, space_name, opts) check_param(space_id, 'space_id', 'number') opts = opts or {} check_param_table(opts, { if_exists = 'boolean' }) @@ -872,7 +884,7 @@ box.schema.space.drop = function(space_id, space_name, opts) end feedback_save_event('drop_space') -end +end) box.schema.space.rename = function(space_id, space_name) check_param(space_id, 'space_id', 'number') @@ -1252,10 +1264,9 @@ local function space_sequence_check(sequence, parts, space_name, index_name) end -- --- The first stage of a space sequence modification operation. --- Called before altering the space definition. Checks sequence --- options and detaches the old sequence from the space. --- Returns a proxy object that is supposed to be passed to +-- The first stage of a space sequence modification operation. Called +-- before altering the space definition. Checks sequence options and +-- returns a proxy object that is supposed to be passed to the -- space_sequence_alter_commit() to complete the operation. -- local function space_sequence_alter_prepare(format, parts, options, @@ -1361,11 +1372,6 @@ local function space_sequence_alter_prepare(format, parts, options, new_sequence.is_generated = new_sequence.is_generated or false end - if old_sequence ~= nil then - -- Detach the old sequence before altering the space. - _space_sequence:delete(space_id) - end - return { space_id = space_id, new_sequence = new_sequence, @@ -1374,9 +1380,9 @@ local function space_sequence_alter_prepare(format, parts, options, end -- --- The second stage of a space sequence modification operation. --- Called after altering the space definition. Attaches the sequence --- to the space and drops the old sequence if required. 'proxy' is +-- The second stage of a space sequence modification operation. Called after +-- altering the space definition. Detaches the old sequence from the space and +-- attaches the new one to it. Drops the old sequence if required. 'proxy' is -- an object returned by space_sequence_alter_prepare(). -- local function space_sequence_alter_commit(proxy) @@ -1391,6 +1397,10 @@ local function space_sequence_alter_commit(proxy) local old_sequence = proxy.old_sequence local new_sequence = proxy.new_sequence + if old_sequence ~= nil then + _space_sequence:delete(space_id) + end + if new_sequence ~= nil then -- Attach the new sequence. _space_sequence:insert{space_id, new_sequence.id, @@ -1476,7 +1486,7 @@ local function func_id_by_name(func_name) end box.internal.func_id_by_name = func_id_by_name -- for space.upgrade -box.schema.index.create = function(space_id, name, options) +box.schema.index.create = atomic_wrapper(function(space_id, name, options) check_param(space_id, 'space_id', 'number') check_param(name, 'name', 'string') check_param_table(options, create_index_template) @@ -1599,9 +1609,9 @@ box.schema.index.create = function(space_id, name, options) feedback_save_event('create_index') return space.index[name] -end +end) -box.schema.index.drop = function(space_id, index_id) +box.schema.index.drop = atomic_wrapper(function(space_id, index_id) check_param(space_id, 'space_id', 'number') check_param(index_id, 'index_id', 'number') if index_id == 0 then @@ -1625,7 +1635,7 @@ box.schema.index.drop = function(space_id, index_id) _index:delete{space_id, index_id} feedback_save_event('drop_index') -end +end) box.schema.index.rename = function(space_id, index_id, name) check_param(space_id, 'space_id', 'number') @@ -1636,7 +1646,7 @@ box.schema.index.rename = function(space_id, index_id, name) _index:update({space_id, index_id}, {{"=", 3, name}}) end -box.schema.index.alter = function(space_id, index_id, options) +box.schema.index.alter = atomic_wrapper(function(space_id, index_id, options) local space = box.space[space_id] if space == nil then box.error(box.error.NO_SUCH_SPACE, '#'..tostring(space_id)) @@ -1739,7 +1749,7 @@ box.schema.index.alter = function(space_id, index_id, options) _func_index:insert{space_id, index_id, index_opts.func} end space_sequence_alter_commit(sequence_proxy) -end +end) -- a static box_tuple_t ** instance for calling box_index_* API local ptuple = ffi.new('box_tuple_t *[1]') @@ -2850,7 +2860,7 @@ box.schema.sequence.alter = function(name, opts) opts.max, opts.start, opts.cache, opts.cycle} end -box.schema.sequence.drop = function(name, opts) +box.schema.sequence.drop = atomic_wrapper(function(name, opts) opts = opts or {} check_param_table(opts, {if_exists = 'boolean'}) local id = sequence_resolve(name) @@ -2865,7 +2875,7 @@ box.schema.sequence.drop = function(name, opts) local _sequence_data = box.space[box.schema.SEQUENCE_DATA_ID] _sequence_data:delete{id} _sequence:delete{id} -end +end) local function privilege_parse(privs) -- TODO: introduce a global privilege -> bit mapping? @@ -3142,7 +3152,7 @@ box.schema.func.create = function(name, opts) opts.comment, opts.created, opts.last_altered} end -box.schema.func.drop = function(name, opts) +box.schema.func.drop = atomic_wrapper(function(name, opts) opts = opts or {} check_param_table(opts, { if_exists = 'boolean' }) local _func = box.space[box.schema.FUNC_ID] @@ -3165,7 +3175,7 @@ box.schema.func.drop = function(name, opts) end revoke_object_privs('function', fid) _func:delete{fid} -end +end) function box.schema.func.exists(name_or_id) local _vfunc = box.space[box.schema.VFUNC_ID] @@ -3326,7 +3336,7 @@ box.schema.user.passwd = function(name, new_password) end end -box.schema.user.create = function(name, opts) +box.schema.user.create = atomic_wrapper(function(name, opts) local uid = user_or_role_resolve(name) opts = opts or {} check_param_table(opts, { password = 'string', if_not_exists = 'boolean' }) @@ -3356,7 +3366,7 @@ box.schema.user.create = function(name, opts) -- grant option box.session.su('admin', box.schema.user.grant, uid, 'session,usage', 'universe', nil, {if_not_exists=true}) -end +end) box.schema.user.exists = function(name) if user_resolve(name) then @@ -3542,7 +3552,7 @@ box.schema.user.disable = function(user) {if_exists = true}) end -box.schema.user.drop = function(name, opts) +box.schema.user.drop = atomic_wrapper(function(name, opts) opts = opts or {} check_param_table(opts, { if_exists = 'boolean' }) local uid = user_resolve(name) @@ -3563,7 +3573,7 @@ box.schema.user.drop = function(name, opts) box.error(box.error.NO_SUCH_USER, name) end return -end +end) local function info(id) local _priv = box.space._vpriv @@ -3616,7 +3626,7 @@ box.schema.role.create = function(name, opts) math.floor(fiber.time())} end -box.schema.role.drop = function(name, opts) +box.schema.role.drop = atomic_wrapper(function(name, opts) opts = opts or {} check_param_table(opts, { if_exists = 'boolean' }) local uid = role_resolve(name) @@ -3632,7 +3642,7 @@ box.schema.role.drop = function(name, opts) box.error(box.error.DROP_USER, name, "the user or the role is a system") end return drop(uid) -end +end) local function role_check_grant_revoke_of_sys_priv(priv) priv = string.lower(priv) diff --git a/test/box-luatest/builtin_events_test.lua b/test/box-luatest/builtin_events_test.lua index 9e37097b13..bba16da828 100644 --- a/test/box-luatest/builtin_events_test.lua +++ b/test/box-luatest/builtin_events_test.lua @@ -278,7 +278,7 @@ g.test_box_schema = function(cg) version_n = 0 cg.master:exec(function() box.space.p:drop() end) - t.helpers.retrying({}, function() t.assert_equals(version_n, 2) end) + t.helpers.retrying({}, function() t.assert_equals(version_n, 1) end) -- there'll be 2 changes - index and space t.assert_equals(version, init_version + 4) diff --git a/test/box-luatest/gh_4348_transactional_ddl_test.lua b/test/box-luatest/gh_4348_transactional_ddl_test.lua new file mode 100644 index 0000000000..cbaf96b813 --- /dev/null +++ b/test/box-luatest/gh_4348_transactional_ddl_test.lua @@ -0,0 +1,271 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group('gh-4348-transactional-ddl-test', + t.helpers.matrix({mvcc = {true, false}})) + +g.before_all(function(cg) + cg.server = server:new({ + box_cfg = {memtx_use_mvcc_engine = cg.params.mvcc} + }) + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +g.after_each(function(cg) + cg.server:exec(function() + if box.space.s ~= nil then + box.space.s:drop() + end + if box.space.s2 ~= nil then + box.space.s2:drop() + end + box.schema.func.drop('f', {if_exists = true}) + box.schema.sequence.drop('seq', {if_exists = true}) + box.schema.user.drop('new_user', {if_exists = true}) + box.schema.user.drop('new_user_2', {if_exists = true}) + end) +end) + +g.test_atomic_space_drop = function(cg) + cg.server:exec(function() + local s = box.schema.space.create('s') + local s2 = box.schema.space.create('s2') + + s:create_index('pk') + s2:create_index('pk') + + local s2sk = s2:create_index('sk') + + s2:insert({2}) + s:insert({1, 2}) + + box.schema.space.alter(s.id, {foreign_key = { + f1 = {space = s2.name, field = {[2] = 1}}, + }}) + + -- Attempt tp drop a referenced foreign key space with secondary + -- indexes. + -- + -- Currently the space drop flow looks like this: + -- 1. Drop automatically generated sequence for the space. + -- 2. Drop triggers of the space. + -- 3. Disable functional indexes of the space. + -- 4. (!) Remove each index of the space starting from secondary + -- indexes. + -- 5. Revoke the space privileges. + -- 6. Remove the associated entry from the _truncate system space. + -- 7. Remove the space entry from _space system space. + -- + -- If the space is referenced by another space with foreign key + -- constraint then the flow fails on the primary index drop (step 4). + -- But at that point all the secondary indexes are dropped already, so + -- we have an inconsistent state of the database. + -- + -- But if the drop function is transactional then the dropped secondary + -- indexes are restored on transaction revert and the database remains + -- consistent: we can continue using the secondary index of the table we + -- have failed to drop. + + local err = "Can't modify space '" .. s2.name + .. "': space is referenced by foreign key" + t.assert_error_msg_equals(err, s2.drop, s2) + + -- The secondary index is restored on drop fail so this must succeed. + s2sk:select(42) + end) +end + + +g.test_atomic_index_create = function(cg) + cg.server:exec(function() + local s = box.schema.space.create('s') + s:create_index('pk', {parts = {{1, 'scalar'}}}) + + -- Currently on the index creation _func_index entry is created after + -- the _index space is modified, so if the error is thrown on performing + -- function ID check, the new index is registered already. + -- + -- If the index creation is not transactional then we gonna have a new + -- disabled functional index. But if it is then the index creation is + -- rolled back. + + local err = "Function '42' does not exist" + t.assert_error_msg_equals(err, s.create_index, s, 'fk', {func = 42}) + + -- The created index should be dropped if the index creation is atomic. + t.assert_equals(box.space.s.index.fk, nil) + end) +end + +-- The index drop is not testable without error injection. + +g.test_atomic_index_alter = function(cg) + cg.server:exec(function() + local s = box.schema.space.create('s') + s:create_index('pk', {parts = {{1, 'scalar'}}}) + local sk = s:create_index('sk') + + -- Currently on the index alter _func_index entry is created after the + -- _index space is modified, so if the error is thrown on performing + -- function ID check, the index is altered already. + -- + -- If the index creation is not transactional then we gonna have a + -- disabled functional index. But if it is then the index alter is + -- rolled back. + + local err = "Function '42' does not exist" + t.assert_error_msg_equals(err, sk.alter, sk, {name = 'fk', func = 42}) + + -- The index name should be reverted if the index alter is atomic. + t.assert_equals(box.space.s.index[1].name, 'sk') + end) +end + +g.test_atomic_sequence_drop = function(cg) + cg.server:exec(function() + local s = box.schema.space.create('s') + s:create_index('pk', {sequence = true}) + + -- The sequence drop routine first drops the corresponding entry from + -- the _sequence_data space and then drops the sequence itself. So + -- if the routine is not atomic we will observe the sequence reset + -- on failed attempt to drop it. If it's not - the sequence data will + -- be restored. + + -- Create an entry in the _sequence_data. + box.space._sequence_data:insert({1, 42}) + + -- Attempt to drop the sequence which is in use by the 's' space. + local err = "Can't drop sequence 's_seq': the sequence is in use" + t.assert_error_msg_equals(err, box.schema.sequence.drop, 's_seq') + + -- The dropped _sequence_data entry should be restored. + t.assert_equals(box.space._sequence_data:select(), {{1, 42}}) + + -- A new item should have the correct ID (which is 43). + t.assert_equals(s:insert({nil, 1})[1], 43) + end) +end + +g.test_atomic_func_drop = function(cg) + cg.server:exec(function() + local s = box.schema.space.create('s') + s:create_index('pk') + + box.schema.func.create('f', { + language = 'LUA', + is_deterministic = true, + is_sandboxed = true, + body = 'function() return {1} end' + }) + + -- Use the function in a functional index. + s:create_index('fk', {func = 'f'}) + + -- Add an entry to the _priv space. + box.schema.user.grant('admin', 'execute', 'function', 'f') + + -- Attempt to drop the function which is in use. + local err = "function has references" + t.assert_error_msg_contains(err, box.schema.func.drop, 'f') + + -- Check if the dropped privileges had been restored. If it's not the + -- case then the following privilege revocation will fail. + box.schema.user.revoke('admin', 'execute', 'function', 'f') + end) +end + +g.test_atomic_user_create = function(cg) + cg.server:exec(function() + -- Nothing should be there yet. + t.assert_equals(box.space.s, nil) + t.assert_equals(box.schema.user.exists('new_user'), false) + + -- The user creation procedure includes creation of an entry in the + -- _user space and granting him some privileges. In case if the user + -- creator does not have rights to grant privilegies to other users + -- then the privilege granting part will fail. + -- + -- In order to check that the creation is atomic, we create a user + -- unable to grant ay privileges to any other user and so we make + -- the user creation fail on privilege grant part. The created user + -- should be dropped on the transaction rollback. + + local original_user = box.session.euid() + + -- Create a new user that can't grant any privileges. + box.session.su('admin') + box.schema.user.create('new_user') + box.schema.user.grant('new_user', 'read,write', 'space', '_user') + box.schema.user.grant('new_user', 'create', 'user') + + -- Attempt to create a used by this user will fail on privilege + -- assignment stage, because he can't access the _priv space. + box.session.su('new_user') + local err = "Write access to space '_priv' is denied for user" + t.assert_error_msg_contains(err, box.schema.user.create, 'new_user_2') + + box.session.su(original_user) + + -- Check if the new user had been dropped after transaction rollback. + t.assert_equals(box.schema.user.exists('new_user_2'), false) + end) +end + +-- box.schema.role.drop is a variation of box.schema.user.drop. +g.test_atomic_user_drop = function(cg) + cg.server:exec(function() + -- Nothing should be there yet. + t.assert_equals(box.space.s, nil) + t.assert_equals(box.sequence.seq, nil) + t.assert_equals(box.schema.user.exists('new_user'), false) + + -- The user drop is not just removal of an entry from the _user space. + -- All the objects created by the user should be dropped too, including + -- (but not limited to) spaces and sequences. + -- + -- The spaces are dropped first, and, at some point later, we drop the + -- user's sequences. That means in case if the user drop is not atomic, + -- then it's possible the situation when we succeed to drop all spaces, + -- but failed to drop a sequence. In this case we are going to have an + -- inconsistent state: the changes are partially applied. + -- + -- So here we create a user, make him create a space and a sequence, and + -- then, in order to make the sequence drop fail, we use the sequence in + -- an admin's space. So attempt drop a user will cause the sequence drop + -- which will fail, because the sequence is in use by admin's space. + -- + -- In order to check that the drop is atomic, we check if the space that + -- had been dropped within the transaction, will still be there once the + -- transaction is rolled back on failure. + + -- Create a new user and make him create a new space and sequence. + local original_user = box.session.euid() + box.session.su('admin') + box.schema.user.create('new_user') + box.schema.user.grant('new_user', + 'create,drop,read,write,execute', 'universe') + box.session.su('new_user', box.schema.space.create, 's') + box.session.su('new_user', box.schema.sequence.create, 'seq') + box.session.su(original_user) + + -- Use the sequence created by the new user. + local s2 = box.schema.space.create('s2') + s2:create_index('pk', {sequence = 'seq'}) + + -- Attempt to drop the user will fail, because it drops everything that + -- had been created by the user, including sequences. But the sequence + -- created by the user is used by admin in his space. + local err = "Can't drop sequence 'seq': the sequence is in use" + t.assert_error_msg_equals(err, box.schema.user.drop, 'new_user') + + -- The sequence drop attempt happens after drop of all user spaces, but + -- the dropped space should be recovered by the rollback if the space + -- drop is transactional. + t.assert_not_equals(box.space.s, nil) + end) +end diff --git a/test/box/errinj.result b/test/box/errinj.result index 6c2dd1ea27..7af6163f7d 100644 --- a/test/box/errinj.result +++ b/test/box/errinj.result @@ -415,6 +415,11 @@ s_withdata:drop() --- - error: Failed to write to disk ... +-- FIXME(gh-9120): The space is recreated, so the s_withdata object is not +-- valid anymore. +s_withdata = box.space.withdata +--- +... box.space['withdata'].enabled --- - true @@ -1335,6 +1340,11 @@ s:drop() --- - error: Failed to write to disk ... +-- FIXME(gh-9120): The space object is invalidated on reverted drop, so we set +-- it to the current one. +s = box.space.test +--- +... s:truncate() --- - error: Failed to write to disk diff --git a/test/box/errinj.test.lua b/test/box/errinj.test.lua index 78047408d6..e2219529fa 100644 --- a/test/box/errinj.test.lua +++ b/test/box/errinj.test.lua @@ -100,6 +100,9 @@ s_withindex.index.secondary s_withdata.index.secondary:drop() s_withdata.index.secondary.unique s_withdata:drop() +-- FIXME(gh-9120): The space is recreated, so the s_withdata object is not +-- valid anymore. +s_withdata = box.space.withdata box.space['withdata'].enabled index4 = s_withdata:create_index('another', { type = 'tree', parts = { 5, 'unsigned' }, unique = false}) s_withdata.index.another @@ -447,6 +450,9 @@ errinj.set('ERRINJ_WAL_IO', true) s:drop() s:truncate() s:drop() +-- FIXME(gh-9120): The space object is invalidated on reverted drop, so we set +-- it to the current one. +s = box.space.test s:truncate() errinj.set('ERRINJ_WAL_IO', false) for i = 1, 10 do s:replace{i + 10} end diff --git a/test/box/sequence.result b/test/box/sequence.result index b49540983a..0803609159 100644 --- a/test/box/sequence.result +++ b/test/box/sequence.result @@ -1722,7 +1722,7 @@ box.space._space_sequence:replace{s2.id, sq1.id, false, 0, ''} -- error --- - error: Read access to sequence 'seq1' is denied for user 'user' ... -s2.index.pk:alter({sequence = 'seq2'}) -- ok +_ = s2:create_index('pk', {sequence = 'seq2'}) -- ok --- ... box.session.su('admin') diff --git a/test/box/sequence.test.lua b/test/box/sequence.test.lua index 21a56f5b46..0b7b411f48 100644 --- a/test/box/sequence.test.lua +++ b/test/box/sequence.test.lua @@ -569,7 +569,7 @@ s1.index.pk:alter({sequence = 'seq1'}) -- error box.space._space_sequence:replace{s1.id, sq1.id, false, 0, ''} -- error box.space._space_sequence:replace{s1.id, sq2.id, false, 0, ''} -- error box.space._space_sequence:replace{s2.id, sq1.id, false, 0, ''} -- error -s2.index.pk:alter({sequence = 'seq2'}) -- ok +_ = s2:create_index('pk', {sequence = 'seq2'}) -- ok box.session.su('admin') -- If the user owns a sequence attached to a space, diff --git a/test/engine-luatest/gh_6436_complex_foreign_key_test.lua b/test/engine-luatest/gh_6436_complex_foreign_key_test.lua index 9a26e28516..2a0a4f517b 100644 --- a/test/engine-luatest/gh_6436_complex_foreign_key_test.lua +++ b/test/engine-luatest/gh_6436_complex_foreign_key_test.lua @@ -109,7 +109,7 @@ g.test_complex_foreign_key_primary = function(cg) t.assert_equals(country:select{}, {{1, 11, 'Russia'}, {1, 12, 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_error_msg_content_equals( "Foreign key 'country' integrity check failed: wrong foreign field name", @@ -198,7 +198,7 @@ g.test_complex_foreign_key_secondary = function(cg) {101, 1, 'earth', 'rf', 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_equals(country:select{}, {{100, 1, 'earth', 'ru', 'Russia'}, {101, 1, 'earth', 'rf', 'France'}}) @@ -293,7 +293,7 @@ g.test_complex_foreign_key_numeric = function(cg) {101, 1, 'earth', 'rf', 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_equals(country:select{}, {{100, 1, 'earth', 'ru', 'Russia'}, {101, 1, 'earth', 'rf', 'France'}}) diff --git a/test/engine-luatest/gh_6436_field_foreign_key_test.lua b/test/engine-luatest/gh_6436_field_foreign_key_test.lua index bdb04acde4..c6a34a7ac9 100644 --- a/test/engine-luatest/gh_6436_field_foreign_key_test.lua +++ b/test/engine-luatest/gh_6436_field_foreign_key_test.lua @@ -137,7 +137,7 @@ g.test_foreign_key_primary = function(cg) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( @@ -215,7 +215,7 @@ g.test_foreign_key_secondary = function(cg) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( @@ -297,7 +297,7 @@ g.test_foreign_key_numeric = function(cg) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( "Can't modify space 'country': space is referenced by foreign key", - box.atomic, country.drop, country + country.drop, country ) t.assert_equals(country:select{}, {{1, 'ru', 'Russia'}, {2, 'fr', 'France'}}) t.assert_error_msg_content_equals( diff --git a/test/engine/func_index.result b/test/engine/func_index.result index 40573bbfb0..fc7166afc4 100644 --- a/test/engine/func_index.result +++ b/test/engine/func_index.result @@ -57,9 +57,6 @@ _ = s:create_index('idx', {func = 6666, parts = {{1, 'unsigned'}}}) | --- | - error: Function '6666' does not exist | ... -s.index.idx:drop() - | --- - | ... -- Can't use non-persistent function in functional index. _ = s:create_index('idx', {func = box.func.s_nonpersistent.id, parts = {{1, 'unsigned'}}}) | --- diff --git a/test/engine/func_index.test.lua b/test/engine/func_index.test.lua index 3b48bb478f..8b26769705 100644 --- a/test/engine/func_index.test.lua +++ b/test/engine/func_index.test.lua @@ -21,7 +21,6 @@ _ = s:create_index('idx', {func = box.func.s.id, parts = {{1, 'unsigned'}}}) pk = s:create_index('pk') -- Invalid fid. _ = s:create_index('idx', {func = 6666, parts = {{1, 'unsigned'}}}) -s.index.idx:drop() -- Can't use non-persistent function in functional index. _ = s:create_index('idx', {func = box.func.s_nonpersistent.id, parts = {{1, 'unsigned'}}}) -- Can't use non-deterministic function in functional index. diff --git a/test/sql/no-pk-space.result b/test/sql/no-pk-space.result index 12f2407d80..e7f79da014 100644 --- a/test/sql/no-pk-space.result +++ b/test/sql/no-pk-space.result @@ -39,30 +39,3 @@ box.execute("UPDATE \"test\" SET id = 3;") s:drop() --- ... --- Notorious artefact: check of view referencing counter occurs --- after drop of indexes. So, if space:drop() fails due to being --- referenced by a view, space becomes unusable in SQL terms. --- -box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);") ---- -- row_count: 1 -... -box.execute("CREATE VIEW v1 AS SELECT * FROM t1;") ---- -- row_count: 1 -... -box.space.T1:drop() ---- -- error: 'Can''t drop space ''T1'': other views depend on this space' -... -box.execute("SELECT * FROM v1;") ---- -- null -- SQL does not support spaces without primary key -... -box.space.V1:drop() ---- -... -box.space.T1:drop() ---- -... diff --git a/test/sql/no-pk-space.test.lua b/test/sql/no-pk-space.test.lua index d7f9479213..7e02b9beec 100644 --- a/test/sql/no-pk-space.test.lua +++ b/test/sql/no-pk-space.test.lua @@ -11,14 +11,3 @@ box.execute("DELETE FROM \"test\";") box.execute("UPDATE \"test\" SET id = 3;") s:drop() - --- Notorious artefact: check of view referencing counter occurs --- after drop of indexes. So, if space:drop() fails due to being --- referenced by a view, space becomes unusable in SQL terms. --- -box.execute("CREATE TABLE t1 (id INT PRIMARY KEY);") -box.execute("CREATE VIEW v1 AS SELECT * FROM t1;") -box.space.T1:drop() -box.execute("SELECT * FROM v1;") -box.space.V1:drop() -box.space.T1:drop() -- GitLab