From 9036eeeb80702cff55eaaf1a61a5b78cf9e3c015 Mon Sep 17 00:00:00 2001
From: Roman Tsisyk <roman@tsisyk.com>
Date: Fri, 22 Jan 2016 15:39:01 +0300
Subject: [PATCH] Fix #1042: bad error message for _vspace, _vindex, _vuser,
 etc.

---
 src/box/errcode.h                |  3 ++
 src/box/index.cc                 | 84 ++++++++++++++++++++------------
 src/box/index.h                  | 14 +++++-
 src/box/memtx_bitset.cc          | 12 +----
 src/box/memtx_bitset.h           |  1 -
 src/box/memtx_hash.cc            |  3 +-
 src/box/memtx_rtree.cc           | 14 ++----
 src/box/memtx_tree.cc            | 10 ++--
 src/box/sophia_index.cc          |  7 ++-
 src/box/sysview_engine.cc        | 37 ++++++++++++++
 src/box/sysview_index.cc         | 10 ----
 src/box/sysview_index.h          |  3 --
 test/big/iterator.result         |  6 ++-
 test/big/sql.result              |  4 +-
 test/box/access_sysview.result   | 26 +++++++++-
 test/box/access_sysview.test.lua | 10 +++-
 test/box/misc.result             |  4 +-
 test/box/rtree_misc.result       | 13 +++--
 test/sophia/constraint.result    |  3 +-
 test/sophia/gh.result            |  2 +-
 20 files changed, 174 insertions(+), 92 deletions(-)

diff --git a/src/box/errcode.h b/src/box/errcode.h
index cb05f90ec2..3b2fe4f8e7 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -165,6 +165,9 @@ struct errcode_record {
 	/*109 */_(ER_WRONG_SCHEMA_VERSION, 2, "Wrong schema version, current: %d, in request: %u") \
 	/*110 */_(ER_SLAB_ALLOC_MAX, 2, "Failed to allocate %u bytes for tuple in the slab allocator: tuple is too large. Check 'slab_alloc_maximal' configuration option.") \
 	/*112 */_(ER_WRONG_SPACE_OPTIONS, 2, "Wrong space options (field %u): %s") \
+	/*113 */_(ER_UNSUPPORTED_INDEX_FEATURE,	2, "Index '%s' (%s) of space '%s' (%s) does not support %s") \
+	/*114 */_(ER_VIEW_IS_RO,		2, "View '%s' is read-only") \
+
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/index.cc b/src/box/index.cc
index df58dafe3a..4bc504a029 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -59,6 +59,18 @@ static_assert(sizeof(iterator_type_strs) / sizeof(const char *) ==
 
 /* {{{ Utilities. **********************************************/
 
+UnsupportedIndexFeature::UnsupportedIndexFeature(const char *file,
+	unsigned line, const Index *index, const char *what)
+	: ClientError(file, line, ER_UNKNOWN)
+{
+	struct key_def *key_def = index->key_def;
+	struct space *space = space_cache_find(key_def->space_id);
+	m_errcode = ER_UNSUPPORTED_INDEX_FEATURE;
+	error_format_msg(this, tnt_errcode_desc(m_errcode), key_def->name,
+			 index_type_strs[key_def->type],
+			 space->def.name, space->def.engine_name, what);
+}
+
 void
 key_validate_parts(struct key_def *key_def, const char *key,
 		   uint32_t part_count)
@@ -160,26 +172,21 @@ Index::~Index()
 size_t
 Index::size() const
 {
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-	          index_type_strs[key_def->type],
-	          "size()");
+	tnt_raise(UnsupportedIndexFeature, this, "size()");
+	return 0;
 }
 
 struct tuple *
 Index::min(const char* /* key */, uint32_t /* part_count */) const
 {
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "min()");
+	tnt_raise(UnsupportedIndexFeature, this, "min()");
 	return NULL;
 }
 
 struct tuple *
 Index::max(const char* /* key */, uint32_t /* part_count */) const
 {
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "max()");
+	tnt_raise(UnsupportedIndexFeature, this, "max()");
 	return NULL;
 }
 
