diff --git a/src/box/tuple.cc b/src/box/tuple.cc index bef792946884442c1bd8ac363be3ece24f90ca36..2d3d877654588a389b58b175430549019fa16558 100644 --- a/src/box/tuple.cc +++ b/src/box/tuple.cc @@ -79,7 +79,8 @@ field_type_create(enum field_type *types, uint32_t field_count, if (*ptype != UNKNOWN && *ptype != part->type) { tnt_raise(ClientError, ER_FIELD_TYPE_MISMATCH, - key_def->name, part - key_def->parts, + key_def->name, + part - key_def->parts + INDEX_OFFSET, field_type_strs[part->type], field_type_strs[*ptype]); } @@ -219,7 +220,8 @@ tuple_format_new(struct rlist *key_list) * format data. */ void -tuple_init_field_map(struct tuple_format *format, struct tuple *tuple, uint32_t *field_map) +tuple_init_field_map(struct tuple_format *format, struct tuple *tuple, + uint32_t *field_map) { if (format->field_count == 0) return; /* Nothing to initialize */ @@ -243,7 +245,8 @@ tuple_init_field_map(struct tuple_format *format, struct tuple *tuple, uint32_t enum mp_type mp_type = mp_typeof(*pos); mp_next(&pos); - key_mp_type_validate(*type, mp_type, ER_FIELD_TYPE, i); + key_mp_type_validate(*type, mp_type, ER_FIELD_TYPE, + i + INDEX_OFFSET); if (*offset < 0 && *offset != INT32_MIN) field_map[*offset] = d - tuple->data; @@ -356,7 +359,7 @@ tuple_next_cstr(struct tuple_iterator *it) if (field == NULL) tnt_raise(ClientError, ER_NO_SUCH_FIELD, fieldno); if (mp_typeof(*field) != MP_STR) - tnt_raise(ClientError, ER_FIELD_TYPE, fieldno, + tnt_raise(ClientError, ER_FIELD_TYPE, fieldno + INDEX_OFFSET, field_type_strs[STRING]); uint32_t len = 0; const char *str = mp_decode_str(&field, &len); @@ -376,7 +379,7 @@ tuple_field_cstr(struct tuple *tuple, uint32_t i) if (field == NULL) tnt_raise(ClientError, ER_NO_SUCH_FIELD, i); if (mp_typeof(*field) != MP_STR) - tnt_raise(ClientError, ER_FIELD_TYPE, i, + tnt_raise(ClientError, ER_FIELD_TYPE, i + INDEX_OFFSET, field_type_strs[STRING]); uint32_t len = 0; const char *str = mp_decode_str(&field, &len); @@ -628,7 +631,8 @@ double mp_decode_num(const char **data, uint32_t i) val = mp_decode_double(data); break; default: - tnt_raise(ClientError, ER_FIELD_TYPE, i, field_type_strs[NUM]); + tnt_raise(ClientError, ER_FIELD_TYPE, i + INDEX_OFFSET, + field_type_strs[NUM]); } return val; } diff --git a/src/box/tuple.h b/src/box/tuple.h index dd8d50d07919d45c47a17f39472b13ac2df3291a..4585a44d1ecfb030d99f3ab8f5433ce885b8e6b9 100644 --- a/src/box/tuple.h +++ b/src/box/tuple.h @@ -33,6 +33,12 @@ enum { FORMAT_ID_MAX = UINT16_MAX - 1, FORMAT_ID_NIL = UINT16_MAX }; enum { FORMAT_REF_MAX = INT32_MAX, TUPLE_REF_MAX = UINT16_MAX }; +/* + * We don't pass INDEX_OFFSET around dynamically all the time, + * at least hard code it so that in most cases it's a nice error + * message + */ +enum { INDEX_OFFSET = 1 }; /** Common quota for tuples and indexes */ extern struct quota memtx_quota; @@ -323,11 +329,13 @@ tuple_field_u32(struct tuple *tuple, uint32_t i) if (field == NULL) tnt_raise(ClientError, ER_NO_SUCH_FIELD, i); if (mp_typeof(*field) != MP_UINT) - tnt_raise(ClientError, ER_FIELD_TYPE, i, field_type_strs[NUM]); + tnt_raise(ClientError, ER_FIELD_TYPE, i + INDEX_OFFSET, + field_type_strs[NUM]); uint64_t val = mp_decode_uint(&field); if (val > UINT32_MAX) - tnt_raise(ClientError, ER_FIELD_TYPE, i, field_type_strs[NUM]); + tnt_raise(ClientError, ER_FIELD_TYPE, i + INDEX_OFFSET, + field_type_strs[NUM]); return (uint32_t) val; } @@ -427,12 +435,12 @@ tuple_next_u32(struct tuple_iterator *it) if (field == NULL) tnt_raise(ClientError, ER_NO_SUCH_FIELD, it->fieldno); if (mp_typeof(*field) != MP_UINT) - tnt_raise(ClientError, ER_FIELD_TYPE, fieldno, + tnt_raise(ClientError, ER_FIELD_TYPE, fieldno + INDEX_OFFSET, field_type_strs[NUM]); uint32_t val = mp_decode_uint(&field); if (val > UINT32_MAX) - tnt_raise(ClientError, ER_FIELD_TYPE, fieldno, + tnt_raise(ClientError, ER_FIELD_TYPE, fieldno + INDEX_OFFSET, field_type_strs[NUM]); return (uint32_t) val; } diff --git a/test/big/hash.result b/test/big/hash.result index b5a1ecc0e52c90114b27160f00f796c752a5443d..fb8ec35fe5b467771bf0be209179c7c89ca2c53e 100644 --- a/test/big/hash.result +++ b/test/big/hash.result @@ -40,7 +40,7 @@ tmp:bsize() > bsize -- Insert invalid fields hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 32-bit hash replace fields tests @@ -61,7 +61,7 @@ hash:replace{2, 'value1 v1.43', 'value2 1.92'} -- Replace invalid fields hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 32-bit hash select fields test @@ -178,7 +178,7 @@ hash:insert{103, 'value1 v1.0', 'value2 v1.0'} ... hash:insert{'invalid key', 'value1 v1.0', 'value2 v1.0'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 64-bit hash replace fields tests @@ -211,7 +211,7 @@ hash:replace{2, 'value1 v1.43', 'value2 1.92'} ... hash:replace{'invalid key', 'value1 v1.0', 'value2 v1.0'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... ------------------------------------------------------------------------------- -- 64-bit hash select fields test @@ -701,3 +701,19 @@ for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1 hash:drop() --- ... +-- +-- gh-616 "1-based indexing and 0-based error message +-- +_ = box.schema.create_space('test') +--- +... +_ = box.space.test:create_index('i',{parts={1,'STR'}}) +--- +... +box.space.test:insert{1} +--- +- error: 'Tuple field 1 type does not match one required by operation: expected STR' +... +box.space.test:drop() +--- +... diff --git a/test/big/hash.test.lua b/test/big/hash.test.lua index bf505b3c3fd5cd75f1485e16bf0b89e91b9e58a7..7fb2cb7c01cdbf092133c2f2922299419f30517f 100644 --- a/test/big/hash.test.lua +++ b/test/big/hash.test.lua @@ -299,3 +299,11 @@ hash:insert{0} hash:insert{16} for _, tuple in hi:pairs(nil, {iterator = box.index.ALL}) do hash:delete{tuple[1]} end hash:drop() + +-- +-- gh-616 "1-based indexing and 0-based error message +-- +_ = box.schema.create_space('test') +_ = box.space.test:create_index('i',{parts={1,'STR'}}) +box.space.test:insert{1} +box.space.test:drop() diff --git a/test/big/tree_pk.result b/test/big/tree_pk.result index a8a3f3cf35623cbfd5286a127fb3db10c48ee96f..9a4b0da3cc0e524ae9d3f6bf7462d710a36cd020 100644 --- a/test/big/tree_pk.result +++ b/test/big/tree_pk.result @@ -64,15 +64,15 @@ s0:delete{3} -- https://bugs.launchpad.net/tarantool/+bug/1072624 s0:insert{'xxxxxxx'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... s0:insert{''} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... s0:insert{'12'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... s1 = box.schema.space.create('tweedledee') --- diff --git a/test/big/tree_variants.result b/test/big/tree_variants.result index e72ecc90c2df10bfd01d1b5d8d94192a89f61838..5d48efe4e04dfa89a2221c1c477c08ac2bcd0177 100644 --- a/test/big/tree_variants.result +++ b/test/big/tree_variants.result @@ -179,19 +179,19 @@ sort(space:select{}) -- https://bugs.launchpad.net/tarantool/+bug/1072624 space:insert{'', 1, 2, '', '', '', '', '', 0} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... space:insert{'xxxxxxxx', 1, 2, '', '', '', '', '', 0} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... space:insert{1, '', 2, '', '', '', '', '', 0} --- -- error: 'Tuple field 1 type does not match one required by operation: expected NUM' +- error: 'Tuple field 2 type does not match one required by operation: expected NUM' ... space:insert{1, 'xxxxxxxxxxx', 2, '', '', '', '', '', 0} --- -- error: 'Tuple field 1 type does not match one required by operation: expected NUM' +- error: 'Tuple field 2 type does not match one required by operation: expected NUM' ... space:drop() --- diff --git a/test/box/alter.result b/test/box/alter.result index fa0ceaa292dd02d6c91c2a3c922b60ad0440e7df..0231006ccfada34478cb5a1d8ebc9a44dab8788c 100644 --- a/test/box/alter.result +++ b/test/box/alter.result @@ -20,7 +20,7 @@ _space:insert{_space.id, ADMIN, 'test', 5 } -- _space:insert{'hello', 'world', 'test'} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... -- -- Can't create a space which has wrong field count - field_count must be NUM diff --git a/test/box/alter_limits.result b/test/box/alter_limits.result index e38eaac1c153bb2d04112b58206e97ef89c7aa3f..406adb57dcbaf9af2f4c030a4ead7680a903af23 100644 --- a/test/box/alter_limits.result +++ b/test/box/alter_limits.result @@ -508,7 +508,7 @@ index = s:create_index('t1', { type = 'hash' }) -- field type contradicts field type of another index index = s:create_index('t2', { type = 'hash', parts = { 1, 'str' }}) --- -- error: Ambiguous field type in index 't2', key part 0. Requested type is STR but +- error: Ambiguous field type in index 't2', key part 1. Requested type is STR but the field has previously been defined as NUM ... -- ok @@ -785,7 +785,7 @@ _ = box.space['_index']:update({s.id, s.index.year.id}, {{"=", 8, 'num'}}) -- ambiguous field type index = s:create_index('str', { type = 'tree', unique = false, parts = { 2, 'str'}}) --- -- error: Ambiguous field type in index 'str', key part 0. Requested type is STR but +- error: Ambiguous field type in index 'str', key part 1. Requested type is STR but the field has previously been defined as NUM ... -- create index on a non-existing field @@ -803,7 +803,7 @@ s:insert{'Der Baader Meinhof Komplex', '2009 '} -- create an index on a field with a wrong type index = s:create_index('year', { type = 'tree', unique = false, parts = { 2, 'num'}}) --- -- error: 'Tuple field 1 type does not match one required by operation: expected NUM' +- error: 'Tuple field 2 type does not match one required by operation: expected NUM' ... -- a field is missing s:replace{'Der Baader Meinhof Komplex'} diff --git a/test/box/rtree_misc.result b/test/box/rtree_misc.result index 1cf45eed8eb93daaade27bb632fb6e00476a9fab..f356dac885bf27a91fdeb57adac9595d4749d7d8 100644 --- a/test/box/rtree_misc.result +++ b/test/box/rtree_misc.result @@ -44,11 +44,11 @@ i = s:create_index('secondary', { type = 'hash', parts = {2, 'num'}}) -- adding a tuple with array instead of num will fail i = s:insert{{1, 2, 3}, 4} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... i = s:insert{1, {2, 3, 4}} --- -- error: 'Tuple field 1 type does not match one required by operation: expected NUM' +- error: 'Tuple field 2 type does not match one required by operation: expected NUM' ... -- rtree index must be one-part i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {1, 'array', 2, 'array'}}) @@ -81,15 +81,15 @@ i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'arr -- inserting wrong values (should fail) s:insert{1, 2, 3} --- -- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY' +- error: 'Tuple field 3 type does not match one required by operation: expected ARRAY' ... s:insert{1, 2, "3"} --- -- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY' +- error: 'Tuple field 3 type does not match one required by operation: expected ARRAY' ... s:insert{1, 2, nil, 3} --- -- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY' +- error: 'Tuple field 3 type does not match one required by operation: expected ARRAY' ... s:insert{1, 2, {}} --- @@ -98,23 +98,23 @@ s:insert{1, 2, {}} ... s:insert{1, 2, {"3", "4", "5", "6"}} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... s:insert{1, 2, {nil, 4, 5, 6}} --- -- error: 'Tuple field 0 type does not match one required by operation: expected NUM' +- error: 'Tuple field 1 type does not match one required by operation: expected NUM' ... s:insert{1, 2, {3, {4}, 5, 6}} --- -- error: 'Tuple field 1 type does not match one required by operation: expected NUM' +- error: 'Tuple field 2 type does not match one required by operation: expected NUM' ... s:insert{1, 2, {3, 4, {}, 6}} --- -- error: 'Tuple field 2 type does not match one required by operation: expected NUM' +- error: 'Tuple field 3 type does not match one required by operation: expected NUM' ... s:insert{1, 2, {3, 4, 5, "6"}} --- -- error: 'Tuple field 3 type does not match one required by operation: expected NUM' +- error: 'Tuple field 4 type does not match one required by operation: expected NUM' ... s:insert{1, 2, {3}} ---