diff --git a/src/box/alter.cc b/src/box/alter.cc index 324b7dc2c533972b2d563320ce981e9695ff1281..9215c07fd55745ee120946aee90bb402c7beb8e2 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -372,8 +372,9 @@ field_def_decode(struct field_def *field, const char **data, uint32_t key_len; const char *key = mp_decode_str(data, &key_len); if (opts_parse_key(field, field_def_reg, key, key_len, data, - ER_WRONG_SPACE_FORMAT, - fieldno + TUPLE_INDEX_BASE, region) != 0) + ER_WRONG_SPACE_FORMAT, + fieldno + TUPLE_INDEX_BASE, region, + true) != 0) diag_raise(); } if (field->name == NULL) { diff --git a/src/box/opt_def.c b/src/box/opt_def.c index ebb219c83ea5bd00e922bd2a4124195b0a308bd7..cd93c23b819e2bb1534bef01a5b818802700f888 100644 --- a/src/box/opt_def.c +++ b/src/box/opt_def.c @@ -144,7 +144,8 @@ opt_set(void *opts, const struct opt_def *def, const char **val, int opts_parse_key(void *opts, const struct opt_def *reg, const char *key, uint32_t key_len, const char **data, uint32_t errcode, - uint32_t field_no, struct region *region) + uint32_t field_no, struct region *region, + bool skip_unknown_options) { char errmsg[DIAG_ERRMSG_MAX]; bool found = false; @@ -163,10 +164,14 @@ opts_parse_key(void *opts, const struct opt_def *reg, const char *key, break; } if (!found) { - snprintf(errmsg, sizeof(errmsg), "unexpected option '%.*s'", - key_len, key); - diag_set(ClientError, errcode, field_no, errmsg); - return -1; + if (skip_unknown_options) { + mp_next(data); + } else { + snprintf(errmsg, sizeof(errmsg), + "unexpected option '%.*s'", key_len, key); + diag_set(ClientError, errcode, field_no, errmsg); + return -1; + } } return 0; } @@ -195,7 +200,7 @@ opts_decode(void *opts, const struct opt_def *reg, const char **map, uint32_t key_len; const char *key = mp_decode_str(map, &key_len); if (opts_parse_key(opts, reg, key, key_len, map, errcode, - field_no, region) != 0) + field_no, region, false) != 0) return -1; } return 0; diff --git a/src/box/opt_def.h b/src/box/opt_def.h index d1109b65c4f6dc3cce4ed7acf6a824e68c26d8d5..e1149b9820a8875918dee69b352f27333c571e1c 100644 --- a/src/box/opt_def.h +++ b/src/box/opt_def.h @@ -33,6 +33,7 @@ #include "trivia/util.h" #include <stddef.h> +#include <stdbool.h> #if defined(__cplusplus) extern "C" { @@ -88,12 +89,24 @@ opts_decode(void *opts, const struct opt_def *reg, const char **map, uint32_t errcode, uint32_t field_no, struct region *region); /** - * Populate one options from msgpack-encoded representation + * Decode one option and store it into @a opts struct as a field. + * @param opts[out] Options to decode to. + * @param reg Options definition. + * @param key Name of an option. + * @param key_len Length of @a key. + * @param data Option value. + * @param errcode Code of error to set if something is wrong. + * @param field_no Field number of an option in a parent element. + * @param region Region to allocate OPT_STRPTR option. + * @param skip_unknown_options If true, do not set error, if an + * option is unknown. Useful, when it is neccessary to + * allow to store custom fields in options. */ int opts_parse_key(void *opts, const struct opt_def *reg, const char *key, uint32_t key_len, const char **data, uint32_t errcode, - uint32_t field_no, struct region *region); + uint32_t field_no, struct region *region, + bool skip_unknown_options); #if defined(__cplusplus) } /* extern "C" */ diff --git a/test/box/ddl.result b/test/box/ddl.result index 7076e836add55f790b4ede5d7dfcb32f4595e56f..3f086f9f67174e53e2d80376048c9cea0f837e66 100644 --- a/test/box/ddl.result +++ b/test/box/ddl.result @@ -480,3 +480,28 @@ box.space._collation.index.name:delete{'test'} --- - [2, 'test', 0, 'ICU', 'ru_RU', {}] ... +-- +-- gh-2839: allow to store custom fields in field definition. +-- +format = {} +--- +... +format[1] = {name = 'field1', type = 'unsigned'} +--- +... +format[2] = {'field2', 'unsigned'} +--- +... +format[3] = {'field3', 'unsigned', custom_field = 'custom_value'} +--- +... +s = box.schema.create_space('test', {format = format}) +--- +... +s:format()[3].custom_field +--- +- custom_value +... +s:drop() +--- +... diff --git a/test/box/ddl.test.lua b/test/box/ddl.test.lua index f13c54c66682c8a173e84f1f0f7f1274baab3baa..5b1d9dec7ee3fefc0ebdc5e7e85971b347cdef98 100644 --- a/test/box/ddl.test.lua +++ b/test/box/ddl.test.lua @@ -186,3 +186,14 @@ box.space._collation:select{} test_run:cmd('restart server default') box.space._collation:select{} box.space._collation.index.name:delete{'test'} + +-- +-- gh-2839: allow to store custom fields in field definition. +-- +format = {} +format[1] = {name = 'field1', type = 'unsigned'} +format[2] = {'field2', 'unsigned'} +format[3] = {'field3', 'unsigned', custom_field = 'custom_value'} +s = box.schema.create_space('test', {format = format}) +s:format()[3].custom_field +s:drop()