@@ -187,9 +194,7 @@ struct tuple *
 Index::random(uint32_t rnd) const
 {
 	(void) rnd;
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "random()");
+	tnt_raise(UnsupportedIndexFeature, this, "random()");
 	return NULL;
 }
 
@@ -197,19 +202,35 @@ size_t
 Index::count(enum iterator_type /* type */, const char* /* key */,
              uint32_t /* part_count */) const
 {
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "count()");
+	tnt_raise(UnsupportedIndexFeature, this, "count()");
 	return 0;
 }
 
+struct tuple *
+Index::findByKey(const char *key, uint32_t part_count) const
+{
+	(void) key;
+	(void) part_count;
+	tnt_raise(UnsupportedIndexFeature, this, "findByKey()");
+	return NULL;
+}
+
 struct tuple *
 Index::findByTuple(struct tuple *tuple) const
 {
 	(void) tuple;
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "findByTuple()");
+	tnt_raise(UnsupportedIndexFeature, this, "findByTuple()");
+	return NULL;
+}
+
+struct tuple *
+Index::replace(struct tuple *old_tuple, struct tuple *new_tuple,
+		     enum dup_replace_mode mode)
+{
+	(void) old_tuple;
+	(void) new_tuple;
+	(void) mode;
+	tnt_raise(UnsupportedIndexFeature, this, "replace()");
 	return NULL;
 }
 
@@ -219,6 +240,17 @@ Index::bsize() const
 	return 0;
 }
 
+void
+Index::initIterator(struct iterator *ptr, enum iterator_type type,
+		    const char *key, uint32_t part_count) const
+{
+	(void) ptr;
+	(void) type;
+	(void) key;
+	(void) part_count;
+	tnt_raise(UnsupportedIndexFeature, this, "requested iterator type");
+}
+
 /**
  * Create a read view for iterator so further index modifications
  * will not affect the iterator iteration.
@@ -227,9 +259,7 @@ void
 Index::createReadViewForIterator(struct iterator *iterator)
 {
 	(void) iterator;
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "consistent read view");
+	tnt_raise(UnsupportedIndexFeature, this, "consistent read view");
 }
 
 /**
@@ -240,9 +270,7 @@ void
 Index::destroyReadViewForIterator(struct iterator *iterator)
 {
 	(void) iterator;
-	tnt_raise(ClientError, ER_UNSUPPORTED,
-		  index_type_strs[key_def->type],
-		  "consistent read view");
+	tnt_raise(UnsupportedIndexFeature, this, "consistent read view");
 }
 
 static inline Index *
@@ -341,9 +369,7 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
 		Index *index = check_index(space_id, index_id, &space);
 		if (index->key_def->type != TREE) {
 			/* Show nice error messages in Lua */
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  index_type_strs[index->key_def->type],
-				  "min()");
+			tnt_raise(UnsupportedIndexFeature, index, "min()");
 		}
 		uint32_t part_count = key ? mp_decode_array(&key) : 0;
 		key_validate(index->key_def, ITER_GE, key, part_count);
@@ -370,9 +396,7 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
 		Index *index = check_index(space_id, index_id, &space);
 		if (index->key_def->type != TREE) {
 			/* Show nice error messages in Lua */
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  index_type_strs[index->key_def->type],
-				  "max()");
+			tnt_raise(UnsupportedIndexFeature, index, "max()");
 		}
 		uint32_t part_count = key ? mp_decode_array(&key) : 0;
 		key_validate(index->key_def, ITER_LE, key, part_count);
