diff --git a/src/box/tuple_update.cc b/src/box/tuple_update.cc index 226966ba426672ea95af9c07e92c56020e9ebb12..a40ba6a6b06b61f229ad74fa6c6cfa98b4d4d5d7 100644 --- a/src/box/tuple_update.cc +++ b/src/box/tuple_update.cc @@ -182,33 +182,49 @@ update_field_init(struct update_field *field, field->tail_len = tail_len; } -static inline uint32_t -mp_read_int(const char **expr, const char *where) +static inline int64_t +mp_read_int(struct tuple_update *update, struct update_op *op, + const char **expr) { - uint32_t field_no; + int64_t field_no; if (mp_typeof(**expr) == MP_UINT) field_no = mp_decode_uint(expr); else if (mp_typeof(**expr) == MP_INT) - field_no = (int32_t) mp_decode_int(expr); + field_no = mp_decode_int(expr); else - tnt_raise(ClientError, ER_INVALID_MSGPACK, where); + tnt_raise(ClientError, ER_ARG_TYPE, (char ) op->opcode, + update->index_base + op->field_no, "UINT"); return field_no; } +static inline const char * +mp_read_str(struct tuple_update *update, struct update_op *op, + const char **expr, uint32_t *len) +{ + if (mp_typeof(**expr) != MP_STR) { + tnt_raise(ClientError, ER_ARG_TYPE, (char) op->opcode, + update->index_base + op->field_no, "STR"); + } + return mp_decode_str(expr, len); /* value */ +} + static inline void -op_check_field_no(uint32_t field_no, uint32_t field_max) +op_check_field_no(struct tuple_update *update, uint32_t field_no, + uint32_t field_max) { if (field_no > field_max) - tnt_raise(ClientError, ER_NO_SUCH_FIELD, field_no); + tnt_raise(ClientError, ER_NO_SUCH_FIELD, update->index_base + + field_no); } static inline void -op_adjust_field_no(struct update_op *op, uint32_t field_max) +op_adjust_field_no(struct tuple_update *update, struct update_op *op, + uint32_t field_max) { if (op->field_no == UINT32_MAX) op->field_no = field_max; else - op_check_field_no(op->field_no, field_max); + op_check_field_no(update, op->field_no, field_max); } static inline void @@ -225,7 +241,7 @@ static void do_op_insert(struct tuple_update *update, struct update_op *op, const char **expr) { - op_adjust_field_no(op, rope_size(update->rope)); + op_adjust_field_no(update, op, rope_size(update->rope)); op_set_read(op, expr); struct update_field *field = (struct update_field *) update->alloc(update->alloc_ctx, sizeof(*field)); @@ -253,17 +269,16 @@ static void do_op_delete(struct tuple_update *update, struct update_op *op, const char **expr) { - op_adjust_field_no(op, rope_size(update->rope) - 1); - if (mp_typeof(**expr) != MP_UINT) - tnt_raise(ClientError, ER_ARG_TYPE, op->field_no, "UINT"); - uint32_t delete_count = mp_decode_uint(expr); + op_adjust_field_no(update, op, rope_size(update->rope) - 1); + uint32_t delete_count = mp_read_int(update, op, expr); if ((uint64_t) op->field_no + delete_count > rope_size(update->rope)) delete_count = rope_size(update->rope) - op->field_no; - if (delete_count == 0) - tnt_raise(ClientError, ER_UPDATE_FIELD, + if (delete_count == 0) { + tnt_raise(ClientError, ER_UPDATE_FIELD, update->index_base + op->field_no, "cannot delete 0 fields"); + } for (uint32_t u = 0; u < delete_count; u++) rope_erase(update->rope, op->field_no); @@ -273,7 +288,7 @@ static void do_op_arith(struct tuple_update *update, struct update_op *op, const char **expr) { - op_check_field_no(op->field_no, rope_size(update->rope) - 1); + op_check_field_no(update, op->field_no, rope_size(update->rope) - 1); struct update_field *field = (struct update_field *) rope_extract(update->rope, op->field_no); @@ -281,16 +296,14 @@ do_op_arith(struct tuple_update *update, struct update_op *op, /* TODO: signed int & float support */ struct op_arith_arg *arg = &op->arg.arith; - arg->val = mp_read_int(expr, "expected an argument of arithmetic operation (integer)"); + arg->val = mp_read_int(update, op, expr); if (field->op) { - tnt_raise(ClientError, ER_UPDATE_FIELD, + tnt_raise(ClientError, ER_UPDATE_FIELD, update->index_base + op->field_no, "double update of the same field"); } field->op = op; const char *old = field->old; - if (mp_typeof(*old) != MP_UINT) - tnt_raise(ClientError, ER_ARG_TYPE, op->field_no, "UINT"); - uint64_t val = mp_decode_uint(&old); + uint64_t val = mp_read_int(update, op, &old); switch (op->opcode) { case '+': arg->val += val; break; case '&': arg->val &= val; break; @@ -306,41 +319,39 @@ static void do_op_splice(struct tuple_update *update, struct update_op *op, const char **expr) { - op_check_field_no(op->field_no, rope_size(update->rope) - 1); + op_check_field_no(update, op->field_no, rope_size(update->rope) - 1); struct update_field *field = (struct update_field *) rope_extract(update->rope, op->field_no); if (field->op) { tnt_raise(ClientError, ER_UPDATE_FIELD, - op->field_no, "double update of the same field"); + update->index_base + op->field_no, + "double update of the same field"); } struct op_splice_arg *arg = &op->arg.splice; - arg->offset = mp_read_int(expr, "expected splice offset (integer)"); - - arg->cut_length = mp_read_int(expr, "expected splice cut length (integer)"); /* cut length */ + arg->offset = mp_read_int(update, op, expr); + arg->cut_length = mp_read_int(update, op, expr); /* cut length */ - if (mp_typeof(**expr) != MP_STR) - tnt_raise(ClientError, ER_ARG_TYPE, op->field_no, "STR"); - arg->paste = mp_decode_str(expr, &arg->paste_length); /* value */ + arg->paste = mp_read_str(update, op, expr, &arg->paste_length); /* value */ const char *in = field->old; - if (mp_typeof(*in) != MP_STR) - tnt_raise(ClientError, ER_ARG_TYPE, op->field_no, "STR"); uint32_t str_len; - in = mp_decode_str(&in, &str_len); + in = mp_read_str(update, op, &in, &str_len); if (arg->offset < 0) { - if (-arg->offset > str_len + 1) - tnt_raise(ClientError, ER_SPLICE, - "offset is out of bound"); + if (-arg->offset > str_len + 1) { + tnt_raise(ClientError, ER_SPLICE, update->index_base + + op->field_no, "offset is out of bound"); + } arg->offset = arg->offset + str_len + 1; } else if (arg->offset >= update->index_base){ arg->offset -= update->index_base; if (arg->offset > str_len) arg->offset = str_len; } else { - tnt_raise(ClientError, ER_SPLICE, "offset is out of bound"); + tnt_raise(ClientError, ER_SPLICE, update->index_base + + op->field_no, "offset is out of bound"); } assert(arg->offset >= 0 && arg->offset <= str_len); @@ -603,7 +614,7 @@ update_read_ops(struct tuple_update *update, const char *expr, } if (args != op->meta->args) tnt_raise(ClientError, ER_UNKNOWN_UPDATE_OP); - op->field_no = mp_read_int(&expr, "expected a field no (integer)"); + op->field_no = mp_read_int(update, op, &expr); if (op->field_no != UINT32_MAX) { /* Check that field_no is not zero for Lua (base = 1) */ if (op->field_no < update->index_base) { diff --git a/src/errcode.h b/src/errcode.h index 0141b2224ce8daa31ddaca5f0d5623a76c17dcfb..209660af906fba0651b95776ce1ed5b93427e4b2 100644 --- a/src/errcode.h +++ b/src/errcode.h @@ -74,8 +74,8 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 22 */_(ER_TUPLE_NOT_ARRAY, 2, "Tuple/Key must be MsgPack array") \ /* 23 */_(ER_FIELD_TYPE, 2, "Tuple field %u type does not match one required by operation: expected %s") \ /* 24 */_(ER_FIELD_TYPE_MISMATCH, 2, "Ambiguous field type in index %u, key part %u. Requested type is %s but the field has previously been defined as %s") \ - /* 25 */_(ER_SPLICE, 2, "Field SPLICE error: %s") \ - /* 26 */_(ER_ARG_TYPE, 2, "Argument type in operation on field %u does not match field type: expected a %s") \ + /* 25 */_(ER_SPLICE, 2, "SPLICE error on field %u: %s") \ + /* 26 */_(ER_ARG_TYPE, 2, "Argument type in operation '%c' on field %u does not match field type: expected a %s") \ /* 27 */_(ER_TUPLE_IS_TOO_LONG, 2, "Tuple is too long %u") \ /* 28 */_(ER_UNKNOWN_UPDATE_OP, 2, "Unknown UPDATE operation") \ /* 29 */_(ER_UPDATE_FIELD, 2, "Field %u UPDATE error: %s") \ diff --git a/test/box/update.result b/test/box/update.result index fce073b92d1f239507d1df9ee61e853675833cb7..c112d50a185e58bcbc1d21af26dda3f0837319df 100644 --- a/test/box/update.result +++ b/test/box/update.result @@ -87,11 +87,11 @@ s:insert{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} ... s:update({0}, {{'#', 42, 1}}) --- -- error: Field 41 was not found in the tuple +- error: Field 42 was not found in the tuple ... s:update({0}, {{'#', 4, 'abirvalg'}}) --- -- error: 'Argument type in operation on field 3 does not match field type: expected +- error: 'Argument type in operation ''#'' on field 4 does not match field type: expected a UINT' ... s:update({0}, {{'#', 2, 1}, {'#', 4, 2}, {'#', 6, 1}}) @@ -112,7 +112,7 @@ s:update({0}, {{'#', 3, 4294967295}}) ... s:update({0}, {{'#', 2, 0}}) --- -- error: 'Field 1 UPDATE error: cannot delete 0 fields' +- error: 'Field 2 UPDATE error: cannot delete 0 fields' ... s:truncate() --- @@ -175,7 +175,7 @@ s:update({1}, {{'=', 2, 'new field string value'}, {'=', 3, 42}, {'=', 4, 0xdead -- test multiple update opearations on the same field s:update({1}, {{'+', 3, 16}, {'&', 4, 0xffff0000}, {'|', 4, 0x0000a0a0}, {'^', 4, 0xffff00aa}}) --- -- error: 'Field 3 UPDATE error: double update of the same field' +- error: 'Field 4 UPDATE error: double update of the same field' ... -- test update splice operation s:replace{1953719668, 'something to splice'} @@ -197,7 +197,7 @@ s:update(1953719668, {{':', 2, 100, 2, 'every'}}) ... s:update(1953719668, {{':', 2, -100, 2, 'every'}}) --- -- error: 'Field SPLICE error: offset is out of bound' +- error: 'SPLICE error on field 2: offset is out of bound' ... s:truncate() --- @@ -230,7 +230,7 @@ s:replace({10, 'abcde'}) ... s:update(10, {{':', 2, 0, 0, '!'}}) --- -- error: 'Field SPLICE error: offset is out of bound' +- error: 'SPLICE error on field 2: offset is out of bound' ... s:update(10, {{':', 2, 1, 0, '('}}) --- @@ -278,7 +278,7 @@ s:insert{1684234849} ... s:update({1684234849}, {{'#', 2, 1}}) --- -- error: Field 1 was not found in the tuple +- error: Field 2 was not found in the tuple ... s:update({1684234849}, {{'=', -1, 'push1'}}) ---