[PATCH v1 5/5] box: refactor tuple_init_field_map to use bitmap

Kirill Shcherbatov kshcherbatov at tarantool.org
Sun Dec 23 15:40:40 MSK 2018


Refactored tuple_init_field_map to fill temporal bitmap and
compare it with template req_fields_bitmap containing information
about required fields. Each field is mapped to bitmap using
unique field identifier.
This approach to check the required fields will work even after
the introduction of JSON paths, when the field tree becomes
multilevel.

Needed for #1012
---
 src/box/errcode.h                 |   2 +-
 src/box/tuple_format.c            | 183 +++++++++++++++++++++++-------
 src/box/tuple_format.h            |  23 ++++
 test/box/alter_limits.result      |   8 +-
 test/box/ddl.result               |  24 ++--
 test/box/misc.result              |   2 +-
 test/box/sql.result               |  12 +-
 test/box/tree_pk_multipart.result |   8 +-
 test/engine/ddl.result            |  28 ++---
 test/engine/null.result           |  52 ++++-----
 test/vinyl/constraint.result      |  12 +-
 test/vinyl/errinj.result          |  12 +-
 test/vinyl/savepoint.result       |   8 +-
 13 files changed, 250 insertions(+), 124 deletions(-)

diff --git a/src/box/errcode.h b/src/box/errcode.h
index 7d1f8ddc7..812e643d8 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -91,7 +91,7 @@ struct errcode_record {
 	/* 36 */_(ER_NO_SUCH_SPACE,		"Space '%s' does not exist") \
 	/* 37 */_(ER_NO_SUCH_FIELD,		"Field %d was not found in the tuple") \
 	/* 38 */_(ER_EXACT_FIELD_COUNT,		"Tuple field count %u does not match space field count %u") \
-	/* 39 */_(ER_MIN_FIELD_COUNT,		"Tuple field count %u is less than required by space format or defined indexes (expected at least %u)") \
+	/* 39 */_(ER_FIELD_STRUCTURE_MISMATCH,	"Tuple field %s does not math document structure defined by space format or index: %s") \
 	/* 40 */_(ER_WAL_IO,			"Failed to write to disk") \
 	/* 41 */_(ER_MORE_THAN_ONE_TUPLE,	"Get() doesn't support partial keys and non-unique indexes") \
 	/* 42 */_(ER_ACCESS_DENIED,		"%s access to %s '%s' is denied for user '%s'") \
diff --git a/src/box/tuple_format.c b/src/box/tuple_format.c
index e29f84dc5..6e269fd77 100644
--- a/src/box/tuple_format.c
+++ b/src/box/tuple_format.c
@@ -28,6 +28,8 @@
  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+#include "bit/bit.h"
+#include "fiber.h"
 #include "json/json.h"
 #include "tuple_format.h"
 #include "coll_id_cache.h"
@@ -206,6 +208,30 @@ tuple_format_create(struct tuple_format *format, struct key_def * const *keys,
 		return -1;
 	}
 	format->field_map_size = field_map_size;
+
+	/* Allocate required fields bitmap. */
+	uint32_t req_fields_bitmap_sz = (format->total_field_count +
+					 CHAR_BIT * sizeof(unsigned long) - 1) /
+					 CHAR_BIT * sizeof(unsigned long);
+	format->req_fields_bitmap = calloc(1, req_fields_bitmap_sz);
+	if (format->req_fields_bitmap == NULL) {
+		diag_set(OutOfMemory, req_fields_bitmap_sz, "calloc",
+			 "format->req_fields_bitmap");
+		return -1;
+	}
+	struct tuple_field *field;
+	struct json_token *root = (struct json_token *)&format->fields.root;
+	json_tree_foreach_entry_preorder(field, root, struct tuple_field,
+					 token) {
+		/*
+		 * Mark all leaf non-nullable fields as required
+		 * setting corresponding bit 1 in format
+		 * req_fields_bitmap.
+		 */
+		if (tuple_field_is_leaf(field) &&
+		    !tuple_field_is_nullable(field))
+			bit_set(format->req_fields_bitmap, field->id);
+	}
 	return 0;
 }
 