diff --git a/src/box/index.h b/src/box/index.h
index 407b06bef6..e0ab4bfd77 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -330,11 +330,11 @@ class Index {
 	virtual struct tuple *random(uint32_t rnd) const;
 	virtual size_t count(enum iterator_type type, const char *key,
 			     uint32_t part_count) const;
-	virtual struct tuple *findByKey(const char *key, uint32_t part_count) const = 0;
+	virtual struct tuple *findByKey(const char *key, uint32_t part_count) const;
 	virtual struct tuple *findByTuple(struct tuple *tuple) const;
 	virtual struct tuple *replace(struct tuple *old_tuple,
 				      struct tuple *new_tuple,
-				      enum dup_replace_mode mode) = 0;
+				      enum dup_replace_mode mode);
 	virtual size_t bsize() const;
 
 	/**
@@ -358,6 +358,16 @@ class Index {
 	virtual void destroyReadViewForIterator(struct iterator *iterator);
 };
 
+/*
+ * A wrapper for ClientError(ER_UNSUPPORTED_INDEX_FEATURE, ...) to format
+ * nice error messages (see gh-1042). You never need to catch this class.
+ */
+class UnsupportedIndexFeature: public ClientError {
+public:
+	UnsupportedIndexFeature(const char *file, unsigned line,
+				const Index *index, const char *what);
+};
+
 struct IteratorGuard
 {
 	struct iterator *it;
diff --git a/src/box/memtx_bitset.cc b/src/box/memtx_bitset.cc
index 58a68df8fd..c3eff30fcd 100644
--- a/src/box/memtx_bitset.cc
+++ b/src/box/memtx_bitset.cc
@@ -253,15 +253,6 @@ MemtxBitset::allocIterator() const
 	return (struct iterator *) it;
 }
 
-struct tuple *
-MemtxBitset::findByKey(const char *key, uint32_t part_count) const
-{
-	(void) key;
-	(void) part_count;
-	tnt_raise(ClientError, ER_UNSUPPORTED, "MemtxBitset", "findByKey()");
-	return NULL;
-}
-
 static inline const char *
 make_key(const char *field, uint32_t *key_len)
 {
@@ -377,8 +368,7 @@ MemtxBitset::initIterator(struct iterator *iterator, enum iterator_type type,
 						       bitset_key_size);
 			break;
 		default:
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "MemtxBitset", "requested iterator type");
+			return initIterator(iterator, type, key, part_count);
 		}
 
 		if (rc != 0) {
diff --git a/src/box/memtx_bitset.h b/src/box/memtx_bitset.h
index 528c2fa91a..cadfbbe011 100644
--- a/src/box/memtx_bitset.h
+++ b/src/box/memtx_bitset.h
@@ -50,7 +50,6 @@ class MemtxBitset: public MemtxIndex {
 	virtual size_t size() const;
 	virtual size_t count(enum iterator_type type, const char *key,
 			     uint32_t part_count) const;
-	virtual struct tuple *findByKey(const char *key, uint32_t part_count) const;
 	virtual struct tuple *replace(struct tuple *old_tuple,
 				      struct tuple *new_tuple,
 				      enum dup_replace_mode mode);
diff --git a/src/box/memtx_hash.cc b/src/box/memtx_hash.cc
index a801d02e47..5c56fa8494 100644
--- a/src/box/memtx_hash.cc
+++ b/src/box/memtx_hash.cc
@@ -375,8 +375,7 @@ MemtxHash::initIterator(struct iterator *ptr, enum iterator_type type,
 		it->base.next = hash_iterator_eq;
 		break;
 	default:
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-			  "Hash index", "requested iterator type");
+		return Index::initIterator(ptr, type, key, part_count);
 	}
 }
 
