diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c index 9cdeb051b9b8323cb98db3eb2bf9ff4156e2421d..9b913306449563a471cd743a9e17cb4f6634541a 100644 --- a/src/box/tuple_format.c +++ b/src/box/tuple_format.c @@ -152,7 +152,7 @@ tuple_field_new(void) field->type = FIELD_TYPE_ANY; field->offset_slot = TUPLE_OFFSET_SLOT_NIL; field->coll_id = COLL_NONE; - field->nullable_action = ON_CONFLICT_ACTION_NONE; + field->nullable_action = ON_CONFLICT_ACTION_DEFAULT; field->multikey_required_fields = NULL; return field; } diff --git a/test/engine/json.result b/test/engine/json.result index e5a36a8f54cb98af2877488530e4f36d45ded9b6..9f0c896844cce2cc12c14828d68aff6dfb385f13 100644 --- a/test/engine/json.result +++ b/test/engine/json.result @@ -596,6 +596,9 @@ box.snapshot() - ok ... test_run:cmd("restart server default") +engine = test_run:get_cfg('engine') +--- +... s = box.space["withdata"] --- ... @@ -685,7 +688,7 @@ s:drop() ... -- Check replace with tuple with map having numeric keys that -- cannot be included in JSON index. -s = box.schema.space.create('withdata', {engine='vinyl'}) +s = box.schema.space.create('withdata', {engine = engine}) --- ... pk = s:create_index('pk', {parts={{1, 'int'}}}) @@ -716,8 +719,84 @@ s:insert({5, {1, 1, 1}, {{fname='A', sname='B'}, {fname='C', sname='D'}, {fname= - [5, [1, 1, 1], [{'fname': 'A', 'sname': 'B'}, {'fname': 'C', 'sname': 'D'}, {'fname': 'A', 'sname': 'B'}]] ... -s:delete(5) +_ = s:delete(5) +--- +... +s:drop() +--- +... +-- Check that null isn't allowed in case array/map is expected +-- according to json document format. +s = box.schema.space.create('test', {engine = engine}) +--- +... +_ = s:create_index('pk') +--- +... +_ = s:create_index('sk', {parts = {{'[2][1].a', 'unsigned'}}}) +--- +... +s:insert{1, box.NULL} -- error +--- +- error: 'Tuple field 2 type does not match one required by operation: expected array' +... +s:insert{2, {box.NULL}} -- error +--- +- error: 'Tuple field [2][1] type does not match one required by operation: expected + map' +... +s:insert{3} -- error +--- +- error: Tuple field [2][1]["a"] required by space format is missing +... +s:insert{4, {}} -- error +--- +- error: Tuple field [2][1]["a"] required by space format is missing +... +s:insert{5, {{b = 1}}} -- error +--- +- error: Tuple field [2][1]["a"] required by space format is missing +... +s:insert{6, {{a = 1}}} -- ok +--- +- [6, [{'a': 1}]] +... +s.index.sk:alter{parts = {{'[2][1].a', 'unsigned', is_nullable = true}}} +--- +... +s:insert{7, box.NULL} -- error +--- +- error: 'Tuple field 2 type does not match one required by operation: expected array' +... +s:insert{8, {box.NULL}} -- error +--- +- error: 'Tuple field [2][1] type does not match one required by operation: expected + map' +... +-- Skipping nullable fields is okay though. +s:insert{9} -- ok +--- +- [9] +... +s:insert{10, {}} -- ok +--- +- [10, []] +... +s:insert{11, {{b = 1}}} -- ok +--- +- [11, [{'b': 1}]] +... +s:insert{12, {{a = box.NULL}}} -- ok +--- +- [12, [{'a': null}]] +... +s.index.sk:select() --- +- - [9] + - [10, []] + - [11, [{'b': 1}]] + - [12, [{'a': null}]] + - [6, [{'a': 1}]] ... s:drop() --- diff --git a/test/engine/json.test.lua b/test/engine/json.test.lua index 592706e0e8cd42eda7e0a63ca10ad5217621592a..c6c207dc9bf75fc36bac4621b5d6722f2bf6a9db 100644 --- a/test/engine/json.test.lua +++ b/test/engine/json.test.lua @@ -171,6 +171,7 @@ name:select({'Max'}) name:get({'Max', 'Stierlitz', 'Otto'}) box.snapshot() test_run:cmd("restart server default") +engine = test_run:get_cfg('engine') s = box.space["withdata"] pk = s.index["pk"] name = s.index["name"] @@ -195,7 +196,7 @@ s:drop() -- Check replace with tuple with map having numeric keys that -- cannot be included in JSON index. -s = box.schema.space.create('withdata', {engine='vinyl'}) +s = box.schema.space.create('withdata', {engine = engine}) pk = s:create_index('pk', {parts={{1, 'int'}}}) idx0 = s:create_index('idx0', {parts = {{2, 'str', path = 'name'}, {3, "str"}}}) s:insert({4, {"d", name='D'}, "test"}) @@ -204,5 +205,27 @@ idx0:drop() s:truncate() idx0 = s:create_index('idx2', {parts = {{3, 'str', path = '[1].fname'}, {3, 'str', path = '[1].sname'}}}) s:insert({5, {1, 1, 1}, {{fname='A', sname='B'}, {fname='C', sname='D'}, {fname='A', sname='B'}}}) -s:delete(5) +_ = s:delete(5) +s:drop() + +-- Check that null isn't allowed in case array/map is expected +-- according to json document format. +s = box.schema.space.create('test', {engine = engine}) +_ = s:create_index('pk') +_ = s:create_index('sk', {parts = {{'[2][1].a', 'unsigned'}}}) +s:insert{1, box.NULL} -- error +s:insert{2, {box.NULL}} -- error +s:insert{3} -- error +s:insert{4, {}} -- error +s:insert{5, {{b = 1}}} -- error +s:insert{6, {{a = 1}}} -- ok +s.index.sk:alter{parts = {{'[2][1].a', 'unsigned', is_nullable = true}}} +s:insert{7, box.NULL} -- error +s:insert{8, {box.NULL}} -- error +-- Skipping nullable fields is okay though. +s:insert{9} -- ok +s:insert{10, {}} -- ok +s:insert{11, {{b = 1}}} -- ok +s:insert{12, {{a = box.NULL}}} -- ok +s.index.sk:select() s:drop() diff --git a/test/engine/multikey.result b/test/engine/multikey.result index 38c108ebc305e22fd1f5b3a4b107d5eb29b365ca..e7326cb96a2af92560762d260e3ab53a6893d85e 100644 --- a/test/engine/multikey.result +++ b/test/engine/multikey.result @@ -777,3 +777,61 @@ s:insert({"Jorge", {"911", "89457609234"}, 'a'}) s:drop() --- ... +-- +-- Inserting box.NULL where a multikey array is expected is +-- handled gracefully: no crashes, just an error message. +-- +s = box.schema.space.create('test', {engine = engine}) +--- +... +_ = s:create_index('pk') +--- +... +_ = s:create_index('sk', {parts = {{'[2][*]', 'unsigned'}}}) +--- +... +s:insert{1, box.NULL} -- error +--- +- error: 'Tuple field 2 type does not match one required by operation: expected array' +... +s:insert{2, {box.NULL}} -- error +--- +- error: 'Tuple field [2][*] type does not match one required by operation: expected + unsigned' +... +s:insert{3, {}} -- ok +--- +- [3, []] +... +s:insert{4, {1}} -- ok +--- +- [4, [1]] +... +s.index.sk:alter{parts = {{'[2][*]', 'unsigned', is_nullable = true}}} +--- +... +s:insert{5, box.NULL} -- still error +--- +- error: 'Tuple field 2 type does not match one required by operation: expected array' +... +s:insert{6, {box.NULL}} -- ok +--- +- [6, [null]] +... +s:insert{7, {}} -- ok +--- +- [7, []] +... +s:insert{8, {2}} -- ok +--- +- [8, [2]] +... +s.index.sk:select() +--- +- - [6, [null]] + - [4, [1]] + - [8, [2]] +... +s:drop() +--- +... diff --git a/test/engine/multikey.test.lua b/test/engine/multikey.test.lua index a2bef989f93db8b387366a95234ef3a2ab566e25..48eed2a3b055ef6c9ef387047375a1620088d969 100644 --- a/test/engine/multikey.test.lua +++ b/test/engine/multikey.test.lua @@ -205,3 +205,22 @@ phone_idx = s:create_index('phone_idx', {parts = {{'[2][*]', 'string'}, {3, 'str s:insert({"Genadiy", {"911"}, 'b'}) s:insert({"Jorge", {"911", "89457609234"}, 'a'}) s:drop() + +-- +-- Inserting box.NULL where a multikey array is expected is +-- handled gracefully: no crashes, just an error message. +-- +s = box.schema.space.create('test', {engine = engine}) +_ = s:create_index('pk') +_ = s:create_index('sk', {parts = {{'[2][*]', 'unsigned'}}}) +s:insert{1, box.NULL} -- error +s:insert{2, {box.NULL}} -- error +s:insert{3, {}} -- ok +s:insert{4, {1}} -- ok +s.index.sk:alter{parts = {{'[2][*]', 'unsigned', is_nullable = true}}} +s:insert{5, box.NULL} -- still error +s:insert{6, {box.NULL}} -- ok +s:insert{7, {}} -- ok +s:insert{8, {2}} -- ok +s.index.sk:select() +s:drop()