[PATCH 3/8] Add 'exact_field_count' parameter to options decoder

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Wed Aug 8 01:03:46 MSK 2018


Needed for promotion. Promotion uses system space
_promotion, into which a user can write tuples directly
with not API usage (and we can not do anything with it),
so _promotion should do severe validation of each field
of each tuple since it affects the cluster state.

For this a new parameter of options decoder is introduced,
that checks for exact field count.

Needed for #3055
---
 src/box/alter.cc  | 10 +++++-----
 src/box/key_def.c |  2 +-
 src/box/opt_def.c | 13 ++++++++-----
 src/box/opt_def.h | 16 +++++++++++++++-
 4 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 3007a131d..d13ecb783 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -239,7 +239,7 @@ index_opts_decode(struct index_opts *opts, const char *map)
 {
 	index_opts_create(opts);
 	if (opts_decode(opts, index_opts_reg, &map, ER_WRONG_INDEX_OPTIONS,
-			BOX_INDEX_FIELD_OPTS, NULL) != 0)
+			BOX_INDEX_FIELD_OPTS, NULL, 0) != 0)
 		diag_raise();
 	if (opts->distance == rtree_index_distance_type_MAX) {
 		tnt_raise(ClientError, ER_WRONG_INDEX_OPTIONS,
@@ -403,8 +403,8 @@ space_opts_decode(struct space_opts *opts, const char *data)
 				flags++;
 		}
 	} else if (opts_decode(opts, space_opts_reg, &data,
-			       ER_WRONG_SPACE_OPTIONS,
-			       BOX_SPACE_FIELD_OPTS, NULL) != 0) {
+			       ER_WRONG_SPACE_OPTIONS, BOX_SPACE_FIELD_OPTS,
+			       NULL, 0) != 0) {
 		diag_raise();
 	}
 }
@@ -2382,8 +2382,8 @@ coll_id_def_new_from_tuple(const struct tuple *tuple, struct coll_id_def *def)
 
 	assert(base->type == COLL_TYPE_ICU);
 	if (opts_decode(&base->icu, coll_icu_opts_reg, &options,
-			ER_WRONG_COLLATION_OPTIONS,
-			BOX_COLLATION_FIELD_OPTIONS, NULL) != 0)
+			ER_WRONG_COLLATION_OPTIONS, BOX_COLLATION_FIELD_OPTIONS,
+			NULL, 0) != 0)
 		diag_raise();
 
 	if (base->icu.french_collation == coll_icu_on_off_MAX) {
diff --git a/src/box/key_def.c b/src/box/key_def.c
index ee09dc99d..bc0c1ba35 100644
--- a/src/box/key_def.c
+++ b/src/box/key_def.c
@@ -454,7 +454,7 @@ key_def_decode_parts(struct key_part_def *parts, uint32_t part_count,
 		*part = key_part_def_default;
 		if (opts_decode(part, part_def_reg, data,
 				ER_WRONG_INDEX_OPTIONS, i + TUPLE_INDEX_BASE,
-				NULL) != 0)
+				NULL, 0) != 0)
 			return -1;
 		if (part->type == field_type_MAX) {
 			diag_set(ClientError, ER_WRONG_INDEX_OPTIONS,
diff --git a/src/box/opt_def.c b/src/box/opt_def.c
index cd93c23b8..6710f8187 100644
--- a/src/box/opt_def.c
+++ b/src/box/opt_def.c
@@ -176,13 +176,10 @@ opts_parse_key(void *opts, const struct opt_def *reg, const char *key,
 	return 0;
 }
 
-/**
- * Populate key options from their msgpack-encoded representation
- * (msgpack map).
- */
 int
 opts_decode(void *opts, const struct opt_def *reg, const char **map,
-	    uint32_t errcode, uint32_t field_no, struct region *region)
+	    uint32_t errcode, uint32_t field_no, struct region *region,
+	    uint32_t exact_field_count)
 {
 	assert(mp_typeof(**map) == MP_MAP);
 
@@ -191,6 +188,12 @@ opts_decode(void *opts, const struct opt_def *reg, const char **map,
 	 * DDL is not performance-critical, so this is not a problem.
 	 */
 	uint32_t map_size = mp_decode_map(map);
+	if (map_size != exact_field_count && exact_field_count != 0) {
+		diag_set(ClientError, errcode, field_no,
+			 tt_sprintf("expected %u keys but got %u",
+				    exact_field_count, map_size));
+		return -1;
+	}
 	for (uint32_t i = 0; i < map_size; i++) {
 		if (mp_typeof(**map) != MP_STR) {
 			diag_set(ClientError, errcode, field_no,
diff --git a/src/box/opt_def.h b/src/box/opt_def.h
index 633832af9..4cfebf62a 100644
--- a/src/box/opt_def.h
+++ b/src/box/opt_def.h
@@ -83,10 +83,24 @@ struct region;
 /**
  * Populate key options from their msgpack-encoded representation
  * (msgpack map).
+ * @param[out] opts Where decode options to.
+ * @param reg Field definitions array.
+ * @param map MessagePack to decode.
+ * @param errcode Error code to set on any error. The error code
+ *        has to accept field number and description as
+ *        parameters.
+ * @param field_no Field number to set for @a errcode.
+ * @param region Region for dynamic allocations such as strings.
+ * @param exact_field_count If non-zero, then @a map should
+ *        contain exactly this count of fields.
+ *
+ * @retval 0 Success.
+ * @retval -1 Error.
  */
 int
 opts_decode(void *opts, const struct opt_def *reg, const char **map,
-	    uint32_t errcode, uint32_t field_no, struct region *region);
+	    uint32_t errcode, uint32_t field_no, struct region *region,
+	    uint32_t exact_field_count);
 
 /**
  * Decode one option and store it into @a opts struct as a field.
-- 
2.15.2 (Apple Git-101.1)




More information about the Tarantool-patches mailing list