diff --git a/src/box/memtx_rtree.cc b/src/box/memtx_rtree.cc
index e9d87e8eb9..e4d590236d 100644
--- a/src/box/memtx_rtree.cc
+++ b/src/box/memtx_rtree.cc
@@ -156,10 +156,9 @@ MemtxRTree::MemtxRTree(struct key_def *key_def)
 	m_dimension = key_def->opts.dimension;
 	if (m_dimension < 1 || m_dimension > RTREE_MAX_DIMENSION) {
 		char message[64];
-		snprintf(message, 64, "dimension (%u) must belong to range "
+		snprintf(message, 64, "dimension (%u): must belong to range "
 			 "[%u, %u]", m_dimension, 1, RTREE_MAX_DIMENSION);
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-			  "RTREE index", message);
+		tnt_raise(UnsupportedIndexFeature, this, message);
 	}
 
 	memtx_index_arena_init();
@@ -242,10 +241,8 @@ MemtxRTree::initIterator(struct iterator *iterator, enum iterator_type type,
 	struct rtree_rect rect;
 	if (part_count == 0) {
 		if (type != ITER_ALL) {
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree index",
-				  "It is possible to omit "
-				  "key only for ITER_ALL");
+			tnt_raise(UnsupportedIndexFeature, this,
+				  "empty keys for requested iterator type");
 		}
 	} else if (mp_decode_rect_from_key(&rect, m_dimension,
 					   key, part_count)) {
@@ -280,8 +277,7 @@ MemtxRTree::initIterator(struct iterator *iterator, enum iterator_type type,
 		op = SOP_NEIGHBOR;
 		break;
 	default:
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-			  "RTREE index", "Unsupported search operation for RTREE");
+		return initIterator(iterator, type, key, part_count);
 	}
 	rtree_search(&m_tree, &rect, op, &it->impl);
 }
diff --git a/src/box/memtx_tree.cc b/src/box/memtx_tree.cc
index 1a8b5cc6d7..904e1d37ac 100644
--- a/src/box/memtx_tree.cc
+++ b/src/box/memtx_tree.cc
@@ -295,9 +295,10 @@ MemtxTree::initIterator(struct iterator *iterator, enum iterator_type type,
 		 * If no key is specified, downgrade equality
 		 * iterators to a full range.
 		 */
-		if (type < 0 || type > ITER_GT)
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "Tree index", "requested iterator type");
+		if (type < 0 || type > ITER_GT) {
+			return Index::initIterator(iterator, type, key,
+						   part_count);
+		}
 		type = iterator_type_is_reverse(type) ? ITER_LE : ITER_GE;
 		key = 0;
 	}
@@ -347,8 +348,7 @@ MemtxTree::initIterator(struct iterator *iterator, enum iterator_type type,
 		it->base.next = tree_iterator_bwd_skip_one;
 		break;
 	default:
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-			  "Tree index", "requested iterator type");
+		return Index::initIterator(iterator, type, key, part_count);
 	}
 }
 
diff --git a/src/box/sophia_index.cc b/src/box/sophia_index.cc
index dfcbb84a94..68c15dc4c8 100644
--- a/src/box/sophia_index.cc
+++ b/src/box/sophia_index.cc
@@ -690,8 +690,8 @@ SophiaIndex::initIterator(struct iterator *ptr,
 	assert(it->cursor == NULL);
 	if (part_count > 0) {
 		if (part_count != key_def->part_count) {
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-			          "Sophia Index iterator", "partial keys");
+			tnt_raise(UnsupportedIndexFeature, this,
+				  "partial keys");
 		}
 	} else {
 		key = NULL;
@@ -718,8 +718,7 @@ SophiaIndex::initIterator(struct iterator *ptr,
 	case ITER_LT: compare = "<";
 		break;
 	default:
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-		          "Sophia Index", "requested iterator type");
+		return initIterator(ptr, type, key, part_count);
 	}
 	it->base.next = sophia_iterator_next;
 	it->cursor = sp_cursor(env);