@@ -304,6 +330,7 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
 		struct tuple_field *field = tuple_field_new();
 		if (field == NULL)
 			goto error;
+		field->id = fieldno;
 		field->token.num = fieldno;
 		field->token.type = JSON_TOKEN_NUM;
 		if (json_tree_add(&format->fields, &format->fields.root,
@@ -323,6 +350,8 @@ tuple_format_alloc(struct key_def * const *keys, uint16_t key_count,
 		format->dict = dict;
 		tuple_dictionary_ref(dict);
 	}
+	format->total_field_count = field_count;
+	format->req_fields_bitmap = NULL;
 	format->refs = 0;
 	format->id = FORMAT_ID_NIL;
 	format->index_field_count = index_field_count;
@@ -339,6 +368,7 @@ error:
 static inline void
 tuple_format_destroy(struct tuple_format *format)
 {
+	free(format->req_fields_bitmap);
 	tuple_format_destroy_fields(format);
 	tuple_dictionary_unref(format->dict);
 }
@@ -422,6 +452,74 @@ tuple_format1_can_store_format2_tuples(struct tuple_format *format1,
 	return true;
 }
 
+/**
+ * Return meta information of a tuple field given a format
+ * and a unique field identifier.
+ */
+static struct tuple_field *
+tuple_format_field_by_id(const struct tuple_format *format, uint32_t id)
+{
+	struct tuple_field *field;
+	struct json_token *root = (struct json_token *)&format->fields.root;
+	json_tree_foreach_entry_preorder(field, root, struct tuple_field,
+					 token) {
+		if (field->id == id)
+			return field;
+	}
+	return NULL;
+}
+
+/**
+ * Analyze fields_bitmap to ensure that all required fields
+ * present in tuple. Routine relies on req_fields_bitmap is
+ * initialized on tuple_format_create and all required field's
+ * id bits are set 1.
+ */
+static int
+tuple_format_fields_bitmap_test(const struct tuple_format *format,
+				const char *fields_bitmap)
+{
+	struct tuple_field *missed_field = NULL;
+	const char *req_fields_bitmap = format->req_fields_bitmap;
+	for (uint32_t i = 0; i < format->total_field_count; i++) {
+		bool is_required = bit_test(req_fields_bitmap, i);
+		if (is_required && is_required != bit_test(fields_bitmap, i)) {
+			missed_field = tuple_format_field_by_id(format, i);
+			assert(missed_field != NULL);
+			break;
+		}
+	}
+	if (missed_field == NULL)
+		return 0;
+
+	struct json_token *token = &missed_field->token;
+	const char *err;
+	if (missed_field->token.type == JSON_TOKEN_STR) {
+		err = tt_sprintf("map does not contain a key \"%.*s\"",
+				 token->len, token->str);
+	} else if (missed_field->token.type == JSON_TOKEN_NUM) {
+		struct json_token *parent = token->parent;
+		/*
+		 * Determine minimal field size looking for
+		 * the greatest fieldno between non-nullable
+		 * missed_field neighbors.
+		 */
+		uint32_t expected_size;
+		for (int i = 0; i <= parent->max_child_idx; i++) {
+			struct tuple_field *field =
+				tuple_format_field((struct tuple_format *)format,
+						   i);
+			if (!tuple_field_is_nullable(field))
+				expected_size = i + 1;
+		}
+		err = tt_sprintf("invalid array size %d (expected at least %d)",
+				 token->num, expected_size);
+	}
+	diag_set(ClientError, ER_FIELD_STRUCTURE_MISMATCH,
+		 tuple_field_path(missed_field), err);
+	return -1;
+}
+
 /** @sa declaration for details. */
 int
 tuple_init_field_map(const struct tuple_format *format, uint32_t *field_map,
@@ -441,54 +539,59 @@ tuple_init_field_map(const struct tuple_format *format, uint32_t *field_map,
 			 (unsigned) format->exact_field_count);
 		return -1;
 	}
-	if (validate && field_count < format->min_field_count) {
-		diag_set(ClientError, ER_MIN_FIELD_COUNT,
-			 (unsigned) field_count,
-			 (unsigned) format->min_field_count);
-		return -1;
-	}
-
-	/* first field is simply accessible, so we do not store offset to it */
-	const struct tuple_field *field =
-		tuple_format_field((struct tuple_format *)format, 0);
-	if (validate &&
-	    !field_mp_type_is_compatible(field->type, mp_typeof(*pos),
-					 tuple_field_is_nullable(field))) {
-		diag_set(ClientError, ER_FIELD_TYPE, tuple_field_path(field),
-			 field_type_strs[field->type]);
-		return -1;
-	}
-	mp_next(&pos);
-	/* other fields...*/
-	uint32_t i = 1;
 	uint32_t defined_field_count = MIN(field_count, validate ?
 					   tuple_format_field_count(format) :
 					   format->index_field_count);
-	if (field_count < format->index_field_count) {
-		/*
-		 * Nullify field map to be able to detect by 0,
-		 * which key fields are absent in tuple_field().
-		 */
-		memset((char *)field_map - format->field_map_size, 0,
-		       format->field_map_size);
-	}
-	for (; i < defined_field_count; ++i) {
-		field = tuple_format_field((struct tuple_format *)format, i);
-		if (validate &&
-		    !field_mp_type_is_compatible(field->type, mp_typeof(*pos),
-						 tuple_field_is_nullable(field))) {
-			diag_set(ClientError, ER_FIELD_TYPE,
-				 tuple_field_path(field),
-				 field_type_strs[field->type]);
+	struct region *region = &fiber()->gc;
+	char *fields_bitmap = NULL;
+	if (validate) {
+		uint32_t fields_bitmap_sz = (format->total_field_count +
+					     CHAR_BIT *
+					     sizeof(unsigned long) - 1) /
+					     CHAR_BIT * sizeof(unsigned long);
+		fields_bitmap = region_alloc(region, fields_bitmap_sz);
+		if (fields_bitmap == NULL) {
+			diag_set(OutOfMemory, fields_bitmap_sz, "calloc",
+				"fields_bitmap");
 			return -1;
 		}
-		if (field->offset_slot != TUPLE_OFFSET_SLOT_NIL) {
-			field_map[field->offset_slot] =
-				(uint32_t) (pos - tuple);
+		memset(fields_bitmap, 0, fields_bitmap_sz);
+	}
+	memset((char *)field_map - format->field_map_size, 0,
+	       format->field_map_size);
+	struct json_tree *tree = (struct json_tree *)&format->fields;
+	struct json_token *parent = &tree->root;
+	struct json_token token;
+	token.parent = NULL;
+	token.type = JSON_TOKEN_NUM;
+	token.num = 0;
+	while ((uint32_t)token.num < defined_field_count) {
+		struct tuple_field *field =
+			json_tree_lookup_entry(tree, parent, &token,
+					       struct tuple_field, token);
+		if (field != NULL) {
+			bool is_nullable = tuple_field_is_nullable(field);
+			if (validate &&
+			    !field_mp_type_is_compatible(field->type,
+							 mp_typeof(*pos),
+							 is_nullable) != 0) {
+				diag_set(ClientError, ER_FIELD_TYPE,
+					 tuple_field_path(field),
+					 field_type_strs[field->type]);
+				return -1;
+			}
+			if (field->offset_slot != TUPLE_OFFSET_SLOT_NIL) {
+				field_map[field->offset_slot] =
+					(uint32_t)(pos - tuple);
+			}
+			if (validate)
+				bit_set(fields_bitmap, field->id);
 		}
+		token.num++;
 		mp_next(&pos);
 	}
-	return 0;
+	return validate ?
+	       tuple_format_fields_bitmap_test(format, fields_bitmap) : 0;
 }
 
 uint32_t
diff --git a/src/box/tuple_format.h b/src/box/tuple_format.h
index 949337807..947d0d8a5 100644
--- a/src/box/tuple_format.h
+++ b/src/box/tuple_format.h
@@ -31,6 +31,7 @@
  * SUCH DAMAGE.
  */
 
+#include "bit/bit.h"
 #include "key_def.h"
 #include "field_def.h"
 #include "errinj.h"
@@ -114,6 +115,8 @@ struct tuple_field {
 	struct coll *coll;
 	/** Collation identifier. */
 	uint32_t coll_id;
+	/** Field unique identifier in tuple_format. */
+	uint32_t id;
 	/** Link in tuple_format::fields. */
 	struct json_token token;
 };
@@ -173,6 +176,20 @@ struct tuple_format {
 	 * Shared names storage used by all formats of a space.
 	 */
 	struct tuple_dictionary *dict;
+	/**
+	 * This bitmap of "required fields" contains information
+	 * about fields that must present in tuple to be inserted.
+	 * Look for tuple_format_fields_bitmap_test comment for
+	 * more details.
+	 */
+	char *req_fields_bitmap;
+	/**
+	 * Total count of format fields in fields subtree.
+	 * Required to allocate temporal objects containing
+	 * attributes for all fields. Particularly to allocate
+	 * temporal req_fields_bitmap on region.
+	 */
+	uint32_t total_field_count;
 	/**
 	 * Fields comprising the format, organized in a tree.
 	 * First level nodes correspond to tuple fields.
@@ -194,6 +211,12 @@ tuple_format_field_count(const struct tuple_format *format)
 	return root->children != NULL ? root->max_child_idx + 1 : 0;
 }
 
+static inline bool
+tuple_field_is_leaf(struct tuple_field *field)
+{
+	return field->token.max_child_idx == -1;
+}
+
 /**
  * Return meta information of a top-level tuple field given
  * a format and a field index.
diff --git a/test/box/alter_limits.result b/test/box/alter_limits.result
index 7f7e5a24e..d32b7bed5 100644
--- a/test/box/alter_limits.result
+++ b/test/box/alter_limits.result
@@ -842,8 +842,8 @@ index = s:create_index('string', { type = 'tree', unique =  false, parts = { 2,
 -- create index on a non-existing field
 index = s:create_index('nosuchfield', { type = 'tree', unique = true, parts = { 3, 'string'}})
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 3)'
 ...
 s.index.year:drop()
 ---
@@ -865,8 +865,8 @@ s:replace{'Der Baader Meinhof Komplex'}
 ...
 index = s:create_index('year', { type = 'tree', unique = false, parts = { 2, 'unsigned'}})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s:drop()
 ---
diff --git a/test/box/ddl.result b/test/box/ddl.result
index 7b4aba156..eaf58fe78 100644
--- a/test/box/ddl.result
+++ b/test/box/ddl.result
@@ -326,33 +326,33 @@ box.internal.collation.drop('test')
 ...
 box.space._collation:auto_increment{'test'}
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 6)'
 ...
 box.space._collation:auto_increment{'test', 0, 'ICU'}
 ---
-- error: Tuple field count 4 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [5] does not math document structure defined by space format
+    or index: invalid array size 4 (expected at least 6)'
 ...
 box.space._collation:auto_increment{'test', 'ADMIN', 'ICU', 'ru_RU'}
 ---
-- error: Tuple field count 5 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [3] type does not match one required by operation: expected
+    unsigned'
 ...
 box.space._collation:auto_increment{42, 0, 'ICU', 'ru_RU'}
 ---
-- error: Tuple field count 5 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [2] type does not match one required by operation: expected
+    string'
 ...
 box.space._collation:auto_increment{'test', 0, 42, 'ru_RU'}
 ---
-- error: Tuple field count 5 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [4] type does not match one required by operation: expected
+    string'
 ...
 box.space._collation:auto_increment{'test', 0, 'ICU', 42}
 ---
-- error: Tuple field count 5 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [5] type does not match one required by operation: expected
+    string'
 ...
 box.space._collation:auto_increment{'test', 0, 'ICU', 'ru_RU', setmap{}} --ok
 ---
diff --git a/test/box/misc.result b/test/box/misc.result
index d266bb334..479a401ea 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -369,7 +369,7 @@ t;
   36: box.error.NO_SUCH_SPACE
   37: box.error.NO_SUCH_FIELD
   38: box.error.EXACT_FIELD_COUNT
-  39: box.error.MIN_FIELD_COUNT
+  39: box.error.FIELD_STRUCTURE_MISMATCH
   40: box.error.WAL_IO
   41: box.error.MORE_THAN_ONE_TUPLE
   42: box.error.ACCESS_DENIED
diff --git a/test/box/sql.result b/test/box/sql.result
index 1818b294d..cfbe3fe41 100644
--- a/test/box/sql.result
+++ b/test/box/sql.result
@@ -299,8 +299,8 @@ s:truncate()
 -- get away with it.
 space:insert{'Britney'}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 sorted(space.index.secondary:select('Anything'))
 ---
@@ -308,8 +308,8 @@ sorted(space.index.secondary:select('Anything'))
 ...
 space:insert{'Stephanie'}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 sorted(space.index.secondary:select('Anything'))
 ---
@@ -638,8 +638,8 @@ sorted(space.index.secondary:select('Britney'))
 -- try to insert the incoplete tuple
 space:replace{'Spears'}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 -- check that nothing has been updated
 space:select{'Spears'}
diff --git a/test/box/tree_pk_multipart.result b/test/box/tree_pk_multipart.result
index 28cab3f94..e05d3ed00 100644
--- a/test/box/tree_pk_multipart.result
+++ b/test/box/tree_pk_multipart.result
@@ -490,13 +490,13 @@ i1 = space:create_index('primary', { type = 'tree', parts = {1, 'unsigned', 3, '
 ...
 space:insert{1, 1}
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 3)'
 ...
 space:replace{1, 1}
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 3)'
 ...
 space:drop()
 ---
diff --git a/test/engine/ddl.result b/test/engine/ddl.result
index 09001c9a1..5f9bd7fa9 100644
--- a/test/engine/ddl.result
+++ b/test/engine/ddl.result
@@ -77,8 +77,8 @@ index = space:create_index('primary', {type = 'tree', parts = {1, 'unsigned', 2,
 ...
 space:insert({13})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 space:drop()
 ---
@@ -853,13 +853,13 @@ s:replace{1, '2', {3, 3}, 4.4, -5, true, {7}, 8, 9}
 ...
 s:replace{1, '2', {3, 3}, 4.4, -5, true, {value=7}}
 ---
-- error: Tuple field count 7 is less than required by space format or defined indexes
-    (expected at least 9)
+- error: 'Tuple field [8] does not math document structure defined by space format
+    or index: invalid array size 7 (expected at least 9)'
 ...
 s:replace{1, '2', {3, 3}, 4.4, -5, true, {value=7}, 8}
 ---
-- error: Tuple field count 8 is less than required by space format or defined indexes
-    (expected at least 9)
+- error: 'Tuple field [9] does not math document structure defined by space format
+    or index: invalid array size 8 (expected at least 9)'
 ...
 s:truncate()
 ---
@@ -1343,8 +1343,8 @@ s:format(format)
 -- Fail, not enough fields.
 s:replace{2, 2, 2, 2, 2}
 ---
-- error: Tuple field count 5 is less than required by space format or defined indexes
-    (expected at least 6)
+- error: 'Tuple field [6] does not math document structure defined by space format
+    or index: invalid array size 5 (expected at least 6)'
 ...
 s:replace{2, 2, 2, 2, 2, 2, 2}
 ---
@@ -1356,8 +1356,8 @@ format[7] = {name = 'field7', type = 'unsigned'}
 -- Fail, the tuple {1, ... 1} is invalid for a new format.
 s:format(format)
 ---
-- error: Tuple field count 6 is less than required by space format or defined indexes
-    (expected at least 7)
+- error: 'Tuple field [7] does not math document structure defined by space format
+    or index: invalid array size 6 (expected at least 7)'
 ...
 s:drop()
 ---
@@ -2032,8 +2032,8 @@ s:create_index('sk', {parts = {4, 'unsigned'}}) -- error: field type
 ...
 s:create_index('sk', {parts = {4, 'integer', 5, 'string'}}) -- error: field missing
 ---
-- error: Tuple field count 4 is less than required by space format or defined indexes
-    (expected at least 5)
+- error: 'Tuple field [5] does not math document structure defined by space format
+    or index: invalid array size 4 (expected at least 5)'
 ...
 i1 = s:create_index('i1', {parts = {2, 'string'}, unique = false})
 ---
@@ -2087,8 +2087,8 @@ i3:alter{parts = {4, 'unsigned'}} -- error: field type
 ...
 i3:alter{parts = {4, 'integer', 5, 'string'}} -- error: field missing
 ---
-- error: Tuple field count 4 is less than required by space format or defined indexes
-    (expected at least 5)
+- error: 'Tuple field [5] does not math document structure defined by space format
+    or index: invalid array size 4 (expected at least 5)'
 ...
 i3:alter{parts = {2, 'string', 4, 'integer'}} -- ok
 ---
diff --git a/test/engine/null.result b/test/engine/null.result
index 05f47332d..797a525dc 100644
--- a/test/engine/null.result
+++ b/test/engine/null.result
@@ -458,8 +458,8 @@ sk = s:create_index('sk', {parts = {2, 'unsigned'}})
 ...
 s:replace{1, 2} -- error
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 3)'
 ...
 t1 = s:replace{2, 3, 4}
 ---
@@ -530,18 +530,18 @@ sk = s:create_index('sk', {parts = {2, 'unsigned'}})
 ...
 s:replace{1, 2} -- error
 ---
-- error: Tuple field count 2 is less than required by space format or defined indexes
-    (expected at least 5)
+- error: 'Tuple field [3] does not math document structure defined by space format
+    or index: invalid array size 2 (expected at least 5)'
 ...
 s:replace{2, 3, 4} -- error
 ---
-- error: Tuple field count 3 is less than required by space format or defined indexes
-    (expected at least 5)
+- error: 'Tuple field [5] does not math document structure defined by space format
+    or index: invalid array size 4 (expected at least 5)'
 ...
 s:replace{3, 4, 5, 6} -- error
 ---
-- error: Tuple field count 4 is less than required by space format or defined indexes
-    (expected at least 5)
+- error: 'Tuple field [5] does not math document structure defined by space format
+    or index: invalid array size 4 (expected at least 5)'
 ...
 t1 = s:replace{4, 5, 6, 7, 8}
 ---
@@ -1071,8 +1071,8 @@ sk = s:create_index('sk', {parts = {{2, 'unsigned', is_nullable = true}}})
 -- Test tuple_compare_slowpath, tuple_compare_with_key_slowpath.
 s:replace{} -- Fail
 ---
-- error: Tuple field count 0 is less than required by space format or defined indexes
-    (expected at least 1)
+- error: 'Tuple field [1] does not math document structure defined by space format
+    or index: invalid array size 0 (expected at least 1)'
 ...
 -- Compare full vs not full.
 s:replace{2}
@@ -1772,8 +1772,8 @@ s:format(format)
 -- Field 2 is not nullable.
 s:insert{5}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s:insert{5, box.NULL}
 ---
@@ -1791,8 +1791,8 @@ s:insert{5, box.NULL}
 ...
 s:insert{5}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s.index.secondary:alter{parts={{2, 'unsigned', is_nullable=false}}}
 ---
@@ -1811,8 +1811,8 @@ s:insert{5, box.NULL}
 ...
 s:insert{5}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s.index.secondary:alter{parts={{2, 'unsigned', is_nullable=true}}}
 ---
@@ -1857,13 +1857,13 @@ _ = s:delete{5}
 ...
 s:format(format) -- Still fail.
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s.index.secondary:alter{parts={{2, 'unsigned', is_nullable=false}}} -- Still fail.
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 -- Now check we can set nullability to false step by step.
 _ = s:delete{6}
@@ -1882,8 +1882,8 @@ s:insert{5, box.NULL} -- Fail.
 ...
 s:insert{5} -- Fail.
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 format[2].is_nullable = true
 ---
@@ -1901,8 +1901,8 @@ s:insert{5, box.NULL} -- Fail.
 ...
 s:insert{5} -- Fail.
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 format[2].is_nullable = false
 ---
@@ -1916,8 +1916,8 @@ s:select{}
 ...
 s:insert{5} -- Fail.
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s:insert{9, 10} -- Success.
 ---
diff --git a/test/vinyl/constraint.result b/test/vinyl/constraint.result
index 4c533f7f2..61161ee98 100644
--- a/test/vinyl/constraint.result
+++ b/test/vinyl/constraint.result
@@ -89,13 +89,13 @@ index = space:create_index('primary', { type = 'tree', parts = {1,'unsigned',2,'
 ...
 space:insert{1}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 space:replace{1}
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 space:delete{1}
 ---
@@ -107,8 +107,8 @@ space:update(1, {{'=', 1, 101}})
 ...
 space:upsert({1}, {{'+', 1, 10}})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 space:get{1}
 ---
diff --git a/test/vinyl/errinj.result b/test/vinyl/errinj.result
index dec469423..f176cc029 100644
--- a/test/vinyl/errinj.result
+++ b/test/vinyl/errinj.result
@@ -1635,8 +1635,8 @@ errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", 0.001)
 ...
 s:create_index('sk', {parts = {2, 'unsigned'}}) -- must fail
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 errinj.set("ERRINJ_VY_READ_PAGE_TIMEOUT", 0)
 ---
@@ -2088,8 +2088,8 @@ fiber.sleep(0)
 ...
 s:format{{'key', 'unsigned'}, {'value', 'unsigned'}} -- must fail
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s:select()
 ---
@@ -2113,8 +2113,8 @@ fiber.sleep(0)
 ...
 s:create_index('sk', {parts = {2, 'unsigned'}})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 2)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 2)'
 ...
 s:select()
 ---
diff --git a/test/vinyl/savepoint.result b/test/vinyl/savepoint.result
index fb93b8fe1..e80f21a8c 100644
--- a/test/vinyl/savepoint.result
+++ b/test/vinyl/savepoint.result
@@ -124,8 +124,8 @@ index2 = space:create_index('secondary', { parts = {2, 'int', 3, 'str'} })
 ...
 space:insert({1})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 3)'
 ...
 space:insert({1, 1, 'a'})
 ---
@@ -624,8 +624,8 @@ space:insert({4, 2, 'b'})
 ...
 space:upsert({2}, {{'=', 4, 1000}})
 ---
-- error: Tuple field count 1 is less than required by space format or defined indexes
-    (expected at least 3)
+- error: 'Tuple field [2] does not math document structure defined by space format
+    or index: invalid array size 1 (expected at least 3)'
 ...
 index3:delete({3, 'a'})
 ---
-- 
2.19.2




More information about the Tarantool-patches mailing list