diff --git a/changelogs/unreleased/gh-10099-vy-crash-on-invalid-upsert-fix.md b/changelogs/unreleased/gh-10099-vy-crash-on-invalid-upsert-fix.md new file mode 100644 index 0000000000000000000000000000000000000000..3dff68a29588b96cf618e680b610eda273ba1840 --- /dev/null +++ b/changelogs/unreleased/gh-10099-vy-crash-on-invalid-upsert-fix.md @@ -0,0 +1,4 @@ +## bugfix/vinyl + +* Fixed a bug when an `upsert` statement crashed in case the created tuple had + fields conflicting with the primary key definition (gh-10099). diff --git a/src/box/vy_upsert.c b/src/box/vy_upsert.c index fdae931f67c6f25a9c6dabb85c0be1e93a8d9894..6041843913639e9deaae38ee6966ef268c385ebf 100644 --- a/src/box/vy_upsert.c +++ b/src/box/vy_upsert.c @@ -132,6 +132,18 @@ vy_apply_upsert_on_terminal_stmt(struct tuple *upsert, struct tuple *stmt, ups_ops = ups_ops_end; continue; } + /* + * Result statement must satisfy space's format. Since upsert's + * tuple correctness is already checked in vy_upsert(), let's + * use its format to provide result verification. + */ + struct tuple_format *format = tuple_format(upsert); + if (tuple_validate_raw(format, exec_res) != 0) { + if (!suppress_error) + diag_log(); + ups_ops = ups_ops_end; + continue; + } /* * If it turns out that resulting tuple modifies primary * key, then simply ignore this upsert. @@ -148,17 +160,6 @@ vy_apply_upsert_on_terminal_stmt(struct tuple *upsert, struct tuple *stmt, continue; } ups_ops = ups_ops_end; - /* - * Result statement must satisfy space's format. Since upsert's - * tuple correctness is already checked in vy_upsert(), let's - * use its format to provide result verification. - */ - struct tuple_format *format = tuple_format(upsert); - if (tuple_validate_raw(format, exec_res) != 0) { - if (! suppress_error) - diag_log(); - continue; - } result_mp = exec_res; result_mp_end = exec_res + mp_size; } diff --git a/test/vinyl-luatest/gh_10099_invalid_upsert_test.lua b/test/vinyl-luatest/gh_10099_invalid_upsert_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..2349f7bbb78df4a1d873352f8375999f931ad700 --- /dev/null +++ b/test/vinyl-luatest/gh_10099_invalid_upsert_test.lua @@ -0,0 +1,42 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + 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.test ~= nil then + box.space.test:drop() + end + end) +end) + +g.test_invalid_upsert = function(cg) + cg.server:exec(function() + local s = box.schema.create_space('test', {engine = 'vinyl'}) + s:create_index('pk', {parts = {{1, 'integer'}}}) + s:insert({1}) + s:insert({2}) + s:insert({3}) + box.snapshot() + box.begin() + s:upsert({1}, {{'#', 1, 1}}) + s:upsert({2}, {{'=', 1, 's'}}) + s:upsert({3}, {{'=', 1, 1}}) + s:upsert({1}, {{'!', 2, 10}}) + s:upsert({2}, {{'!', 2, 20}}) + s:upsert({3}, {{'!', 2, 30}}) + box.commit() + t.assert_equals(s:select({}, {fullscan = true}), + {{1, 10}, {2, 20}, {3, 30}}) + end) +end