diff --git a/src/box/sysview_engine.cc b/src/box/sysview_engine.cc
index bb6659a33e..97ad63c2d9 100644
--- a/src/box/sysview_engine.cc
+++ b/src/box/sysview_engine.cc
@@ -37,8 +37,45 @@ struct SysviewSpace: public Handler {
 	SysviewSpace(Engine *e) : Handler(e) {}
 
 	virtual ~SysviewSpace() {}
+
+	virtual struct tuple *
+	executeReplace(struct txn *, struct space *, struct request *);
+	virtual struct tuple *
+	executeDelete(struct txn *, struct space *, struct request *);
+	virtual struct tuple *
+	executeUpdate(struct txn *, struct space *, struct request *);
+	virtual void
+	executeUpsert(struct txn *, struct space *, struct request *);
 };
 
+struct tuple *
+SysviewSpace::executeReplace(struct txn *, struct space *space,
+			      struct request *)
+{
+	tnt_raise(ClientError, ER_VIEW_IS_RO, space->def.name);
+	return NULL;
+}
+
+struct tuple *
+SysviewSpace::executeDelete(struct txn*, struct space *space, struct request *)
+{
+	tnt_raise(ClientError, ER_VIEW_IS_RO, space->def.name);
+	return NULL;
+}
+
+struct tuple *
+SysviewSpace::executeUpdate(struct txn*, struct space *space, struct request *)
+{
+	tnt_raise(ClientError, ER_VIEW_IS_RO, space->def.name);
+	return NULL;
+}
+
+void
+SysviewSpace::executeUpsert(struct txn *, struct space *space, struct request *)
+{
+	tnt_raise(ClientError, ER_VIEW_IS_RO, space->def.name);
+}
+
 SysviewEngine::SysviewEngine()
 	:Engine("sysview")
 {
diff --git a/src/box/sysview_index.cc b/src/box/sysview_index.cc
index a55493963d..4306ff6a1d 100644
--- a/src/box/sysview_index.cc
+++ b/src/box/sysview_index.cc
@@ -141,16 +141,6 @@ SysviewIndex::findByKey(const char *key, uint32_t part_count) const
 	return tuple;
 }
 
