diff --git a/src/box/index.cc b/src/box/index.cc
index 4d3074d50b07f13d07dc6d3096dc507c2e4a4fe1..209d92aa73d62bd90b2765a0cc983677231b36f4 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -74,16 +74,28 @@ key_validate(struct key_def *key_def, enum iterator_type type, const char *key,
 	}
 
         if (key_def->type == RTREE) {
-                if (part_count != 1 && part_count != 2 && part_count != 4) {
+                if (part_count != 1 && part_count != 2 && part_count != 4)
                         tnt_raise(ClientError, ER_KEY_PART_COUNT, 4, part_count);
-                }
-#if 0
-		for (uint32_t part = 0; part < part_count; part++) {
+                if (part_count == 1) {
 			enum mp_type mp_type = mp_typeof(*key);
-			mp_next(&key);
-			key_mp_type_validate(NUM, mp_type, ER_KEY_PART_TYPE, part);
-		}
-#endif
+			key_mp_type_validate(ARRAY, mp_type, ER_KEY_PART_TYPE, 0);
+			uint32_t arr_size = mp_decode_array(&key);
+			if (arr_size != 2 && arr_size != 4)
+				tnt_raise(ClientError, ER_UNSUPPORTED,
+					  "R-Tree key", "Key should contain 2 (point) "
+					  "or 4 (rectangle) numeric coordinates");
+			for (uint32_t part = 0; part < arr_size; part++) {
+				enum mp_type mp_type = mp_typeof(*key);
+				mp_next(&key);
+				key_mp_type_validate(NUMBER, mp_type, ER_KEY_PART_TYPE, 0);
+			}
+                } else {
+			for (uint32_t part = 0; part < part_count; part++) {
+				enum mp_type mp_type = mp_typeof(*key);
+				mp_next(&key);
+				key_mp_type_validate(NUMBER, mp_type, ER_KEY_PART_TYPE, part);
+			}
+                }
         } else {
                 if (part_count > key_def->part_count)
                         tnt_raise(ClientError, ER_KEY_PART_COUNT,
diff --git a/src/box/index.h b/src/box/index.h
index 0b22c3fb9e4cdbb3511c806c1edf8b1a875c527b..a86fd2f1c7f5e6110dc620671d396727921467a4 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -105,7 +105,7 @@ iterator_close(struct iterator *it) {
  *
  * @param key_def key definition
  * @param type iterator type (see enum iterator_type)
- * @param key BER-encoded key
+ * @param key msgpack-encoded key
  * @param part_count number of parts in \a key
  */
 void
diff --git a/src/box/key_def.cc b/src/box/key_def.cc
index 463d19ada18869f0c452e34f96e9ad07c684c9b2..7a071d490e7d15a0cbfc22193b8cf4883d56fba2 100644
--- a/src/box/key_def.cc
+++ b/src/box/key_def.cc
@@ -33,7 +33,7 @@
 #include <stdio.h>
 #include "exception.h"
 
-const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARRAY", "\0"};
+const char *field_type_strs[] = {"UNKNOWN", "NUM", "STR", "ARRAY", "NUMBER", ""};
 STRS(index_type, ENUM_INDEX_TYPE);
 
 const uint32_t key_mp_type[] = {
@@ -41,6 +41,7 @@ const uint32_t key_mp_type[] = {
 	/* [NUM]     = */  1U << MP_UINT,
 	/* [STR]     =  */  1U << MP_STR,
 	/* [ARRAY]   =  */  1U << MP_ARRAY,
+	/* [NUMBER]  =  */  (1U << MP_UINT) | (1U << MP_INT) | (1U << MP_FLOAT) | (1U << MP_DOUBLE),
 };
 
 enum schema_object_type
diff --git a/src/box/key_def.h b/src/box/key_def.h
index fb7a3a4b7059256a6f590adebbd42e721b85303e..008db160fb2052361ddf93939e0596d33f30fe8b 100644
--- a/src/box/key_def.h
+++ b/src/box/key_def.h
@@ -75,7 +75,7 @@ schema_object_type(const char *name);
  * since there is a mismatch between enum name (STRING) and type
  * name literal ("STR"). STR is already used as Objective C type.
  */
-enum field_type { UNKNOWN = 0, NUM, STRING, ARRAY, field_type_MAX };
+enum field_type { UNKNOWN = 0, NUM, STRING, ARRAY, NUMBER, field_type_MAX };
 extern const char *field_type_strs[];
 
 static inline uint32_t
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 212946343b35073452109f2a83a90c8b8ee6161b..ce473137025c19635628fb7603051f1de6b508e1 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -533,8 +533,8 @@ function box.schema.space.bless(space)
     index_mt.__index = index_mt
     -- min and max
     index_mt.min = function(index, key)
-        if index.type == 'HASH' then
-            box.error(box.error.UNSUPPORTED, 'HASH', 'min()')
+        if index.type ~= 'TREE' then
+            box.error(box.error.UNSUPPORTED, index.type, 'min()')
         end
         local lst = index:select(key, { iterator = 'GE', limit = 1 })[1]
         if lst ~= nil then
@@ -544,8 +544,8 @@ function box.schema.space.bless(space)
         end
     end
     index_mt.max = function(index, key)
-        if index.type == 'HASH' then
-            box.error(box.error.UNSUPPORTED, 'HASH', 'max()')
+        if index.type ~= 'TREE' then
+            box.error(box.error.UNSUPPORTED, index.type, 'max()')
         end
         local lst = index:select(key, { iterator = 'LE', limit = 1 })[1]
         if lst ~= nil then
diff --git a/src/box/rtree_index.cc b/src/box/rtree_index.cc
index f8ddddf7e216f5a60ce0be2fadd95921191002b8..5869d24d00d239786f7a8d62aa21b84577452a4d 100644
--- a/src/box/rtree_index.cc
+++ b/src/box/rtree_index.cc
@@ -44,9 +44,9 @@ static int rtree_page_pool_initialized = 0;
 inline void extract_rectangle(struct rtree_rect *rect,
 			      const struct tuple *tuple, struct key_def *kd)
 {
+        assert(kd->part_count == 1);
 	const char *elems = tuple_field(tuple, kd->parts[0].fieldno);
 	uint32_t size = mp_decode_array(&elems);
-        assert (kd->part_count == 1);
 	switch (size) {
 	case 1: // array
 	{
@@ -197,9 +197,7 @@ RTreeIndex::findByKey(const char *key, uint32_t part_count) const
 			rect.upper_point.coords[1] = mp_decode_num(&key, 3);
 			break;
 		default:
-			tnt_raise(ClientError, ER_UNSUPPORTED,
-				  "R-Tree key", "Key should be array of 2 (point) "
-				  "or 4 (rectangle) numeric coordinates");
+			assert(false);
 		}
 		break;
 	}
@@ -218,9 +216,7 @@ RTreeIndex::findByKey(const char *key, uint32_t part_count) const
 		rect.upper_point.coords[1] = mp_decode_num(&key, 3);
 		break;
 	default:
-		tnt_raise(ClientError, ER_UNSUPPORTED,
-			  "R-Tree key", "Key should contain 2 (point) "
-			  "or 4 (rectangle) numeric coordinates");
+		assert(false);
 	}
         struct tuple *result = NULL;
         if (rtree_search(&tree, &rect, SOP_OVERLAPS, &iterator))
diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index de65e1af7b86c997256824d9bd0fc7e2844ac9ea..d00728e2c8134a197c5242071fbcf628b359545c 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -36,15 +36,6 @@
 #include <exception.h>
 #include <stdio.h>
 
-#ifndef DBL_MIN
-#define DBL_MIN		4.94065645841246544e-324
-#define FLT_MIN		((float)1.40129846432481707e-45)
-#endif
-#ifndef DBL_MAX
-#define DBL_MAX		1.79769313486231470e+308
-#define FLT_MAX		((float)3.40282346638528860e+38)
-#endif
-
 /** Global table of tuple formats */
 struct tuple_format **tuple_formats;
 struct tuple_format *tuple_format_ber;
diff --git a/src/lib/salad/rtree.c b/src/lib/salad/rtree.c
index 1ad73cd886e99468e18ff89aeec660f94fcc124a..a14f89134ee1ff5555b177baadab3cb0a7e1fcc9 100644
--- a/src/lib/salad/rtree.c
+++ b/src/lib/salad/rtree.c
@@ -83,7 +83,6 @@ struct rtree_reinsert_list {
 /* R-tree rectangle methods */
 /*------------------------------------------------------------------------- */
 
-
 void
 rtree_rect_normalize(struct rtree_rect *rect)
 {
@@ -284,8 +283,8 @@ rtree_page_cover(const struct rtree_page *page)
 
 /* Create root page by first inserting record */
 static void
-rtree_page_init_record(struct rtree_page *page,
-		       struct rtree_rect *rect, record_t obj)
+rtree_page_init_with_record(struct rtree_page *page,
+			    struct rtree_rect *rect, record_t obj)
 {
 	page->n = 1;
 	page->b[0].rect = *rect;
@@ -294,8 +293,8 @@ rtree_page_init_record(struct rtree_page *page,
 
 /* Create root page by branch */
 static void
-rtree_page_init_branch(struct rtree_page *page,
-		       const struct rtree_page_branch *br)
+rtree_page_init_with_branch(struct rtree_page *page,
+			    const struct rtree_page_branch *br)
 {
 	page->n = 1;
 	page->b[0] = *br;
@@ -303,9 +302,9 @@ rtree_page_init_branch(struct rtree_page *page,
 
 /* Create new root page (root splitting) */
 static void
-rtree_page_init_page(struct rtree_page *page,
-		     struct rtree_page *page1,
-		     struct rtree_page *page2)
+rtree_page_init_with_pages(struct rtree_page *page,
+			   struct rtree_page *page1,
+			   struct rtree_page *page2)
 {
 	page->n = 2;
 	page->b[0].rect = rtree_page_cover(page1);
@@ -366,10 +365,10 @@ rtree_split_page(struct rtree *tree, struct rtree_page *page,
 
 	if (seed[0] == 0) {
 		group_rect[0] = br->rect;
-		rtree_page_init_branch(p, br);
+		rtree_page_init_with_branch(p, br);
 	} else {
 		group_rect[0] = page->b[seed[0] - 1].rect;
-		rtree_page_init_branch(p, &page->b[seed[0] - 1]);
+		rtree_page_init_with_branch(p, &page->b[seed[0] - 1]);
 		page->b[seed[0] - 1] = *br;
 	}
 	area_t group_area[2] = {rect_area[seed[0]], rect_area[seed[1]]};
@@ -788,7 +787,7 @@ rtree_insert(struct rtree *tree, struct rtree_rect *rect, record_t obj)
 {
 	if (tree->root == NULL) {
 		tree->root = rtree_alloc_page(tree);
-		rtree_page_init_record(tree->root, rect, obj);
+		rtree_page_init_with_record(tree->root, rect, obj);
 		tree->height = 1;
 		tree->n_pages++;
 	} else {
@@ -797,7 +796,7 @@ rtree_insert(struct rtree *tree, struct rtree_rect *rect, record_t obj)
 		if (p != NULL) {
 			/* root splitted */
 			struct rtree_page *new_root = rtree_alloc_page(tree);
-			rtree_page_init_page(new_root, tree->root, p);
+			rtree_page_init_with_pages(new_root, tree->root, p);
 			tree->root = new_root;
 			tree->height++;
 			tree->n_pages++;
@@ -830,7 +829,8 @@ rtree_remove(struct rtree *tree, const struct rtree_rect *rect, record_t obj)
 				/* root splitted */
 				struct rtree_page *new_root
 					= rtree_alloc_page(tree);
-				rtree_page_init_page(new_root, tree->root, p);
+				rtree_page_init_with_pages(new_root,
+							   tree->root, p);
 				tree->root = new_root;
 				tree->height++;
 				tree->n_pages++;
diff --git a/src/lib/salad/rtree.h b/src/lib/salad/rtree.h
index 6eb8a3eb1fc8262afc5cd2d2baa1e35c9fb95649..f3e62085009023b2ee4aeb4af23375898295baf8 100644
--- a/src/lib/salad/rtree.h
+++ b/src/lib/salad/rtree.h
@@ -60,15 +60,30 @@ enum {
 	RTREE_PAGE_SIZE = 1024
 };
 
+/**
+ * Rtree search operations. Used for searching and iterations.
+ * All operations except SOP_ALL reqires a rectangle to be set,
+ * and treat it in different ways
+ */
 enum spatial_search_op
 {
+	/* Find and itearate all records */
 	SOP_ALL,
+	/* Find and itearate records with the same rectangle */
 	SOP_EQUALS,
+	/* Find and itearate records that contain given rectangle */
 	SOP_CONTAINS,
+	/* Find and itearate records that strictly contain given rectangle */
 	SOP_STRICT_CONTAINS,
+	/* Find and itearate records that overlaps with given rectangle */
 	SOP_OVERLAPS,
+	/* Find and itearate records that belongs to given rectangle */
 	SOP_BELONGS,
+	/* Find and itearate records that strictly belongs to given rectangle */
 	SOP_STRICT_BELONGS,
+	/* Find and itearate nearest records from a given point (the point is
+	 * acluattly lowest_point of given rectangle). Records are iterated in
+	 * order of distance to given point. Yes, it is KNN iterator */
 	SOP_NEIGHBOR
 };
 
@@ -143,63 +158,147 @@ struct rtree_iterator
 	/* Position of ready-to-use list entry in allocated page */
 	int page_pos;
 
+	/* Comparators for comparison rectagnle of the iterator with
+	 * rectangles of tree nodes. If the comparator returns true,
+	 * the node is accepted; if false - skipped.
+	 */
+	/* Comparator for interanal (not leaf) nodes of the tree */
 	rtree_comparator_t intr_cmp;
+	/* Comparator for leaf nodes of the tree */
 	rtree_comparator_t leaf_cmp;
 
+	/* Current path of search in tree */
 	struct {
 		struct rtree_page *page;
 		int pos;
 	} stack[RTREE_MAX_HEIGHT];
 };
 
+/**
+ * @brief Rectangle normalization. Makes lower_point member to be vertex
+ * with minimal coordinates, and upper_point - with maximal coordinates.
+ * Useful when the rectangle is initialized with two diagonal vertexes that
+ * could be not lowest and highest correspondingly.
+ * @param rect - pointer to a rectangle
+ */
 void
 rtree_rect_normalize(struct rtree_rect *rect);
 
+/**
+ * @brief Set up 2D rectangle by 4 coordinates
+ * @param rect - pointer to a rectangle
+ * @params left, bottom, right, top - corresponding coordinates
+ */
 void
 rtree_set2d(struct rtree_rect *rect,
 	    coord_t left, coord_t bottom, coord_t right, coord_t top);
 
+/**
+ * @brief Initialize a tree
+ * @param tree - pointer to a tree
+ * @param page_alloc - page allocation function
+ * @param page_free - page deallocation function
+ */
 void
-rtree_init(struct rtree *tree, rtree_page_alloc_t page_alloc, rtree_page_free_t page_free);
+rtree_init(struct rtree *tree,
+	   rtree_page_alloc_t page_alloc, rtree_page_free_t page_free);
 
+/**
+ * @brief Destroy a tree
+ * @param tree - pointer to a tree
+ */
 void
 rtree_destroy(struct rtree *tree);
 
+/**
+ * @brief Delete all data from a tree, i.e. make it empty
+ * @param tree - pointer to a tree
+ */
 void
 rtree_purge(struct rtree *tree);
 
+/**
+ * @brief Find a record in a tree
+ * @return true if at least one record found (false otherwise)
+ * @param tree - pointer to a tree
+ * @param rect - rectangle to find (the meaning depends on op argument)
+ * @param op - type of search, see enum spatial_search_op for details
+ * @param itr - pointer to iterator (must be initialized earlier),
+ *  iterator itr should be used for accessing found record
+ */
 bool
 rtree_search(const struct rtree *tree, const struct rtree_rect *rect,
 	     enum spatial_search_op op, struct rtree_iterator *itr);
 
+/**
+ * @brief Insert a record to the tree
+ * @param tree - pointer to a tree
+ * @param rect - rectangle to insert
+ * @param obj - record to insert
+ */
 void
 rtree_insert(struct rtree *tree, struct rtree_rect *rect, record_t obj);
 
+/**
+ * @brief Remove the record from a tree
+ * @return true if the record deleted (false otherwise)
+ * @param tree - pointer to a tree
+ * @param rect - rectangle of the record to delete
+ * @param obj - record to delete
+ */
 bool
 rtree_remove(struct rtree *tree, const struct rtree_rect *rect, record_t obj);
 
+/**
+ * @brief Size of memory used by tree
+ * @param tree - pointer to a tree
+ **/
 size_t
 rtree_used_size(const struct rtree *tree);
 
+/**
+ * @brief Number of records in the tree
+ * @param tree - pointer to a tree
+ **/
 unsigned
 rtree_number_of_records(const struct rtree *tree);
 
 #if 0
+/**
+ * @brief Print a tree to stdout. Debug function, thus disabled.
+ * Needs <stdio.h> to be included before
+ * @param tree - pointer to a tree
+ **/
 void
 rtree_debug_print(const struct rtree *tree);
 #endif
 
+/**
+ * @brief Initialize an iterator for rtree
+ * Every iterator must be initialized before any usage
+ * @param itr - pointer to a iterator
+ **/
 void
 rtree_iterator_init(struct rtree_iterator *itr);
 
+/**
+ * @brief Destroy an iterator
+ * Every iterator must be destroyed
+ * @param itr - pointer to a iterator
+ **/
 void
 rtree_iterator_destroy(struct rtree_iterator *itr);
 
+/**
+ * @brief Retrieve a record from the iterator and iterate it to the next record
+ * @return a record or NULL if no more records
+ * @param itr - pointer to a iterator
+ **/
 record_t
 rtree_iterator_next(struct rtree_iterator *itr);
 
 #if defined(__cplusplus)
-}
+} /* extern "C" { */
 #endif /* defined(__cplusplus) */
 
 #endif /* #ifndef INCLUDES_TARANTOOL_SALAD_RTREE_H */
diff --git a/test/box/rtree_misc.result b/test/box/rtree_misc.result
new file mode 100644
index 0000000000000000000000000000000000000000..9e073f9cedbb7fa6a2286157a1e1d7b96bc74d8e
--- /dev/null
+++ b/test/box/rtree_misc.result
@@ -0,0 +1,288 @@
+s = box.schema.create_space('spatial')
+---
+...
+-- rtree index as primary key must be forbidden (unique)
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {1, 'array'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: RTREE index can not be unique'
+...
+-- any non-unique index as primary key must be forbidden
+i = s:create_index('spatial', { type = 'hash', unique = false, parts = {1, 'num'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: primary key must be unique'
+...
+i = s:create_index('spatial', { type = 'tree', unique = false, parts = {1, 'num'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: primary key must be unique'
+...
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {1, 'array'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: primary key must be unique'
+...
+-- tree and hash indexes over array field is not possible
+i = s:create_index('primary', { type = 'tree', parts = {1, 'array'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: ARRAY field type is not supported'
+...
+i = s:create_index('primary', { type = 'hash', parts = {1, 'array'}})
+---
+- error: 'Can''t create or modify index 0 in space 512: ARRAY field type is not supported'
+...
+-- normal indexes
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+---
+...
+i = s:create_index('secondary', { type = 'hash', parts = {2, 'num'}})
+---
+...
+-- adding a tuple with array instead of num will fail
+i = s:insert{{1, 2, 3}, 4}
+---
+- error: 'Tuple field 0 type does not match one required by operation: expected NUM'
+...
+i = s:insert{1, {2, 3, 4}}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected NUM'
+...
+-- rtree index must be one-part
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {1, 'array', 2, 'array'}})
+---
+- error: 'Can''t create or modify index 2 in space 512: RTREE index key can not be
+    multipart'
+...
+-- unique rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+---
+- error: 'Can''t create or modify index 2 in space 512: RTREE index can not be unique'
+...
+-- num rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'num'}})
+---
+- error: 'Can''t create or modify index 2 in space 512: RTREE index field type must
+    be ARRAY'
+...
+-- str rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'str'}})
+---
+- error: 'Can''t create or modify index 2 in space 512: RTREE index field type must
+    be ARRAY'
+...
+-- normal rtree index
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+---
+...
+-- inserting wrong values (should fail)
+s:insert{1, 2, 3}
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY'
+...
+s:insert{1, 2, "3"}
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY'
+...
+s:insert{1, 2, nil, 3}
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected ARRAY'
+...
+s:insert{1, 2, {}}
+---
+- error: R-Tree index does not support Key should contain 2 (point) or 4 (rectangle)
+    coordinates
+...
+s:insert{1, 2, {"3", "4", "5", "6"}}
+---
+- error: 'Tuple field 0 type does not match one required by operation: expected NUM'
+...
+s:insert{1, 2, {nil, 4, 5, 6}}
+---
+- error: 'Tuple field 0 type does not match one required by operation: expected NUM'
+...
+s:insert{1, 2, {3, {4}, 5, 6}}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected NUM'
+...
+s:insert{1, 2, {3, 4, {}, 6}}
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected NUM'
+...
+s:insert{1, 2, {3, 4, 5, "6"}}
+---
+- error: 'Tuple field 3 type does not match one required by operation: expected NUM'
+...
+s:insert{1, 2, {3}}
+---
+- error: R-Tree index does not support Field should be array with size 2 (point) or
+    4 (rectangle)
+...
+s:insert{1, 2, {3, 4, 5}}
+---
+- error: R-Tree index does not support Key should contain 2 (point) or 4 (rectangle)
+    coordinates
+...
+-- inserting good value
+s:insert{1, 2, {3, 4, 5, 6}}
+---
+- [1, 2, [3, 4, 5, 6]]
+...
+-- invalid alters
+s.index.spatial:alter({unique = true})
+---
+- error: 'Can''t create or modify index 2 in space 512: RTREE index can not be unique'
+...
+s.index.spatial:alter({type = 'tree'})
+---
+- error: 'Can''t create or modify index 2 in space 512: ARRAY field type is not supported'
+...
+box.space[box.schema.SPACE_ID]:update({s.id}, {{"=", 4, 'sophia'}})
+---
+- error: 'Can''t modify space 512: can not change space engine'
+...
+-- chech that truncate works
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+---
+- - [1, 2, [3, 4, 5, 6]]
+...
+s:truncate()
+---
+...
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+---
+- []
+...
+-- inserting lots of equvalent records
+for i = 1,500 do s:insert{i, i, {3, 4, 5, 6}} end
+---
+...
+-- and some records for chaos
+for i = 1,10 do for j = 1,10 do s:insert{500+i+j*20, 500+i*20+j, {i, j, i, j}} end end
+---
+...
+s.index.spatial:count()
+---
+- 600
+...
+#s.index.spatial:select({3, 4, 5, 6})
+---
+- 500
+...
+for i = 1,500,2 do s:delete{i} end
+---
+...
+s.index.spatial:count()
+---
+- 350
+...
+#s.index.spatial:select({3, 4, 5, 6})
+---
+- 250
+...
+s.index.spatial:min()
+---
+- error: RTREE does not support min()
+...
+s.index.spatial:max()
+---
+- error: RTREE does not support max()
+...
+s:drop()
+---
+...
+s = box.schema.create_space('sophia', {engine = 'sophia'})
+---
+...
+-- rtree indexes are not enabled in sophia
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+---
+- error: Unsupported index type supplied for index 0 in space 512
+...
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+---
+...
+-- ... even secondary
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+---
+- error: Unsupported index type supplied for index 1 in space 512
+...
+s:drop()
+---
+...
+-- rtree in temp space must work fine
+s = box.schema.create_space('spatial', {temporary = true})
+---
+...
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+---
+...
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+---
+...
+s:insert{1, 2, {3, 4, 5, 6}}
+---
+- [1, 2, [3, 4, 5, 6]]
+...
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+---
+- - [1, 2, [3, 4, 5, 6]]
+...
+s:drop()
+---
+...
+-- snapshot test
+s = box.schema.create_space('spatial')
+---
+...
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+---
+...
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+---
+...
+for i = 1,10 do s:insert{i, i, {i, i, i + 1, i + 1}} end
+---
+...
+box.snapshot()
+---
+- ok
+...
+for i = 11,20 do s:insert{i, i, i + 1, i + 1}
+---
+- error: '[string "for i = 11,20 do s:insert{i, i, i + 1, i + 1} "]:1: ''end'' expected
+    near ''<eof>'''
+...
+i:select({0, 0}, {iterator = 'neighbor'})
+---
+- - [1, 1, [1, 1, 2, 2]]
+  - [2, 2, [2, 2, 3, 3]]
+  - [3, 3, [3, 3, 4, 4]]
+  - [4, 4, [4, 4, 5, 5]]
+  - [5, 5, [5, 5, 6, 6]]
+  - [6, 6, [6, 6, 7, 7]]
+  - [7, 7, [7, 7, 8, 8]]
+  - [8, 8, [8, 8, 9, 9]]
+  - [9, 9, [9, 9, 10, 10]]
+  - [10, 10, [10, 10, 11, 11]]
+...
+--# stop server default
+--# start server default
+s = box.space.spatial
+---
+...
+i = s.index.spatial
+---
+...
+i:select({0, 0}, {iterator = 'neighbor'})
+---
+- - [1, 1, [1, 1, 2, 2]]
+  - [2, 2, [2, 2, 3, 3]]
+  - [3, 3, [3, 3, 4, 4]]
+  - [4, 4, [4, 4, 5, 5]]
+  - [5, 5, [5, 5, 6, 6]]
+  - [6, 6, [6, 6, 7, 7]]
+  - [7, 7, [7, 7, 8, 8]]
+  - [8, 8, [8, 8, 9, 9]]
+  - [9, 9, [9, 9, 10, 10]]
+  - [10, 10, [10, 10, 11, 11]]
+...
+s:drop()
+---
+...
diff --git a/test/box/rtree_misc.test.lua b/test/box/rtree_misc.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fa2680025a1e6377e2f41bb92e5b5dbf7d4b5f17
--- /dev/null
+++ b/test/box/rtree_misc.test.lua
@@ -0,0 +1,110 @@
+s = box.schema.create_space('spatial')
+
+-- rtree index as primary key must be forbidden (unique)
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {1, 'array'}})
+
+-- any non-unique index as primary key must be forbidden
+i = s:create_index('spatial', { type = 'hash', unique = false, parts = {1, 'num'}})
+i = s:create_index('spatial', { type = 'tree', unique = false, parts = {1, 'num'}})
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {1, 'array'}})
+
+-- tree and hash indexes over array field is not possible
+i = s:create_index('primary', { type = 'tree', parts = {1, 'array'}})
+i = s:create_index('primary', { type = 'hash', parts = {1, 'array'}})
+
+-- normal indexes
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+i = s:create_index('secondary', { type = 'hash', parts = {2, 'num'}})
+
+-- adding a tuple with array instead of num will fail
+i = s:insert{{1, 2, 3}, 4}
+i = s:insert{1, {2, 3, 4}}
+
+-- rtree index must be one-part
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {1, 'array', 2, 'array'}})
+
+-- unique rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+
+-- num rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'num'}})
+
+-- str rtree index is not possible
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'str'}})
+
+
+-- normal rtree index
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+
+-- inserting wrong values (should fail)
+s:insert{1, 2, 3}
+s:insert{1, 2, "3"}
+s:insert{1, 2, nil, 3}
+s:insert{1, 2, {}}
+s:insert{1, 2, {"3", "4", "5", "6"}}
+s:insert{1, 2, {nil, 4, 5, 6}}
+s:insert{1, 2, {3, {4}, 5, 6}}
+s:insert{1, 2, {3, 4, {}, 6}}
+s:insert{1, 2, {3, 4, 5, "6"}}
+s:insert{1, 2, {3}}
+s:insert{1, 2, {3, 4, 5}}
+
+-- inserting good value
+s:insert{1, 2, {3, 4, 5, 6}}
+
+-- invalid alters
+s.index.spatial:alter({unique = true})
+s.index.spatial:alter({type = 'tree'})
+box.space[box.schema.SPACE_ID]:update({s.id}, {{"=", 4, 'sophia'}})
+
+-- chech that truncate works
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+s:truncate()
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+
+-- inserting lots of equvalent records
+for i = 1,500 do s:insert{i, i, {3, 4, 5, 6}} end
+-- and some records for chaos
+for i = 1,10 do for j = 1,10 do s:insert{500+i+j*20, 500+i*20+j, {i, j, i, j}} end end
+s.index.spatial:count()
+#s.index.spatial:select({3, 4, 5, 6})
+for i = 1,500,2 do s:delete{i} end
+s.index.spatial:count()
+#s.index.spatial:select({3, 4, 5, 6})
+
+s.index.spatial:min()
+s.index.spatial:max()
+
+s:drop()
+
+s = box.schema.create_space('sophia', {engine = 'sophia'})
+-- rtree indexes are not enabled in sophia
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+-- ... even secondary
+i = s:create_index('spatial', { type = 'rtree', unique = true, parts = {3, 'array'}})
+s:drop()
+
+-- rtree in temp space must work fine
+s = box.schema.create_space('spatial', {temporary = true})
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+s:insert{1, 2, {3, 4, 5, 6}}
+s.index.spatial:select({0, 0, 10, 10}, {iterator = 'le'})
+s:drop()
+
+-- snapshot test
+s = box.schema.create_space('spatial')
+i = s:create_index('primary', { type = 'tree', parts = {1, 'num'}})
+i = s:create_index('spatial', { type = 'rtree', unique = false, parts = {3, 'array'}})
+for i = 1,10 do s:insert{i, i, {i, i, i + 1, i + 1}} end
+box.snapshot()
+for i = 11,20 do s:insert{i, i, i + 1, i + 1}
+i:select({0, 0}, {iterator = 'neighbor'})
+--# stop server default
+--# start server default
+s = box.space.spatial
+i = s.index.spatial
+i:select({0, 0}, {iterator = 'neighbor'})
+s:drop()
+
diff --git a/test/box/session.storage.result b/test/box/session.storage.result
index a292e1b2f287f2e476444ae66b9637ac7f928e8b..9893da2cc197e34bbbfd7b97e9461880e89f6071 100644
--- a/test/box/session.storage.result
+++ b/test/box/session.storage.result
@@ -31,7 +31,7 @@ all = getmetatable(session).aggregate_storage
 ...
 dump(all)
 ---
-- '''[null,null,{"abc":"cde"}]'''
+- '''[null,{"abc":"cde"}]'''
 ...
 --# create connection second to default
 --# set connection second