Skip to content

Commit

Permalink
box: fix creation of CK and FK constraints on the same field
Browse files Browse the repository at this point in the history
Fix a simple typo that caused the problem.

Closes tarantool#7645

NO_DOC=bugfix
  • Loading branch information
alyapunov authored and locker committed Oct 12, 2022
1 parent 805cbaa commit 6e45042
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## bugfix/core

* Fixed creation of a space with check and foreign constraints on the same
field (gh-7645).
8 changes: 4 additions & 4 deletions src/box/tuple_constraint_def.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ tuple_constraint_def_decode(const char **data,
if (*count == 0)
return 0;

int bytes;
size_t bytes;
*def = region_alloc_array(region, struct tuple_constraint_def,
*count, &bytes);
if (*def == NULL) {
Expand All @@ -117,7 +117,7 @@ tuple_constraint_def_decode(const char **data,
for (size_t i = 0; i < map_size; i++)
new_def[i].type = CONSTR_FUNC;

for (size_t i = 0; i < map_size; i++) {
for (uint32_t i = 0; i < map_size; i++) {
if (mp_typeof(**data) != MP_STR) {
diag_set(ClientError, errcode,
"constraint name is expected to be a string");
Expand Down Expand Up @@ -268,7 +268,7 @@ tuple_constraint_def_decode_fkey(const char **data,
if (*count == 0)
return 0;

int bytes;
size_t bytes;
*def = region_alloc_array(region, struct tuple_constraint_def,
*count, &bytes);
if (*def == NULL) {
Expand All @@ -279,7 +279,7 @@ tuple_constraint_def_decode_fkey(const char **data,
(*def)[i] = old_def[i];
struct tuple_constraint_def *new_def = *def + old_count;

for (size_t i = 0; i < *count; i++) {
for (uint32_t i = 0; i < map_size; i++) {
if (mp_typeof(**data) != MP_STR) {
diag_set(ClientError, errcode,
"foreign key name is expected to be a string");
Expand Down
115 changes: 115 additions & 0 deletions test/engine-luatest/gh_7645_ck_fk_constraints_test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
-- https://github.com/tarantool/tarantool/issues/7645
local server = require('test.luatest_helpers.server')
local t = require('luatest')
local g = t.group('gh-7645-ck-fk-constraints', {{engine = 'memtx'},
{engine = 'vinyl'}})

g.before_all(function(cg)
cg.server = server:new({alias = 'master'})
cg.server:start()
end)

g.after_all(function(cg)
cg.server:stop()
cg.server = nil
end)

-- Check that check and foreign key constraints work well on the same field.
g.test_field_ck_fk_constraints = function(cg)
local engine = cg.params.engine

cg.server:exec(function(engine)
local t = require('luatest')
local city_fmt = {{'id', 'integer'}, {'name', 'string'}}
local city = box.schema.space.create('city', {engine = engine,
format = city_fmt})
city:create_index('pk')
city:replace{1, 'Moscow'}
city:replace{100, 'Amsterdam'}

local body = "function(x) return x < 100 end"
box.schema.func.create('check', {is_deterministic = true, body = body})
local user_fmt = {{'id', 'integer'},
{'city_id', 'integer'},
{'name', 'string'}}
user_fmt[2].constraint = {ck = 'check'}
user_fmt[2].foreign_key = {city = {space = 'city', field = 'id'}}
local space_opts = {engine = engine, format = user_fmt}
local user = box.schema.space.create('user', space_opts)
user:create_index('pk')
user:replace{1, 1, 'Alice'}
t.assert_error_msg_content_equals(
"Foreign key constraint 'city' failed for field" ..
" '2 (city_id)': foreign tuple was not found",
function() user:replace({2, 99, 'Bob'}) end
)
t.assert_error_msg_content_equals(
"Check constraint 'ck' failed for field '2 (city_id)'",
function() user:replace{2, 100, 'Bob'} end
)
end, {engine})
end

g.after_test('test_field_ck_fk_constraints', function(cg)
cg.server:exec(function()
if box.space.user then
box.space.user:drop()
end
if box.func.check then
box.func.check:drop()
end
if box.space.city then
box.space.city:drop()
end
end)
end)

-- Check that check and foreign key constraints work well on the same field.
g.test_tuple_ck_fk_constraints = function(cg)
local engine = cg.params.engine

cg.server:exec(function(engine)
local t = require('luatest')
local city_fmt = {{'id', 'integer'}, {'name', 'string'}}
local city = box.schema.space.create('city', {engine = engine,
format = city_fmt})
city:create_index('pk')
city:replace{1, 'Moscow'}
city:replace{100, 'Amsterdam'}

local body = "function(tuple) return tuple.city_id < 100 end"
box.schema.func.create('check', {is_deterministic = true, body = body})
local user_fmt = {{'id', 'integer'},
{'city_id', 'integer'},
{'name', 'string'}}
local foreign_key = {city = {space = 'city', field = {city_id = 'id'}}}
local space_opts = {engine = engine, format = user_fmt,
constraint = {check = 'check'},
foreign_key = foreign_key}
local user = box.schema.space.create('user', space_opts)
user:create_index('pk')
user:replace{1, 1, 'Alice'}
t.assert_error_msg_content_equals(
"Foreign key constraint 'city' failed: foreign tuple was not found",
function() user:replace({2, 99, 'Bob'}) end
)
t.assert_error_msg_content_equals(
"Check constraint 'check' failed for tuple",
function() user:replace{2, 100, 'Bob'} end
)
end, {engine})
end

g.after_test('test_tuple_ck_fk_constraints', function(cg)
cg.server:exec(function()
if box.space.user then
box.space.user:drop()
end
if box.func.check then
box.func.check:drop()
end
if box.space.city then
box.space.city:drop()
end
end)
end)

0 comments on commit 6e45042

Please sign in to comment.