-struct tuple *
-SysviewIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple,
-		     enum dup_replace_mode mode)
-{
-	(void) old_tuple;
-	(void) new_tuple;
-	(void) mode;
-	tnt_raise(ClientError, ER_UNSUPPORTED, "SysviewIndex", "replace()");
-}
-
 static bool
 vspace_filter(struct space *source, struct tuple *tuple)
 {
diff --git a/src/box/sysview_index.h b/src/box/sysview_index.h
index e59026acbb..cd5d91c2c7 100644
--- a/src/box/sysview_index.h
+++ b/src/box/sysview_index.h
@@ -43,9 +43,6 @@ class SysviewIndex: public Index {
 		     uint32_t source_index_id, sysview_filter_f filter);
 	virtual ~SysviewIndex();
 	virtual struct tuple *findByKey(const char *key, uint32_t part_count) const;
-	virtual struct tuple *replace(struct tuple *old_tuple,
-				      struct tuple *new_tuple,
-				      enum dup_replace_mode mode);
 
 	virtual struct iterator *allocIterator() const;
 	virtual void initIterator(struct iterator *iterator,
diff --git a/test/big/iterator.result b/test/big/iterator.result
index 4ea3063e1c..21f39f5978 100644
--- a/test/big/iterator.result
+++ b/test/big/iterator.result
@@ -893,7 +893,8 @@ iterate('tweedledum', 'i5', 1, 3, box.index.EQ, 'sid_005', 'tid_995', 'a')
 -------------------------------------------------------------------------------
 space.index['primary']:pairs({}, {iterator = -666 })
 ---
-- error: Tree index does not support requested iterator type
+- error: Index 'primary' (TREE) of space 'tweedledum' (memtx) does not support requested
+    iterator type
 ...
 -- Test cases for #123: box.index.count does not check arguments properly
 space.index['primary']:pairs(function() end, { iterator = box.index.EQ })
@@ -1079,7 +1080,8 @@ space:select(2)
 ...
 space:select(5, {iterator="GE"})
 ---
-- error: Hash index does not support requested iterator type
+- error: Index 'primary' (HASH) of space 'test' (memtx) does not support requested
+    iterator type
 ...
 space:select(nil, {iterator="GE"})
 ---
diff --git a/test/big/sql.result b/test/big/sql.result
index fb67f223e1..c8a94d4507 100644
--- a/test/big/sql.result
+++ b/test/big/sql.result
@@ -591,11 +591,11 @@ s.index[1]:select{}
 ...
 s.index[0]:min()
 ---
-- error: HASH does not support min()
+- error: Index 'primary' (HASH) of space 'tweedledum' (memtx) does not support min()
 ...
 s.index[0]:max()
 ---
-- error: HASH does not support max()
+- error: Index 'primary' (HASH) of space 'tweedledum' (memtx) does not support max()
 ...
 s.index[1]:min()
 ---
diff --git a/test/box/access_sysview.result b/test/box/access_sysview.result
index 39e200c4e2..9f37cfeea4 100644
--- a/test/box/access_sysview.result
+++ b/test/box/access_sysview.result
@@ -24,10 +24,32 @@ session = box.session
 ---
 - true
 ...
--- error: sysview does not support replace()
+-- gh-1042: bad error message for _vspace, _vuser, _vindex, etc.
+-- Space '_vspace' (sysview) does not support replace
 box.space._vspace:replace({1, 1, 'test'})
 ---
-- error: sysview does not support replace
+- error: View '_vspace' is read-only
+...
+box.space._vspace:delete(1)
+---
+- error: View '_vspace' is read-only
+...
+box.space._vspace:update(1, {{'=', 2, 48}})
+---
+- error: View '_vspace' is read-only
+...
+-- error: Index 'primary' of space '_vspace' (sysview) does not support xxx()
+box.space._vspace.index.primary:len()
+---
+- error: Index 'primary' (TREE) of space '_vspace' (sysview) does not support size()
+...
+box.space._vspace.index.primary:random(48)
+---
+- error: Index 'primary' (TREE) of space '_vspace' (sysview) does not support random()
+...
+box.space._vspace.index.primary:min()
+---
+- error: Index 'primary' (TREE) of space '_vspace' (sysview) does not support min()
 ...
 session.su('guest')
 ---
diff --git a/test/box/access_sysview.test.lua b/test/box/access_sysview.test.lua
index 1bd47aeed2..d67437a2d3 100644
--- a/test/box/access_sysview.test.lua
+++ b/test/box/access_sysview.test.lua
@@ -10,8 +10,16 @@ session = box.session
 #box.space._vpriv:select{} == #box.space._priv:select{}
 #box.space._vfunc:select{} == #box.space._func:select{}
 
--- error: sysview does not support replace()
+-- gh-1042: bad error message for _vspace, _vuser, _vindex, etc.
+-- Space '_vspace' (sysview) does not support replace
 box.space._vspace:replace({1, 1, 'test'})
+box.space._vspace:delete(1)
+box.space._vspace:update(1, {{'=', 2, 48}})
+
+-- error: Index 'primary' of space '_vspace' (sysview) does not support xxx()
+box.space._vspace.index.primary:len()
+box.space._vspace.index.primary:random(48)
+box.space._vspace.index.primary:min()
 
 session.su('guest')
 
diff --git a/test/box/misc.result b/test/box/misc.result
index ca8b2e54a3..69f8b4ea13 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -269,10 +269,12 @@ t;
   - 'box.error.NO_SUCH_INDEX : 35'
   - 'box.error.UNKNOWN_RTREE_INDEX_DISTANCE_TYPE : 103'
   - 'box.error.TUPLE_IS_TOO_LONG : 27'
+  - 'box.error.VIEW_IS_RO : 113'
   - 'box.error.UNKNOWN_SERVER : 62'
   - 'box.error.FUNCTION_EXISTS : 52'
-  - 'box.error.NO_SUCH_FUNCTION : 51'
   - 'box.error.injection : table: <address>
+  - 'box.error.NO_SUCH_FUNCTION : 51'
+  - 'box.error.UNSUPPORTED_INDEX_FEATURE : 112'
   - 'box.error.INDEX_FIELD_COUNT : 39'
   - 'box.error.ROLE_LOOP : 87'
   - 'box.error.TUPLE_NOT_FOUND : 4'
diff --git a/test/box/rtree_misc.result b/test/box/rtree_misc.result
index dcba956766..785976aec7 100644
--- a/test/box/rtree_misc.result
+++ b/test/box/rtree_misc.result
@@ -193,11 +193,11 @@ s.index.spatial:count()
 ...
 s.index.spatial:min()
 ---
-- error: RTREE does not support min()
+- error: Index 'spatial' (RTREE) of space 'spatial' (memtx) does not support min()
 ...
 s.index.spatial:max()
 ---
-- error: RTREE does not support max()
+- error: Index 'spatial' (RTREE) of space 'spatial' (memtx) does not support max()
 ...
 -- seems that drop can't fail
 s.index.spatial:drop()
@@ -493,12 +493,14 @@ i = s:create_index('p')
 -- dimension too big
 i = s:create_index('s', {type = 'rtree', parts = {2, 'array'}, dimension = 21})
 ---
-- error: RTREE index does not support dimension (21) must belong to range [1, 20]
+- error: 'Index ''s'' (RTREE) of space ''s'' (memtx) does not support dimension (21):
+    must belong to range [1, 20]'
 ...
 -- dimension too low
 i = s:create_index('s', {type = 'rtree', parts = {2, 'array'}, dimension = 0})
 ---
-- error: RTREE index does not support dimension (0) must belong to range [1, 20]
+- error: 'Index ''s'' (RTREE) of space ''s'' (memtx) does not support dimension (0):
+    must belong to range [1, 20]'
 ...
 -- cant be unique
 i = s:create_index('s', {type = 'rtree', parts = {2, 'array'}, unique = true})
@@ -576,7 +578,8 @@ box.space._index:insert{s.id, 2, 's', 'rtree', empty_map, {{2, 'array'}}}
 ...
 box.space._index:insert{s.id, 2, 's', 'rtree', {unique = false, dimension = 22}, {{2, 'array'}}}
 ---
-- error: RTREE index does not support dimension (22) must belong to range [1, 20]
+- error: 'Index ''s'' (RTREE) of space ''s'' (memtx) does not support dimension (22):
+    must belong to range [1, 20]'
 ...
 box.space._index:insert{s.id, 2, 's', 'rtree', {unique = false, dimension = 'dimension'}, {{2, 'array'}}}
 ---
diff --git a/test/sophia/constraint.result b/test/sophia/constraint.result
index c2586cc370..a0e92f7517 100644
--- a/test/sophia/constraint.result
+++ b/test/sophia/constraint.result
@@ -129,7 +129,8 @@ space:get{1}
 ...
 index:select({1}, {iterator = box.index.GT})
 ---
-- error: Sophia Index iterator does not support partial keys
+- error: Index 'primary' (TREE) of space 'test' (sophia) does not support partial
+    keys
 ...
 space:drop()
 ---
diff --git a/test/sophia/gh.result b/test/sophia/gh.result
index 53c0c87f25..9d735c7973 100644
--- a/test/sophia/gh.result
+++ b/test/sophia/gh.result
@@ -202,7 +202,7 @@ s:insert{'1','2','0'}
 ...
 i:select({'1','2',nil},{iterator='GT'})
 ---
-- error: Sophia Index iterator does not support partial keys
+- error: Index 'primary' (TREE) of space 't' (sophia) does not support partial keys
 ...
 s:drop()
 ---
-- 
GitLab