* [tarantool-patches] [PATCH 5/5] Methods for ephemeral space and its index
2018-07-12 11:16 [tarantool-patches] [PATCH 0/5] Expose ephemeral spaces into Lua imeevma
` (3 preceding siblings ...)
2018-07-12 11:16 ` [tarantool-patches] [PATCH 4/5] Primary index for ephemeral spaces imeevma
@ 2018-07-12 11:16 ` imeevma
2018-07-13 16:32 ` [tarantool-patches] " Vladislav Shpilevoy
2018-07-12 11:30 ` [tarantool-patches] Re: [PATCH 0/5] Expose ephemeral spaces into Lua Imeev Mergen
5 siblings, 1 reply; 12+ messages in thread
From: imeevma @ 2018-07-12 11:16 UTC (permalink / raw)
To: tarantool-patches
This patch defines most methods for index of
ephemeral space and ephemeral space.
Closes #3375.
---
src/box/box.cc | 62 +
src/box/box.h | 9 +
src/box/index.cc | 172 +
src/box/index.h | 140 +
src/box/lua/info.h | 4 -
src/box/lua/schema.lua | 122 +
src/box/lua/space.cc | 396 +-
test/box/ephemeral_space.result | 7979 +++++++++++++++++++++++++++++++++++++
test/box/ephemeral_space.test.lua | 1694 ++++++++
9 files changed, 10573 insertions(+), 5 deletions(-)
diff --git a/src/box/box.cc b/src/box/box.cc
index 795e3ee..e825735 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1171,6 +1171,68 @@ box_upsert(uint32_t space_id, uint32_t index_id, const char *tuple,
}
int
+box_ephemeral_select(struct space *space, uint32_t index_id,
+ int iterator, uint32_t offset, uint32_t limit,
+ const char *key, const char *key_end,
+ struct port *port)
+{
+ (void)key_end;
+
+ rmean_collect(rmean_box, IPROTO_SELECT, 1);
+
+ if (iterator < 0 || iterator >= iterator_type_MAX) {
+ diag_set(ClientError, ER_ILLEGAL_PARAMS,
+ "Invalid iterator type");
+ diag_log();
+ return -1;
+ }
+
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+
+ enum iterator_type type = (enum iterator_type) iterator;
+ uint32_t part_count = key ? mp_decode_array(&key) : 0;
+ if (key_validate(index->def, type, key, part_count))
+ return -1;
+
+ ERROR_INJECT(ERRINJ_TESTING, {
+ diag_set(ClientError, ER_INJECTION, "ERRINJ_TESTING");
+ return -1;
+ });
+
+ struct iterator *it = index_create_iterator(index, type,
+ key, part_count);
+ if (it == NULL)
+ return -1;
+
+ int rc = 0;
+ uint32_t found = 0;
+ struct tuple *tuple;
+ port_tuple_create(port);
+ while (found < limit) {
+ rc = iterator_next(it, &tuple);
+ if (rc != 0 || tuple == NULL)
+ break;
+ if (offset > 0) {
+ offset--;
+ continue;
+ }
+ rc = port_tuple_add(port, tuple);
+ if (rc != 0)
+ break;
+ found++;
+ }
+ iterator_delete(it);
+
+ if (rc != 0) {
+ port_destroy(port);
+ return -1;
+ }
+ return 0;
+}
+
+int
box_ephemeral_insert(struct space *space, const char *tuple,
const char *tuple_end, box_tuple_t **result)
{
diff --git a/src/box/box.h b/src/box/box.h
index a00a842..30f447b 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -402,6 +402,15 @@ int
box_process1(struct request *request, box_tuple_t **result);
/**
+ * Select all tuples from ephemeral space.
+ */
+int
+box_ephemeral_select(struct space *space, uint32_t index_id,
+ int iterator, uint32_t offset, uint32_t limit,
+ const char *key, const char *key_end,
+ struct port *port);
+
+/**
* Used to prepare request for inserting tuple into
* ephemeral space and call box_process_rw().
*/
diff --git a/src/box/index.cc b/src/box/index.cc
index 188995e..d2d209f 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -354,6 +354,131 @@ box_index_count(uint32_t space_id, uint32_t index_id, int type,
return count;
}
+ssize_t
+box_ephemeral_index_len(struct space *space, uint32_t index_id)
+{
+ struct index *index = space_index(space, index_id);
+ if (index == NULL)
+ return 0;
+ return index_size(index);
+}
+
+ssize_t
+box_ephemeral_index_bsize(struct space *space, uint32_t index_id)
+{
+ struct index *index = space_index(space, index_id);
+ if (index == NULL)
+ return 0;
+ return index_bsize(index);
+}
+
+int
+box_ephemeral_index_random(struct space *space, uint32_t index_id,
+ uint32_t rnd, box_tuple_t **result)
+{
+ assert(result != NULL);
+ struct index *index = index_find(space, index_id);
+ if (index == NULL || index_random(index, rnd, result) != 0)
+ return -1;
+ if (*result != NULL)
+ tuple_bless(*result);
+ return 0;
+}
+
+int
+box_ephemeral_index_get(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result)
+{
+ assert(key != NULL && key_end != NULL && result != NULL);
+ mp_tuple_assert(key, key_end);
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+ if (!index->def->opts.is_unique) {
+ diag_set(ClientError, ER_MORE_THAN_ONE_TUPLE);
+ return -1;
+ }
+ uint32_t part_count = mp_decode_array(&key);
+ if (exact_key_validate(index->def->key_def, key, part_count))
+ return -1;
+ if (index_get(index, key, part_count, result) != 0)
+ return -1;
+ rmean_collect(rmean_box, IPROTO_SELECT, 1);
+ if (*result != NULL)
+ tuple_bless(*result);
+ return 0;
+}
+
+int
+box_ephemeral_index_min(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result)
+{
+ assert(key != NULL && key_end != NULL && result != NULL);
+ mp_tuple_assert(key, key_end);
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+ if (index->def->type != TREE) {
+ diag_set(UnsupportedIndexFeature, index->def, "min()");
+ return -1;
+ }
+ uint32_t part_count = mp_decode_array(&key);
+ if (key_validate(index->def, ITER_GE, key, part_count))
+ return -1;
+ if (index_min(index, key, part_count, result) != 0)
+ return -1;
+ if (*result != NULL)
+ tuple_bless(*result);
+ return 0;
+}
+
+int
+box_ephemeral_index_max(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result)
+{
+ mp_tuple_assert(key, key_end);
+ assert(result != NULL);
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+ if (index->def->type != TREE) {
+ diag_set(UnsupportedIndexFeature, index->def, "max()");
+ return -1;
+ }
+ uint32_t part_count = mp_decode_array(&key);
+ if (key_validate(index->def, ITER_LE, key, part_count))
+ return -1;
+ if (index_max(index, key, part_count, result) != 0)
+ return -1;
+ if (*result != NULL)
+ tuple_bless(*result);
+ return 0;
+}
+
+ssize_t
+box_ephemeral_index_count(struct space *space, uint32_t index_id, int type,
+ const char *key, const char *key_end)
+{
+ assert(key != NULL && key_end != NULL);
+ mp_tuple_assert(key, key_end);
+ if (type < 0 || type >= iterator_type_MAX) {
+ diag_set(ClientError, ER_ILLEGAL_PARAMS,
+ "Invalid iterator type");
+ return -1;
+ }
+ enum iterator_type itype = (enum iterator_type) type;
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+ uint32_t part_count = mp_decode_array(&key);
+ if (key_validate(index->def, itype, key, part_count))
+ return -1;
+ ssize_t count = index_count(index, itype, key, part_count);
+ if (count < 0)
+ return -1;
+ return count;
+}
+
/* }}} */
/* {{{ Iterators ************************************************/
@@ -408,6 +533,32 @@ box_iterator_free(box_iterator_t *it)
iterator_delete(it);
}
+box_iterator_t *
+box_ephemeral_index_iterator(struct space *space, uint32_t index_id, int type,
+ const char *key, const char *key_end)
+{
+ assert(key != NULL && key_end != NULL);
+ mp_tuple_assert(key, key_end);
+ if (type < 0 || type >= iterator_type_MAX) {
+ diag_set(ClientError, ER_ILLEGAL_PARAMS,
+ "Invalid iterator type");
+ return NULL;
+ }
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return NULL;
+ enum iterator_type itype = (enum iterator_type) type;
+ assert(mp_typeof(*key) == MP_ARRAY); /* checked by Lua */
+ uint32_t part_count = mp_decode_array(&key);
+ if (key_validate(index->def, itype, key, part_count))
+ return NULL;
+ struct iterator *it = index_create_iterator(index, itype,
+ key, part_count);
+ if (it == NULL)
+ return NULL;
+ return it;
+}
+
/* }}} */
/* {{{ Other index functions */
@@ -435,6 +586,27 @@ box_index_compact(uint32_t space_id, uint32_t index_id)
return 0;
}
+int
+box_ephemeral_index_stat(struct space *space, uint32_t index_id,
+ struct info_handler *info)
+{
+ struct index *index = index_find(space, index_id);
+ if(index == NULL)
+ return -1;
+ index_stat(index, info);
+ return 0;
+}
+
+int
+box_ephemeral_index_compact(struct space *space, uint32_t index_id)
+{
+ struct index *index = index_find(space, index_id);
+ if(index == NULL)
+ return -1;
+ index_compact(index);
+ return 0;
+}
+
/* }}} */
/* {{{ Internal API */
diff --git a/src/box/index.h b/src/box/index.h
index 686e7a1..ffcb9fc 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -235,6 +235,146 @@ box_index_stat(uint32_t space_id, uint32_t index_id,
int
box_index_compact(uint32_t space_id, uint32_t index_id);
+/**
+ * Return the number of element in the index.
+ * If space have no index it returns 0.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \retval >= 0.
+ */
+ssize_t
+box_ephemeral_index_len(struct space *space, uint32_t index_id);
+
+/**
+ * Return the number of bytes used in memory by the index.
+ * If space have no index it returns 0.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \retval >= 0.
+ */
+ssize_t
+box_ephemeral_index_bsize(struct space *space, uint32_t index_id);
+
+/**
+ * Return a random tuple from the index.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param rnd - random seed.
+ * \param[out] - result a tuple or NULL if index is empty.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_index_random(struct space *space, uint32_t index_id,
+ uint32_t rnd, box_tuple_t **result);
+
+/**
+ * Get a tuple from index by the key.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param key encoded key in MsgPack Array format.
+ * \param key_end - the end of encoded \a key.
+ * \param[out] result - a tuple or NULL if index is empty.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ * \pre key != NULL
+ */
+int
+box_ephemeral_index_get(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result);
+
+/**
+ * Return a first (minimal) tuple matched the provided key.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param key - encoded key in MsgPack Array format.
+ * \param key_end - the end of encoded \a key.
+ * \param[out] - result a tuple or NULL if index is empty.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_index_min(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result);
+
+/**
+ * Count the number of tuple matched the provided key.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param key - encoded key in MsgPack Array format.
+ * \param key_end - the end of encoded \a key.
+ * \param[out] - result a tuple or NULL if index is empty.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_index_max(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result);
+
+/**
+ * Return a last (maximal) tuple matched the provided key.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param key - encoded key in MsgPack Array format.
+ * \param key_end - the end of encoded \a key.
+ * \param[out] - result a tuple or NULL if index is empty.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+ssize_t
+box_ephemeral_index_count(struct space *space, uint32_t index_id, int type,
+ const char *key, const char *key_end);
+
+/**
+ * Allocate and initialize iterator for ephemeral space
+ *
+ * A returned iterator must be destroyed by box_iterator_free().
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ * \param type \link iterator_type iterator type \endlink
+ * \param key encoded key in MsgPack Array format ([part1, part2, ...]).
+ * \param key_end the end of encoded \a key
+ * \retval NULL on error (check box_error_last())
+ * \retval iterator otherwise
+ * \sa box_iterator_next()
+ * \sa box_iterator_free()
+ */
+box_iterator_t *
+box_ephemeral_index_iterator(struct space *space, uint32_t index_id, int type,
+ const char *key, const char *key_end);
+
+/**
+ * Index statistics.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \param info - info handler
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_index_stat(struct space *space, uint32_t index_id,
+ struct info_handler *info);
+
+/**
+ * Trigger index compaction.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_ephemeral_index_compact(struct space *space, uint32_t index_id);
+
struct iterator {
/**
* Iterate to the next tuple.
diff --git a/src/box/lua/info.h b/src/box/lua/info.h
index 78cd9e6..bf4c613 100644
--- a/src/box/lua/info.h
+++ b/src/box/lua/info.h
@@ -49,8 +49,4 @@ luaT_info_handler_create(struct info_handler *h, struct lua_State *L);
} /* extern "C" */
#endif /* defined(__cplusplus) */
-#if defined(__cplusplus)
-} /* extern "C" */
-#endif /* defined(__cplusplus) */
-
#endif /* INCLUDES_TARANTOOL_LUA_INFO_H */
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index 0fe109a..24e033e 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1689,6 +1689,70 @@ space_mt.frommap = box.internal.space.frommap
space_mt.__index = space_mt
-- Metatable for primary index of ephemeral space
+index_ephemeral_mt.len = function(index)
+ local ret = index_ephemeral_methods.len(index)
+ if ret == -1 then
+ box.error()
+ end
+ return tonumber(ret)
+end
+index_ephemeral_mt.bsize = function(index)
+ local ret = index_ephemeral_methods.bsize(index)
+ if ret == -1 then
+ box.error()
+ end
+ return tonumber(ret)
+end
+index_ephemeral_mt.__len = index_ephemeral_mt.len
+index_ephemeral_mt.min = function(index, key)
+ key = keify(key)
+ return index_ephemeral_methods.min(index, key);
+end
+index_ephemeral_mt.max = function(index, key)
+ key = keify(key)
+ return index_ephemeral_methods.max(index, key);
+end
+index_ephemeral_mt.random = function(index, rnd)
+ rnd = rnd or math.random()
+ return index_ephemeral_methods.random(index, rnd);
+end
+index_ephemeral_mt.pairs = function(index, key, opts)
+ key = keify(key)
+ local itype = check_iterator_type(opts, #key == 0);
+ local keymp = msgpack.encode(key)
+ local keybuf = ffi.string(keymp, #keymp)
+ local cdata = index_ephemeral_methods.iterator(index, itype, keymp);
+ return fun.wrap(iterator_gen_luac, keybuf,
+ ffi.gc(cdata, builtin.box_iterator_free))
+end
+index_ephemeral_mt.count = function(index, key, opts)
+ key = keify(key)
+ local itype = check_iterator_type(opts, #key == 0);
+ return index_ephemeral_methods.count(index, itype, key);
+end
+index_ephemeral_mt.select = function(index, key, opts)
+ local key = keify(key)
+ local iterator, offset, limit = check_select_opts(opts, #key == 0)
+ return index_ephemeral_methods.select(index, iterator, offset, limit, key)
+end
+index_ephemeral_mt.get = function(index, key)
+ key = keify(key)
+ return index_ephemeral_methods.get(index, key)
+end
+index_ephemeral_mt.update = function(index, key, ops)
+ key = keify(key)
+ return index_ephemeral_methods.update(index, key, ops)
+end
+index_ephemeral_mt.delete = function(index, key)
+ key = keify(key)
+ return index_ephemeral_methods.delete(index, key)
+end
+index_ephemeral_mt.stat = function(index)
+ return index_ephemeral_methods.stat(index)
+end
+index_ephemeral_mt.compact = function(index)
+ return index_ephemeral_methods.compact(index)
+end
index_ephemeral_mt.drop = index_ephemeral_drop
index_ephemeral_mt.__index = index_ephemeral_mt
@@ -1699,9 +1763,67 @@ end
space_ephemeral_mt.run_triggers = function(ephemeral_space, yesno)
builtin.space_run_triggers(ephemeral_space.space, yesno)
end
+space_ephemeral_mt.auto_increment = function(ephemeral_space, tuple)
+ local max_tuple = check_primary_index(ephemeral_space):max()
+ local max = 0
+ if max_tuple ~= nil then
+ max = max_tuple[1]
+ end
+ table.insert(tuple, 1, max + 1)
+ return ephemeral_space:insert(tuple)
+end
+space_ephemeral_mt.insert = function(ephemeral_space, tuple)
+ return space_ephemeral_methods.insert(ephemeral_space, tuple);
+end
+space_ephemeral_mt.replace = function(ephemeral_space, tuple)
+ return space_ephemeral_methods.replace(ephemeral_space, tuple);
+end
+space_ephemeral_mt.upsert = function(ephemeral_space, tuple_key, ops, deprecated)
+ if deprecated ~= nil then
+ local msg = "Error: extra argument in upsert call: "
+ msg = msg .. tostring(deprecated)
+ msg = msg .. ". Usage :upsert(tuple, operations)"
+ box.error(box.error.PROC_LUA, msg)
+ end
+ return space_ephemeral_methods.upsert(ephemeral_space, tuple_key, ops);
+end
+space_ephemeral_mt.bsize = function(ephemeral_space)
+ if ephemeral_space == nil or ephemeral_space.space == nil then
+ box.error(box.error.NO_SUCH_SPACE, "ephemeral")
+ end
+ return builtin.space_bsize(ephemeral_space.space)
+end
+
+space_ephemeral_mt.pairs = function(ephemeral_space, key, opts)
+ local pk = ephemeral_space.index[0]
+ if pk == nil then
+ -- empty space without indexes, return empty iterator
+ return fun.iter({})
+ end
+ return pk:pairs(key, opts)
+end
+space_ephemeral_mt.__pairs = space_ephemeral_mt.pairs -- Lua 5.2 compatibility
+space_ephemeral_mt.__ipairs = space_ephemeral_mt.pairs -- Lua 5.2 compatibility
+space_ephemeral_mt.truncate = function(ephemeral_space)
+ if ephemeral_space.index == nil or ephemeral_space.index[0] == nil then
+ return
+ end
+ local index = ephemeral_space.index[0]
+ local name = index.name
+ local options = index.options
+ index:drop()
+ ephemeral_space:create_index(name, options)
+end
space_ephemeral_mt.frommap = space_ephemeral_methods.frommap
space_ephemeral_mt.create_index = index_ephemeral_create
space_ephemeral_mt.drop = box.schema.space.drop_ephemeral
+space_ephemeral_mt.put = space_ephemeral_methods.replace
+space_ephemeral_mt.get = index_ephemeral_mt.get
+space_ephemeral_mt.select = index_ephemeral_mt.select
+space_ephemeral_mt.update = index_ephemeral_mt.update
+space_ephemeral_mt.delete = index_ephemeral_mt.delete
+space_ephemeral_mt.count = index_ephemeral_mt.count
+space_ephemeral_mt.len = index_ephemeral_mt.len
space_ephemeral_mt.__index = space_ephemeral_mt
box.schema.index_mt = base_index_mt
diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc
index 4374db9..81b9f3c 100644
--- a/src/box/lua/space.cc
+++ b/src/box/lua/space.cc
@@ -35,6 +35,8 @@
#include "lua/trigger.h"
#include "box/box.h"
#include "box/lua/misc.h" /* lbox_encode_tuple_on_gc() */
+#include "box/info.h"
+#include "box/lua/info.h"
extern "C" {
#include <lua.h>
@@ -51,8 +53,10 @@ extern "C" {
#include "box/sequence.h"
#include "box/coll_id_cache.h"
#include "box/replication.h" /* GROUP_LOCAL */
+#include "box/port.h"
static uint32_t CTID_STRUCT_SPACE_POINTER = 0;
+static uint32_t CTID_STRUCT_ITERATOR_REF = 0;
/**
* Trigger function for all spaces
@@ -704,6 +708,370 @@ lbox_index_drop_ephemeral(struct lua_State *L)
}
/**
+ * Insert tuple into ephemeral space.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple.
+ * @retval not nil - tuple inserted.
+ * @retval nil - error, A reason is returned in
+ * the second value.
+ */
+static int
+lbox_ephemeral_space_insert(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage space:insert(tuple)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t tuple_len;
+ const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_len);
+ struct tuple *result;
+ if (box_ephemeral_insert(space, tuple, tuple + tuple_len, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Replace tuple from ephemeral space.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - tuple to insert.
+ * @retval not nil - tuple replaced.
+ * @retval nil - error, A reason is returned in
+ * the second value.
+ */
+static int
+lbox_ephemeral_space_replace(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage space:replace(tuple)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t tuple_len;
+ const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_len);
+ struct tuple *result;
+ if (box_ephemeral_replace(space, tuple, tuple + tuple_len,
+ &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Insert or update tuple from ephemeral space.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key or tuple to insert.
+ * @param Lua tuple - operaions in case of update .
+ * @retval not nil - tuple upserted.
+ * @retval nil - error, A reason is returned in
+ * the second value.
+ */
+static int
+lbox_ephemeral_space_upsert(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_istable(L, 1) ||
+ (lua_type(L, 2) != LUA_TTABLE && luaT_istuple(L, 2) == NULL) ||
+ (lua_type(L, 3) != LUA_TTABLE && luaT_istuple(L, 3) == NULL))
+ return luaL_error(L, "Usage index:upsert(key, ops)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ size_t ops_len;
+ const char *ops = lbox_encode_tuple_on_gc(L, 3, &ops_len);
+ struct tuple *result;
+ if (box_ephemeral_upsert(space, 0, key, key + key_len,
+ ops, ops + ops_len, 1, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Return the number of element in the index.
+ *
+ * @param Lua ephemeral space.
+ * @retval number - number of element in the index.
+ */
+static int
+lbox_ephemeral_index_len(struct lua_State *L)
+{
+ if (lua_gettop(L) != 1)
+ return luaL_error(L, "Usage: index:len()");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ lua_pushnumber(L, box_ephemeral_index_len(space, 0));
+ return 1;
+}
+
+/**
+ * Return the number of bytes used in memory by the
+ * index.
+ *
+ * @param Lua ephemeral space.
+ * @retval number - number of bytes used in memory
+ * by the index.
+ */
+static int
+lbox_ephemeral_index_bsize(struct lua_State *L)
+{
+ if (lua_gettop(L) != 1)
+ return luaL_error(L, "Usage: index:bsize()");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ lua_pushnumber(L, box_ephemeral_index_bsize(space, 0));
+ return 1;
+}
+
+/**
+ * Return a random tuple from the index.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua number - seed.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_random(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:random(seed)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ uint32_t rnd = luaL_checknumber (L, 2);
+ struct tuple *result;
+ if (box_ephemeral_index_random(space, 0, rnd, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Return a tuple from the index by given key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_get(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:get(key)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ struct tuple *result;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ if (box_ephemeral_index_get(space, 0, key, key + key_len, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+static inline void
+lbox_port_to_table(lua_State *L, struct port *port_base)
+{
+ struct port_tuple *port = port_tuple(port_base);
+ lua_createtable(L, port->size, 0);
+ struct port_tuple_entry *entry = port->first;
+ for (int i = 0 ; i < port->size; i++) {
+ luaT_pushtuple(L, entry->tuple);
+ lua_rawseti(L, -2, i + 1);
+ entry = entry->next;
+ }
+}
+
+static int
+lbox_ephemeral_index_select(lua_State *L)
+{
+ if (lua_gettop(L) != 5 || !lua_istable(L, 1)) {
+ return luaL_error(L, "Usage index:select(iterator, offset, "
+ "limit, key)");
+ }
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ int iterator = luaL_checknumber(L, 2);
+ uint32_t offset = luaL_checknumber(L, 3);
+ uint32_t limit = luaL_checknumber(L, 4);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 5, &key_len);
+ struct port port;
+ if (box_ephemeral_select(space, 0, iterator, offset, limit,
+ key, key + key_len, &port) != 0) {
+ return luaT_error(L);
+ }
+ lbox_port_to_table(L, &port);
+ port_destroy(&port);
+ return 1; /* lua table with tuples */
+}
+
+static int
+lbox_ephemeral_index_iterator(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_istable(L, 1)) {
+ return luaL_error(L, "Usage index:iterator(type, key)");
+ }
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ int iterator = luaL_checknumber(L, 2);
+ size_t mpkey_len;
+ /* Key encoded by Lua */
+ const char *mpkey = lua_tolstring(L, 3, &mpkey_len);
+ struct iterator *it = box_ephemeral_index_iterator(space, 0, iterator,
+ mpkey,
+ mpkey + mpkey_len);
+ if (it == NULL)
+ return luaT_error(L);
+
+ assert(CTID_STRUCT_ITERATOR_REF != 0);
+ struct iterator **ptr = (struct iterator **) luaL_pushcdata(L,
+ CTID_STRUCT_ITERATOR_REF);
+ *ptr = it; /* NULL handled by Lua, gc also set by Lua */
+ return 1;
+}
+
+/**
+ * Return a first (minimal) tuple from the index
+ * matched provided key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_min(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:min(key)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ struct tuple *result;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ if (box_ephemeral_index_min(space, 0, key, key + key_len, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Return a last (maximal) tuple from the index
+ * matched provided key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_max(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:max(key)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ struct tuple *result;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ if (box_ephemeral_index_max(space, 0, key, key + key_len, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Count the number of tuple matched the provided key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua number - iterator type.
+ * @param Lua tuple - key.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_count(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:count(type, key)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ uint32_t type = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+ ssize_t count = box_ephemeral_index_count(space, 0, type, key,
+ key + key_len);
+ if (count < 0)
+ return luaT_error(L);
+ lua_pushnumber(L, count);
+ return 1;
+}
+
+/**
+ * Index statistics.
+ *
+ * @param Lua ephemeral space.
+ * @retval info handler.
+ */
+static int
+lbox_ephemeral_index_stat(lua_State *L)
+{
+ if (lua_gettop(L) != 1 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:stat()");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ struct info_handler info;
+ luaT_info_handler_create(&info, L);
+ if (box_ephemeral_index_stat(space, 0, &info) != 0)
+ return luaT_error(L);
+ return 1;
+}
+
+/**
+ * Run index compaction.
+ *
+ * @param Lua ephemeral space.
+ */
+static int
+lbox_ephemeral_index_compact(lua_State *L)
+{
+ if (lua_gettop(L) != 1 || !lua_istable(L, 1))
+ return luaL_error(L, "Usage index:compact()");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ if (box_ephemeral_index_compact(space, 0) != 0)
+ return luaT_error(L);
+ return 0;
+}
+
+/**
+ * Update tuple matched the provided key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key.
+ * @param Lua tuple - operaions in case of update .
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_update(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_istable(L, 1) ||
+ (lua_type(L, 2) != LUA_TTABLE && luaT_istuple(L, 2) == NULL) ||
+ (lua_type(L, 3) != LUA_TTABLE && luaT_istuple(L, 3) == NULL))
+ return luaL_error(L, "Usage index:update(key, ops)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ size_t ops_len;
+ const char *ops = lbox_encode_tuple_on_gc(L, 3, &ops_len);
+ struct tuple *result;
+ if (box_ephemeral_update(space, 0, key, key + key_len,
+ ops, ops + ops_len, 1, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Delete tuple matched the provided key.
+ *
+ * @param Lua ephemeral space.
+ * @param Lua tuple - key.
+ * @retval tuple or nil.
+ */
+static int
+lbox_ephemeral_index_delete(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_istable(L, 1) ||
+ (lua_type(L, 2) != LUA_TTABLE && luaT_istuple(L, 2) == NULL))
+ return luaL_error(L, "Usage index:delete(key)");
+ struct space *space = (struct space *)lua_checkephemeralspace(L, 1);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 2, &key_len);
+ struct tuple *result;
+ if (box_ephemeral_delete(space, 0, key, key + key_len, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
* Make a tuple or a table Lua object by map.
* @param Lua space object.
* @param Lua map table object.
@@ -771,9 +1139,13 @@ box_lua_space_init(struct lua_State *L)
int rc = luaL_cdef(L, "struct space;");
assert(rc == 0);
- (void) rc;
CTID_STRUCT_SPACE_POINTER = luaL_ctypeid(L, "struct space *");
assert(CTID_STRUCT_SPACE_POINTER != 0);
+ rc = luaL_cdef(L, "struct iterator;");
+ assert(rc == 0);
+ CTID_STRUCT_ITERATOR_REF = luaL_ctypeid(L, "struct iterator&");
+ assert(CTID_STRUCT_ITERATOR_REF != 0);
+ (void) rc;
lua_getfield(L, LUA_GLOBALSINDEX, "box");
lua_newtable(L);
@@ -873,9 +1245,31 @@ box_lua_space_init(struct lua_State *L)
lua_pop(L, 1);
static const struct luaL_Reg space_ephemeral_lib[] = {
{"frommap", lbox_space_frommap_ephemeral},
+ {"insert", lbox_ephemeral_space_insert},
+ {"replace", lbox_ephemeral_space_replace},
+ {"upsert", lbox_ephemeral_space_upsert},
{NULL, NULL}
};
luaL_register(L, "box.schema.space_ephemeral_methods",
space_ephemeral_lib);
lua_pop(L, 1);
+ static const struct luaL_Reg index_ephemeral_lib[] = {
+ {"len", lbox_ephemeral_index_len},
+ {"bsize", lbox_ephemeral_index_bsize},
+ {"random", lbox_ephemeral_index_random},
+ {"get", lbox_ephemeral_index_get},
+ {"min", lbox_ephemeral_index_min},
+ {"max", lbox_ephemeral_index_max},
+ {"count", lbox_ephemeral_index_count},
+ {"iterator", lbox_ephemeral_index_iterator},
+ {"stat", lbox_ephemeral_index_stat},
+ {"compact", lbox_ephemeral_index_compact},
+ {"update", lbox_ephemeral_index_update},
+ {"delete", lbox_ephemeral_index_delete},
+ {"select", lbox_ephemeral_index_select},
+ {NULL, NULL}
+ };
+ luaL_register(L, "box.schema.index_ephemeral_methods",
+ index_ephemeral_lib);
+ lua_pop(L, 1);
}
diff --git a/test/box/ephemeral_space.result b/test/box/ephemeral_space.result
index d958ffe..0f80fa4 100644
--- a/test/box/ephemeral_space.result
+++ b/test/box/ephemeral_space.result
@@ -1,3 +1,6 @@
+test_run = require('test_run').new()
+---
+...
-- Ephemeral space: creation and dropping.
-- Simple creation.
s = box.schema.space.create_ephemeral()
@@ -480,3 +483,7979 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {dummy = true})
s:drop()
---
...
+-- Ephemeral space: methods: insert
+s = box.schema.space.create_ephemeral({field_count = 3})
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1}
+---
+- error: Tuple field count 1 does not match space field count 3
+...
+s:insert{2,2}
+---
+- error: Tuple field count 2 does not match space field count 3
+...
+s:insert{3,3,3}
+---
+- [3, 3, 3]
+...
+s:insert{4,4,4,4}
+---
+- error: Tuple field count 4 does not match space field count 3
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:insert({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+s:insert({tostring(7)})
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:insert({key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1]
+ - [2]
+ - [3]
+ - [4]
+ - [5]
+ - [6]
+ - [7]
+ - [8]
+ - [9]
+ - [10]
+...
+s:insert({7})
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:insert({key, key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1]
+ - [2, 2]
+ - [3, 3]
+ - [4, 4]
+ - [5, 5]
+ - [6, 6]
+ - [7, 7]
+ - [8, 8]
+ - [9, 9]
+ - [10, 10]
+...
+s:insert({7, 7})
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:insert({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+s:insert(box.tuple.new{tostring(7)})
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+index = s:create_index('a')
+---
+...
+s:insert(1)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:insert(1, 2)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:insert(1, 2, 3)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:insert{1}
+---
+- [1]
+...
+s:insert{2, 3}
+---
+- [2, 3]
+...
+tmp = s:delete(1, 2, 3)
+---
+...
+s:select{}
+---
+- - [2, 3]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {3, 'unsigned'} })
+---
+...
+s:insert{1}
+---
+- error: Tuple field count 1 is less than required by space format or defined indexes
+ (expected at least 3)
+...
+s:insert{2, 3}
+---
+- error: Tuple field count 2 is less than required by space format or defined indexes
+ (expected at least 3)
+...
+s:insert{4, 5, 6}
+---
+- [4, 5, 6]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert{"1"}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+s:drop()
+---
+...
+-- Ephemeral space: methods: replace
+s = box.schema.space.create_ephemeral({field_count = 3})
+---
+...
+i = s:create_index('a')
+---
+...
+s:replace{1}
+---
+- error: Tuple field count 1 does not match space field count 3
+...
+s:replace{2, 2}
+---
+- error: Tuple field count 2 does not match space field count 3
+...
+s:replace{3, 3, 3}
+---
+- [3, 3, 3]
+...
+s:replace{4, 4, 4, 4}
+---
+- error: Tuple field count 4 does not match space field count 3
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:replace({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+_ = s:replace({tostring(7)})
+---
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:replace({key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1]
+ - [2]
+ - [3]
+ - [4]
+ - [5]
+ - [6]
+ - [7]
+ - [8]
+ - [9]
+ - [10]
+...
+_ = s:replace({7})
+---
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:replace({key, key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1]
+ - [2, 2]
+ - [3, 3]
+ - [4, 4]
+ - [5, 5]
+ - [6, 6]
+ - [7, 7]
+ - [8, 8]
+ - [9, 9]
+ - [10, 10]
+...
+s:replace({7, 7})
+---
+- [7, 7]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:replace({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+s:replace(box.tuple.new{tostring(7)})
+---
+- ['7']
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+index = s:create_index('a')
+---
+...
+s:replace(1)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:replace(1, 2)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:replace(1, 2, 3)
+---
+- error: Tuple/Key must be MsgPack array
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2, 3}
+---
+- [2, 3]
+...
+tmp = s:delete(1, 2, 3)
+---
+...
+s:select{}
+---
+- - [2, 3]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {3, 'unsigned'} })
+---
+...
+s:replace{1}
+---
+- error: Tuple field count 1 is less than required by space format or defined indexes
+ (expected at least 3)
+...
+s:replace{2, 3}
+---
+- error: Tuple field count 2 is less than required by space format or defined indexes
+ (expected at least 3)
+...
+s:replace{4, 5, 6}
+---
+- [4, 5, 6]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{"1"}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:replace{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+s:drop()
+---
+...
+-- Ephemeral space: methods: upsert
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:upsert({1, 0}, {{'+', 2, 1}})
+---
+...
+s:get{1}
+---
+- [1, 0]
+...
+s:upsert({1, 0}, {{'+', 2, 1}})
+---
+...
+s:get{1}
+---
+- [1, 1]
+...
+s:upsert({1, 0}, {{'+', 1, 1}})
+---
+...
+s:get{1}
+---
+- [1, 1]
+...
+s:get{2}
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 1}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1', 0]
+ - ['2', 0]
+ - ['3', 0]
+ - ['4', 0]
+ - ['5', 0]
+ - ['6', 0]
+ - ['7', 0]
+ - ['8', 0]
+ - ['9', 0]
+ - ['10', 0]
+...
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 10}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1', 10]
+ - ['2', 10]
+ - ['3', 10]
+ - ['4', 10]
+ - ['5', 10]
+ - ['6', 10]
+ - ['7', 10]
+ - ['8', 10]
+ - ['9', 10]
+ - ['10', 10]
+...
+for key = 1, 10 do s:delete({tostring(key)}) end
+---
+...
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 1}, {'=', 3, key}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1', 0]
+ - ['2', 0]
+ - ['3', 0]
+ - ['4', 0]
+ - ['5', 0]
+ - ['6', 0]
+ - ['7', 0]
+ - ['8', 0]
+ - ['9', 0]
+ - ['10', 0]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 1}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1, 0]
+ - [2, 0]
+ - [3, 0]
+ - [4, 0]
+ - [5, 0]
+ - [6, 0]
+ - [7, 0]
+ - [8, 0]
+ - [9, 0]
+ - [10, 0]
+...
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 10}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1, 10]
+ - [2, 10]
+ - [3, 10]
+ - [4, 10]
+ - [5, 10]
+ - [6, 10]
+ - [7, 10]
+ - [8, 10]
+ - [9, 10]
+ - [10, 10]
+...
+for key = 1, 10 do s:delete({key}) end
+---
+...
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 1}, {'=', 3, key}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1, 0]
+ - [2, 0]
+ - [3, 0]
+ - [4, 0]
+ - [5, 0]
+ - [6, 0]
+ - [7, 0]
+ - [8, 0]
+ - [9, 0]
+ - [10, 0]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 1}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 0]
+ - [2, 2, 0]
+ - [3, 3, 0]
+ - [4, 4, 0]
+ - [5, 5, 0]
+ - [6, 6, 0]
+ - [7, 7, 0]
+ - [8, 8, 0]
+ - [9, 9, 0]
+ - [10, 10, 0]
+...
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 10}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 10]
+ - [2, 2, 10]
+ - [3, 3, 10]
+ - [4, 4, 10]
+ - [5, 5, 10]
+ - [6, 6, 10]
+ - [7, 7, 10]
+ - [8, 8, 10]
+ - [9, 9, 10]
+ - [10, 10, 10]
+...
+for key = 1, 10 do s:delete({key, key}) end
+---
+...
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 1}, {'=', 4, key}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 0]
+ - [2, 2, 0]
+ - [3, 3, 0]
+ - [4, 4, 0]
+ - [5, 5, 0]
+ - [6, 6, 0]
+ - [7, 7, 0]
+ - [8, 8, 0]
+ - [9, 9, 0]
+ - [10, 10, 0]
+...
+s:drop()
+---
+...
+test_run:cmd("setopt delimiter ';'");
+---
+- true
+...
+function less(a, b)
+ if type(a[2]) ~= type(b[2]) then
+ return type(a[2]) < type(b[2])
+ end
+ if a[2] == b[2] then
+ return a[1] < b[1]
+ end
+ if type(a[2]) == 'boolean' then
+ return a[2] == false and b[2] == true
+ end
+ return a[2] < b[2]
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+function sort(t) table.sort(t, less) return t end
+---
+...
+-- upsert default tuple constraint
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+s:upsert({0, 'key', 0}, {{'+', 3, 1}})
+---
+- error: 'Tuple field 2 type does not match one required by operation: expected unsigned'
+...
+s:drop()
+---
+...
+-- upsert primary key modify (skipped)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:upsert({0, 0}, {{'+', 1, 1}, {'+', 2, 1}})
+---
+...
+s:get({0})
+---
+- [0, 0]
+...
+s:drop()
+---
+...
+-- upsert with box.tuple.new
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:upsert({0, 0}, {{'+', 1, 1}, {'+', 2, 1}})
+---
+...
+s:get({0})
+---
+- [0, 0]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 1}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 0]
+ - [2, 2, 0]
+ - [3, 3, 0]
+ - [4, 4, 0]
+ - [5, 5, 0]
+ - [6, 6, 0]
+ - [7, 7, 0]
+ - [8, 8, 0]
+ - [9, 9, 0]
+ - [10, 10, 0]
+...
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 10}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 10]
+ - [2, 2, 10]
+ - [3, 3, 10]
+ - [4, 4, 10]
+ - [5, 5, 10]
+ - [6, 6, 10]
+ - [7, 7, 10]
+ - [8, 8, 10]
+ - [9, 9, 10]
+ - [10, 10, 10]
+...
+for key = 1, 10 do s:delete({key, key}) end
+---
+...
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 1}, {'=', 4, key}}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1, 0]
+ - [2, 2, 0]
+ - [3, 3, 0]
+ - [4, 4, 0]
+ - [5, 5, 0]
+ - [6, 6, 0]
+ - [7, 7, 0]
+ - [8, 8, 0]
+ - [9, 9, 0]
+ - [10, 10, 0]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:upsert({0, 0}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0, 0]
+...
+tmp = s:delete{0}
+---
+...
+s:upsert({0, 0, 0}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0, 0, 0]
+...
+tmp = s:delete{0}
+---
+...
+s:upsert({0}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0]
+...
+s:replace{0, 1, 2, 4}
+---
+- [0, 1, 2, 4]
+...
+s:upsert({0, 0, "you will not see it"}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0, 3, 2, 4]
+...
+s:replace{0, -0x4000000000000000ll}
+---
+- [0, -4611686018427387904]
+...
+s:upsert({0}, {{'+', 2, -0x4000000000000001ll}}) -- overflow
+---
+...
+s:select{0}
+---
+- - [0, -4611686018427387904]
+...
+s:replace{0, "thing"}
+---
+- [0, 'thing']
+...
+s:upsert({0, "nothing"}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0, 'thing']
+...
+tmp = s:delete{0}
+---
+...
+s:upsert({0, "thing"}, {{'+', 2, 2}})
+---
+...
+s:select{0}
+---
+- - [0, 'thing']
+...
+s:replace{0, 1, 2}
+---
+- [0, 1, 2]
+...
+s:upsert({0}, {{'!', 42, 42}})
+---
+...
+s:select{0}
+---
+- - [0, 1, 2]
+...
+s:upsert({0}, {{'#', 42, 42}})
+---
+...
+s:select{0}
+---
+- - [0, 1, 2]
+...
+s:upsert({0}, {{'=', 42, 42}})
+---
+...
+s:select{}
+---
+- - [0, 1, 2]
+...
+s:replace{0, 1.5}
+---
+- [0, 1.5]
+...
+s:select{}
+---
+- - [0, 1.5]
+...
+s:upsert({0}, {{'|', 1, 255}})
+---
+...
+s:select{0}
+---
+- - [0, 1.5]
+...
+s:replace{0, 1.5}
+---
+- [0, 1.5]
+...
+s:replace{0, 'something to splice'}
+---
+- [0, 'something to splice']
+...
+s:upsert({0}, {{':', 2, 1, 4, 'no'}})
+---
+...
+s:select{0}
+---
+- - [0, 'nothing to splice']
+...
+s:upsert({0}, {{':', 2, 1, 2, 'every'}})
+---
+...
+s:select{0}
+---
+- - [0, 'everything to splice']
+...
+s:upsert({0}, {{':', 2, -100, 2, 'every'}})
+---
+...
+s:select{0}
+---
+- - [0, 'everything to splice']
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral({ field_count = 1 })
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert({1})
+---
+- [1]
+...
+s:select{}
+---
+- - [1]
+...
+s:upsert({2, 2}, {{'+', 2, 1}})
+---
+- error: Tuple field count 2 does not match space field count 1
+...
+s:select{}
+---
+- - [1]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral({ field_count = 2 })
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert({1, 1})
+---
+- [1, 1]
+...
+s:select{}
+---
+- - [1, 1]
+...
+s:upsert({2, 2, 2}, {{'+', 3, 1}})
+---
+- error: Tuple field count 3 does not match space field count 2
+...
+s:upsert({3, 3}, {{'+', 2, 1}})
+---
+...
+s:select{}
+---
+- - [1, 1]
+ - [3, 3]
+...
+s:drop()
+---
+...
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function anything_to_string(tab)
+ if tab == nil then
+ return 'nil'
+ end
+ local str = '['
+ local first_route = true
+ local t = 0
+ for k,f in pairs(tab) do
+ if not first_route then str = str .. ',' end
+ first_route = false
+ t = t + 1
+ if k ~= t then
+ str = str .. k .. '='
+ end
+ if type(f) == 'string' then
+ str = str .. "'" .. f .. "'"
+ elseif type (f) == 'number' then
+ str = str .. tostring(f)
+ elseif type (f) == 'table' or type (f) == 'cdata' then
+ str = str .. anything_to_string(f)
+ else
+ str = str .. '?'
+ end
+ end
+ str = str .. ']'
+ return str
+end;
+---
+...
+function things_equal(var1, var2)
+ local type1 = type(var1) == 'cdata' and 'table' or type(var1)
+ local type2 = type(var2) == 'cdata' and 'table' or type(var2)
+ if type1 ~= type2 then
+ return false
+ end
+ if type1 ~= 'table' then
+ return var1 == var2
+ end
+ for k,v in pairs(var1) do
+ if not things_equal(v, var2[k]) then
+ return false
+ end
+ end
+ for k,v in pairs(var2) do
+ if not things_equal(v, var1[k]) then
+ return false
+ end
+ end
+ return true
+end;
+---
+...
+function copy_thing(t)
+ if type(t) ~= 'table' then
+ return t
+ end
+ local res = {}
+ for k,v in pairs(t) do
+ res[copy_thing(k)] = copy_thing(v)
+ end
+ return res
+end;
+---
+...
+function test(space, key_tuple, ops, expect)
+ space:upsert(key_tuple, ops)
+ if (things_equal(space:select{}, expect)) then
+ return 'upsert('.. anything_to_string(key_tuple) .. ', ' ..
+ anything_to_string(ops) .. ', ' ..
+ ') OK ' .. anything_to_string(space:select{})
+ end
+ return 'upsert('.. anything_to_string(key_tuple) .. ', ' ..
+ anything_to_string(ops) .. ', ' ..
+ ') FAILED, got ' .. anything_to_string(space:select{}) ..
+ ' expected ' .. anything_to_string(expect)
+end;
+---
+...
+test_run:cmd("setopt delimiter ''");
+---
+- true
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:upsert({1}, {{'!', 2, 100}}) -- must fail on checking tuple
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+s:upsert({'a'}, {{'a', 2, 100}}) -- must fail on checking ops
+---
+- error: Unknown UPDATE operation
+...
+s:upsert({'a'}, {{'!', 2, 'ups1'}}) -- 'fast' upsert via insert in one index
+---
+...
+s:upsert({'a', 'b'}, {{'!', 2, 'ups2'}}) -- 'fast' upsert via update in one index
+---
+...
+s:select{}
+---
+- - ['a', 'ups2']
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert({1, 1, 1})
+---
+- [1, 1, 1]
+...
+s:insert({2, 2, 2})
+---
+- [2, 2, 2]
+...
+s:insert({3, 3, 3})
+---
+- [3, 3, 3]
+...
+s:select{}
+---
+- - [1, 1, 1]
+ - [2, 2, 2]
+ - [3, 3, 3]
+...
+s:upsert({2, 18, 76}, {})
+---
+...
+s:upsert({4, 4, 4}, {})
+---
+...
+s:select{}
+---
+- - [1, 1, 1]
+ - [2, 2, 2]
+ - [3, 3, 3]
+ - [4, 4, 4]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+t = {1, '1', 1, 'qwerty'}
+---
+...
+s:insert(t)
+---
+- [1, '1', 1, 'qwerty']
+...
+-- all good operations, one op, equivalent to update
+test(s, t, {{'+', 3, 5}}, {{1, '1', 6, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',3,5]], ) OK [[1,'1',6,'qwerty']]
+...
+test(s, t, {{'-', 3, 3}}, {{1, '1', 3, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['-',3,3]], ) OK [[1,'1',3,'qwerty']]
+...
+test(s, t, {{'&', 3, 5}}, {{1, '1', 1, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['&',3,5]], ) OK [[1,'1',1,'qwerty']]
+...
+test(s, t, {{'|', 3, 8}}, {{1, '1', 9, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['|',3,8]], ) OK [[1,'1',9,'qwerty']]
+...
+test(s, t, {{'^', 3, 12}}, {{1, '1', 5, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['^',3,12]], ) OK [[1,'1',5,'qwerty']]
+...
+test(s, t, {{':', 4, 2, 4, "uer"}}, {{1, '1', 5, 'query'}})
+---
+- upsert([1,'1',1,'qwerty'], [[':',4,2,4,'uer']], ) OK [[1,'1',5,'query']]
+...
+test(s, t, {{'!', 4, 'answer'}}, {{1, '1', 5, 'answer', 'query'}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',4,'answer']], ) OK [[1,'1',5,'answer','query']]
+...
+test(s, t, {{'#', 5, 1}}, {{1, '1', 5, 'answer'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',5,1]], ) OK [[1,'1',5,'answer']]
+...
+test(s, t, {{'!', -1, 1}}, {{1, '1', 5, 'answer', 1}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',-1,1]], ) OK [[1,'1',5,'answer',1]]
+...
+test(s, t, {{'!', -1, 2}}, {{1, '1', 5, 'answer', 1, 2}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',-1,2]], ) OK [[1,'1',5,'answer',1,2]]
+...
+test(s, t, {{'!', -1, 3}}, {{1, '1', 5, 'answer', 1, 2 ,3}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',-1,3]], ) OK [[1,'1',5,'answer',1,2,3]]
+...
+test(s, t, {{'#', 5, 100500}}, {{1, '1', 5, 'answer'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',5,100500]], ) OK [[1,'1',5,'answer']]
+...
+test(s, t, {{'=', 4, 'qwerty'}}, {{1, '1', 5, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['=',4,'qwerty']], ) OK [[1,'1',5,'qwerty']]
+...
+-- same check for negative posistion
+test(s, t, {{'+', -2, 5}}, {{1, '1', 10, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',-2,5]], ) OK [[1,'1',10,'qwerty']]
+...
+test(s, t, {{'-', -2, 3}}, {{1, '1', 7, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['-',-2,3]], ) OK [[1,'1',7,'qwerty']]
+...
+test(s, t, {{'&', -2, 5}}, {{1, '1', 5, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['&',-2,5]], ) OK [[1,'1',5,'qwerty']]
+...
+test(s, t, {{'|', -2, 8}}, {{1, '1', 13, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['|',-2,8]], ) OK [[1,'1',13,'qwerty']]
+...
+test(s, t, {{'^', -2, 12}}, {{1, '1', 1, 'qwerty'}})
+---
+- upsert([1,'1',1,'qwerty'], [['^',-2,12]], ) OK [[1,'1',1,'qwerty']]
+...
+test(s, t, {{':', -1, 2, 4, "uer"}}, {{1, '1', 1, 'query'}})
+---
+- upsert([1,'1',1,'qwerty'], [[':',-1,2,4,'uer']], ) OK [[1,'1',1,'query']]
+...
+test(s, t, {{'!', -2, 'answer'}}, {{1, '1', 1, 'answer', 'query'}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',-2,'answer']], ) OK [[1,'1',1,'answer','query']]
+...
+test(s, t, {{'#', -1, 1}}, {{1, '1', 1, 'answer'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',-1,1]], ) OK [[1,'1',1,'answer']]
+...
+test(s, t, {{'=', -1, 'answer!'}}, {{1, '1', 1, 'answer!'}})
+---
+- upsert([1,'1',1,'qwerty'], [['=',-1,'answer!']], ) OK [[1,'1',1,'answer!']]
+...
+-- selective test for good multiple ops
+test(s, t, {{'+', 3, 2}, {'!', 4, 42}}, {{1, '1', 3, 42, 'answer!'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',3,2],['!',4,42]], ) OK [[1,'1',3,42,'answer!']]
+...
+test(s, t, {{'!', 1, 666}, {'#', 1, 1}, {'+', 3, 2}}, {{1, '1', 5, 42, 'answer!'}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',1,666],['#',1,1],['+',3,2]], ) OK [[1,'1',5,42,'answer!']]
+...
+test(s, t, {{'!', 3, 43}, {'+', 4, 2}}, {{1, '1', 43, 7, 42, 'answer!'}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',3,43],['+',4,2]], ) OK [[1,'1',43,7,42,'answer!']]
+...
+test(s, t, {{'#', 3, 2}, {'=', 3, 1}, {'=', 4, '1'}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',3,2],['=',3,1],['=',4,'1']], ) OK [[1,'1',1,'1']]
+...
+-- all bad operations, one op, equivalent to update but error is supressed
+test(s, t, {{'+', 4, 3}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',4,3]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'-', 4, 3}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['-',4,3]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'&', 4, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['&',4,1]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'|', 4, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['|',4,1]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'^', 4, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['^',4,1]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{':', 3, 2, 4, "uer"}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [[':',3,2,4,'uer']], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'!', 18, 'answer'}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['!',18,'answer']], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'#', 18, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',18,1]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'=', 18, 'qwerty'}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['=',18,'qwerty']], ) OK [[1,'1',1,'1']]
+...
+-- selective test for good/bad multiple ops mix
+test(s, t, {{'+', 3, 1}, {'+', 4, 1}}, {{1, '1', 2, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',3,1],['+',4,1]], ) OK [[1,'1',2,'1']]
+...
+test(s, t, {{'-', 4, 1}, {'-', 3, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['-',4,1],['-',3,1]], ) OK [[1,'1',1,'1']]
+...
+test(s, t, {{'#', 18, 1}, {'|', 3, 14}, {'!', 18, '!'}}, {{1, '1', 15, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['#',18,1],['|',3,14],['!',18,'!']], ) OK [[1,'1',15,'1']]
+...
+test(s, t, {{'^', 42, 42}, {':', 1, 1, 1, ''}, {'^', 3, 8}}, {{1, '1', 7, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['^',42,42],[':',1,1,1,''],['^',3,8]], ) OK [[1,'1',7,'1']]
+...
+test(s, t, {{'&', 3, 1}, {'&', 2, 1}, {'&', 4, 1}}, {{1, '1', 1, '1'}})
+---
+- upsert([1,'1',1,'qwerty'], [['&',3,1],['&',2,1],['&',4,1]], ) OK [[1,'1',1,'1']]
+...
+-- broken ops must raise an exception and discarded
+'dump ' .. anything_to_string(s:select{})
+---
+- dump [[1,'1',1,'1']]
+...
+test(s, t, {{'&', 'a', 3}, {'+', 3, 3}}, {{1, '1', 1, '1'}})
+---
+- error: Illegal parameters, field id must be a number
+...
+test(s, t, {{'+', 3, 3}, {'&', 3, 'a'}}, {{1, '1', 1, '1'}})
+---
+- error: 'Argument type in operation ''&'' on field 3 does not match field type: expected
+ a positive integer'
+...
+test(s, t, {{'+', 3}, {'&', 3, 'a'}}, {{1, '1', 1, '1'}})
+---
+- error: Unknown UPDATE operation
+...
+test(s, t, {{':', 3, 3}}, {{1, '1', 1, '1'}})
+---
+- error: Unknown UPDATE operation
+...
+test(s, t, {{':', 3, 3, 3}}, {{1, '1', 1, '1'}})
+---
+- error: Unknown UPDATE operation
+...
+test(s, t, {{'?', 3, 3}}, {{1, '1', 1, '1'}})
+---
+- error: Unknown UPDATE operation
+...
+'dump ' .. anything_to_string(s:select{})
+---
+- dump [[1,'1',1,'1']]
+...
+-- -- ignoring ops for insert upsert
+test(s, {2, '2', 2, '2'}, {{}}, {{1, '1', 1, '1'}})
+---
+- error: Illegal parameters, update operation must be an array {op,..}, got empty
+ array
+...
+test(s, {3, '3', 3, '3'}, {{'+', 3, 3}}, {{1, '1', 1, '1'}, {3, '3', 3, '3'}})
+---
+- upsert([3,'3',3,'3'], [['+',3,3]], ) OK [[1,'1',1,'1'],[3,'3',3,'3']]
+...
+t[1] = 1
+---
+...
+test(s, t, {{'+', 3, 3}, {'+', 4, 3}}, {{1, '1', 4, '1'}, {3, '3', 3, '3'}})
+---
+- upsert([1,'1',1,'qwerty'], [['+',3,3],['+',4,3]], ) OK [[1,'1',4,'1'],[3,'3',3,'3']]
+...
+t[1] = 2
+---
+...
+test(s, t, {{'-', 4, 1}}, {{1, '1', 4, '1'}, {2, '1', 1, 'qwerty'}, {3, '3', 3, '3'}})
+---
+- upsert([2,'1',1,'qwerty'], [['-',4,1]], ) OK [[1,'1',4,'1'],[2,'1',1,'qwerty'],[3,'3',3,'3']]
+...
+t[1] = 3
+---
+...
+test(s, t, {{':', 3, 3, 3, ''}, {'|', 3, 4}}, {{1, '1', 4, '1'}, {2, '1', 1, 'qwerty'}, {3, '3', 7, '3'}})
+---
+- upsert([3,'1',1,'qwerty'], [[':',3,3,3,''],['|',3,4]], ) OK [[1,'1',4,'1'],[2,'1',1,'qwerty'],[3,'3',7,'3']]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:replace({1, 1, 1})
+---
+- [1, 1, 1]
+...
+box.snapshot()
+---
+- ok
+...
+s:upsert({1, 1}, {{'+', 2, 2}})
+---
+...
+s:upsert({1, 1}, {{'+', 3, 4}})
+---
+...
+s:select()
+---
+- - [1, 3, 5]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+s:upsert({1}, {})
+---
+- error: 'No index #0 is defined in space ''ephemeral'''
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', {parts = {1, 'unsigned', 3, 'unsigned'}})
+---
+...
+s:upsert({100, 100, 100}, {{'+', 2, 200}})
+---
+...
+s:upsert({200, 100, 200}, {{'+', 2, 300}})
+---
+...
+s:upsert({300, 100, 300}, {{'+', 2, 400}})
+---
+...
+i:select{}
+---
+- - [100, 100, 100]
+ - [200, 100, 200]
+ - [300, 100, 300]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', {parts = {2, 'unsigned', 3, 'unsigned'}})
+---
+...
+s:upsert({100, 100, 100}, {{'+', 1, 200}})
+---
+...
+s:upsert({200, 100, 200}, {{'+', 1, 300}})
+---
+...
+s:upsert({300, 100, 300}, {{'+', 1, 400}})
+---
+...
+i:select{}
+---
+- - [100, 100, 100]
+ - [200, 100, 200]
+ - [300, 100, 300]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', {parts = {3, 'unsigned', 2, 'unsigned'}})
+---
+...
+s:upsert({100, 100, 100}, {{'+', 1, 200}})
+---
+...
+s:upsert({200, 100, 200}, {{'+', 1, 300}})
+---
+...
+s:upsert({300, 100, 300}, {{'+', 1, 400}})
+---
+...
+i:select{}
+---
+- - [100, 100, 100]
+ - [200, 100, 200]
+ - [300, 100, 300]
+...
+s:drop()
+---
+...
+-- Ephemeral index: methods: update
+s = box.schema.space.create_ephemeral()
+---
+...
+-- test delete field
+i = s:create_index('a')
+---
+...
+s:insert{1000001, 1000002, 1000003, 1000004, 1000005}
+---
+- [1000001, 1000002, 1000003, 1000004, 1000005]
+...
+s:update({1000001}, {{'#', 1, 1}})
+---
+- error: Attempt to modify a tuple field which is part of index 'a' in space 'ephemeral'
+...
+s:update({1000001}, {{'#', 1, "only one record please"}})
+---
+- error: 'Argument type in operation ''#'' on field 1 does not match field type: expected
+ a number of fields to delete'
+...
+i:drop()
+---
+...
+-- test arithmetic
+i = s:create_index('a')
+---
+...
+s:insert{1, 0}
+---
+- [1, 0]
+...
+s:update(1, {{'+', 2, 10}})
+---
+- [1, 10]
+...
+s:update(1, {{'+', 2, 15}})
+---
+- [1, 25]
+...
+s:update(1, {{'-', 2, 5}})
+---
+- [1, 20]
+...
+s:update(1, {{'-', 2, 20}})
+---
+- [1, 0]
+...
+s:update(1, {{'|', 2, 0x9}})
+---
+- [1, 9]
+...
+s:update(1, {{'|', 2, 0x6}})
+---
+- [1, 15]
+...
+s:update(1, {{'&', 2, 0xabcde}})
+---
+- [1, 14]
+...
+s:update(1, {{'&', 2, 0x2}})
+---
+- [1, 2]
+...
+s:update(1, {{'^', 2, 0xa2}})
+---
+- [1, 160]
+...
+s:update(1, {{'^', 2, 0xa2}})
+---
+- [1, 2]
+...
+i:drop()
+---
+...
+-- test delete multiple fields
+i = s:create_index('a')
+---
+...
+s:insert{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+---
+- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 42, 1}})
+---
+- error: Field 42 was not found in the tuple
+...
+s:update({0}, {{'#', 4, 'abirvalg'}})
+---
+- error: 'Argument type in operation ''#'' on field 4 does not match field type: expected
+ a number of fields to delete'
+...
+s:update({0}, {{'#', 2, 1}, {'#', 4, 2}, {'#', 6, 1}})
+---
+- [0, 2, 3, 6, 7, 9, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 4, 3}})
+---
+- [0, 2, 3, 10, 11, 12, 13, 14, 15]
+...
+s:update({0}, {{'#', 5, 123456}})
+---
+- [0, 2, 3, 10]
+...
+s:update({0}, {{'#', 3, 4294967295}})
+---
+- [0, 2]
+...
+s:update({0}, {{'#', 2, 0}})
+---
+- error: 'Field 2 UPDATE error: cannot delete 0 fields'
+...
+i:drop()
+---
+...
+-- test insert field
+i = s:create_index('a')
+---
+...
+s:insert{1, 3, 6, 9}
+---
+- [1, 3, 6, 9]
+...
+s:update({1}, {{'!', 2, 2}})
+---
+- [1, 2, 3, 6, 9]
+...
+s:update({1}, {{'!', 4, 4}, {'!', 4, 5}, {'!', 5, 7}, {'!', 5, 8}})
+---
+- [1, 2, 3, 5, 8, 7, 4, 6, 9]
+...
+s:update({1}, {{'!', 10, 10}, {'!', 10, 11}, {'!', 10, 12}})
+---
+- [1, 2, 3, 5, 8, 7, 4, 6, 9, 12, 11, 10]
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 'tuple'}
+---
+- [1, 'tuple']
+...
+s:update({1}, {{'#', 2, 1}, {'!', 2, 'inserted tuple'}, {'=', 3, 'set tuple'}})
+---
+- [1, 'inserted tuple', 'set tuple']
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 'tuple'}
+---
+- [1, 'tuple']
+...
+s:update({1}, {{'=', 2, 'set tuple'}, {'!', 2, 'inserted tuple'}, {'#', 3, 1}})
+---
+- [1, 'inserted tuple']
+...
+s:update({1}, {{'!', 1, 3}, {'!', 1, 2}})
+---
+- error: Attempt to modify a tuple field which is part of index 'a' in space 'ephemeral'
+...
+i:drop()
+---
+...
+-- test update's assign opearations
+i = s:create_index('a')
+---
+...
+s:replace{1, 'field string value'}
+---
+- [1, 'field string value']
+...
+s:update({1}, {{'=', 2, 'new field string value'}, {'=', 3, 42}, {'=', 4, 0xdeadbeef}})
+---
+- [1, 'new field string value', 42, 3735928559]
+...
+-- test multiple update opearations on the same field
+s:update({1}, {{'+', 3, 16}, {'&', 4, 0xffff0000}, {'|', 4, 0x0000a0a0}, {'^', 4, 0xffff00aa}})
+---
+- error: 'Field 4 UPDATE error: double update of the same field'
+...
+-- test update splice operation
+s:replace{1953719668, 'something to splice'}
+---
+- [1953719668, 'something to splice']
+...
+s:update(1953719668, {{':', 2, 1, 4, 'no'}})
+---
+- [1953719668, 'nothing to splice']
+...
+s:update(1953719668, {{':', 2, 1, 2, 'every'}})
+---
+- [1953719668, 'everything to splice']
+...
+-- check an incorrect offset
+s:update(1953719668, {{':', 2, 100, 2, 'every'}})
+---
+- [1953719668, 'everything to spliceevery']
+...
+s:update(1953719668, {{':', 2, -100, 2, 'every'}})
+---
+- error: 'SPLICE error on field 2: offset is out of bound'
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1953719668, 'hello', 'october', '20th'}:unpack()
+---
+- 1953719668
+- hello
+- october
+- 20th
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1953719668, 'hello world'}
+---
+- [1953719668, 'hello world']
+...
+s:update(1953719668, {{'=', 2, 'bye, world'}})
+---
+- [1953719668, 'bye, world']
+...
+s:delete{1953719668}
+---
+- [1953719668, 'bye, world']
+...
+s:replace({10, 'abcde'})
+---
+- [10, 'abcde']
+...
+s:update(10, {{':', 2, 0, 0, '!'}})
+---
+- error: 'SPLICE error on field 2: offset is out of bound'
+...
+s:update(10, {{':', 2, 1, 0, '('}})
+---
+- [10, '(abcde']
+...
+s:update(10, {{':', 2, 2, 0, '({'}})
+---
+- [10, '(({abcde']
+...
+s:update(10, {{':', 2, -1, 0, ')'}})
+---
+- [10, '(({abcde)']
+...
+s:update(10, {{':', 2, -2, 0, '})'}})
+---
+- [10, '(({abcde}))']
+...
+-- test update delete operations
+s:update({1}, {{'#', 4, 1}, {'#', 3, 1}})
+---
+...
+-- test update insert operations
+s:update({1}, {{'!', 2, 1}, {'!', 2, 2}, {'!', 2, 3}, {'!', 2, 4}})
+---
+...
+-- s:update: zero field
+s:insert{48}
+---
+- [48]
+...
+s:update(48, {{'=', 0, 'hello'}})
+---
+- error: Field 0 was not found in the tuple
+...
+-- s:update: push/pop fields
+s:insert{1684234849}
+---
+- [1684234849]
+...
+s:update({1684234849}, {{'#', 2, 1}})
+---
+- error: Field 2 was not found in the tuple
+...
+s:update({1684234849}, {{'!', -1, 'push1'}})
+---
+- [1684234849, 'push1']
+...
+s:update({1684234849}, {{'!', -1, 'push2'}})
+---
+- [1684234849, 'push1', 'push2']
+...
+s:update({1684234849}, {{'!', -1, 'push3'}})
+---
+- [1684234849, 'push1', 'push2', 'push3']
+...
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap1'}})
+---
+- [1684234849, 'push2', 'push3', 'swap1']
+...
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap2'}})
+---
+- [1684234849, 'push3', 'swap1', 'swap2']
+...
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap3'}})
+---
+- [1684234849, 'swap1', 'swap2', 'swap3']
+...
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop1'}})
+---
+- [1684234849, 'swap1', 'swap2', 'noop1']
+...
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop2'}})
+---
+- [1684234849, 'swap1', 'swap2', 'noop2']
+...
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop3'}})
+---
+- [1684234849, 'swap1', 'swap2', 'noop3']
+...
+--
+-- negative indexes
+--
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', 0, 'Test'}})
+---
+- error: Field 0 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -1, 'Test'}})
+---
+- [1, 2, 3, 4, 5, 'Test']
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -3, 'Test'}})
+---
+- [1, 2, 3, 'Test', 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -5, 'Test'}})
+---
+- [1, 'Test', 2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -6, 'Test'}})
+---
+- ['Test', 1, 2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -7, 'Test'}})
+---
+- error: Field -7 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -100500, 'Test'}})
+---
+- error: Field -100500 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', 0, 'Test'}})
+---
+- error: Field 0 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -1, 'Test'}})
+---
+- [1, 2, 3, 4, 'Test']
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -3, 'Test'}})
+---
+- [1, 2, 'Test', 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -5, 'Test'}})
+---
+- ['Test', 2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -6, 'Test'}})
+---
+- error: Field -6 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -100500, 'Test'}})
+---
+- error: Field -100500 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', 0, 100}})
+---
+- error: Field 0 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -1, 100}})
+---
+- [1, 2, 3, 4, 105]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -3, 100}})
+---
+- [1, 2, 103, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -5, 100}})
+---
+- [101, 2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -6, 100}})
+---
+- error: Field -6 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -100500, 100}})
+---
+- error: Field -100500 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', 0, 100}})
+---
+- error: Field 0 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -1, 100}})
+---
+- [1, 2, 3, 4, 101]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -3, 100}})
+---
+- [1, 2, 103, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -5, 100}})
+---
+- [101, 2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -6, 100}})
+---
+- error: Field -6 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -100500, 100}})
+---
+- error: Field -100500 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', 0, 1}})
+---
+- error: Field 0 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -1, 1}})
+---
+- [1, 2, 3, 4]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -3, 1}})
+---
+- [1, 2, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -5, 1}})
+---
+- [2, 3, 4, 5]
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -6, 1}})
+---
+- error: Field -6 was not found in the tuple
+...
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -100500, 1}})
+---
+- error: Field -100500 was not found in the tuple
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 2, 3}
+---
+- [1, 2, 3]
+...
+s:update({1})
+---
+- error: Usage index:update(key, ops)
+...
+s:update({1}, {'=', 1, 1})
+---
+- error: Illegal parameters, update operation must be an array {op,..}
+...
+s:drop()
+---
+...
+ffi = require('ffi')
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{0, -1}
+---
+- [0, -1]
+...
+-- + --
+s:update({0}, {{'+', 2, "a"}}) -- err
+---
+- error: 'Argument type in operation ''+'' on field 2 does not match field type: expected
+ a number'
+...
+s:update({0}, {{'+', 2, 10}}) -- neg(ative) + pos(itive) = pos(itive) 9
+---
+- [0, 9]
+...
+s:update({0}, {{'+', 2, 5}}) -- pos + pos = pos 14
+---
+- [0, 14]
+...
+s:update({0}, {{'+', 2, -4}}) -- pos + neg = pos 10
+---
+- [0, 10]
+...
+s:update({0}, {{'+', 2, -22}}) -- pos + neg = neg -12
+---
+- [0, -12]
+...
+s:update({0}, {{'+', 2, -3}}) -- neg + neg = neg -15
+---
+- [0, -15]
+...
+s:update({0}, {{'+', 2, 7}}) -- neg + pos = neg -8
+---
+- [0, -8]
+...
+-- - --
+s:update({0}, {{'-', 2, "a"}}) -- err
+---
+- error: 'Argument type in operation ''-'' on field 2 does not match field type: expected
+ a number'
+...
+s:update({0}, {{'-', 2, 16}}) -- neg(ative) - pos(itive) = neg(ative) -24
+---
+- [0, -24]
+...
+s:update({0}, {{'-', 2, -4}}) -- neg - neg = neg 20
+---
+- [0, -20]
+...
+s:update({0}, {{'-', 2, -32}}) -- neg - neg = pos 12
+---
+- [0, 12]
+...
+s:update({0}, {{'-', 2, 3}}) -- pos - pos = pos 9
+---
+- [0, 9]
+...
+s:update({0}, {{'-', 2, -5}}) -- pos - neg = pos 14
+---
+- [0, 14]
+...
+s:update({0}, {{'-', 2, 17}}) -- pos - pos = neg -3
+---
+- [0, -3]
+...
+-- bit --
+s:replace{0, 0} -- 0
+---
+- [0, 0]
+...
+s:update({0}, {{'|', 2, 24}}) -- 24
+---
+- [0, 24]
+...
+s:update({0}, {{'|', 2, 2}}) -- 26
+---
+- [0, 26]
+...
+s:update({0}, {{'&', 2, 50}}) -- 18
+---
+- [0, 18]
+...
+s:update({0}, {{'^', 2, 6}}) -- 20
+---
+- [0, 20]
+...
+s:update({0}, {{'|', 2, -1}}) -- err
+---
+- error: 'Argument type in operation ''|'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'&', 2, -1}}) -- err
+---
+- error: 'Argument type in operation ''&'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'^', 2, -1}}) -- err
+---
+- error: 'Argument type in operation ''^'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:replace{0, -1} -- -1
+---
+- [0, -1]
+...
+s:update({0}, {{'|', 2, 2}}) -- err
+---
+- error: 'Argument type in operation ''|'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'&', 2, 40}}) -- err
+---
+- error: 'Argument type in operation ''&'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'^', 2, 6}}) -- err
+---
+- error: 'Argument type in operation ''^'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:replace{0, 1.5} -- 1.5
+---
+- [0, 1.5]
+...
+s:update({0}, {{'|', 2, 2}}) -- err
+---
+- error: 'Argument type in operation ''|'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'&', 2, 40}}) -- err
+---
+- error: 'Argument type in operation ''&'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'^', 2, 6}}) -- err
+---
+- error: 'Argument type in operation ''^'' on field 2 does not match field type: expected
+ a positive integer'
+...
+-- double
+s:replace{0, 5} -- 5
+---
+- [0, 5]
+...
+s:update({0}, {{'+', 2, 1.5}}) -- int + double = double 6.5
+---
+- [0, 6.5]
+...
+s:update({0}, {{'|', 2, 2}}) -- err (double!)
+---
+- error: 'Argument type in operation ''|'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'-', 2, 0.5}}) -- double - double = double 6
+---
+- [0, 6]
+...
+s:update({0}, {{'+', 2, 1.5}}) -- double + double = double 7.5
+---
+- [0, 7.5]
+...
+-- float
+s:replace{0, ffi.new("float", 1.5)} -- 1.5
+---
+- [0, 1.5]
+...
+s:update({0}, {{'+', 2, 2}}) -- float + int = float 3.5
+---
+- [0, 3.5]
+...
+s:update({0}, {{'+', 2, ffi.new("float", 3.5)}}) -- float + int = float 7
+---
+- [0, 7]
+...
+s:update({0}, {{'|', 2, 2}}) -- err (float!)
+---
+- error: 'Argument type in operation ''|'' on field 2 does not match field type: expected
+ a positive integer'
+...
+s:update({0}, {{'-', 2, ffi.new("float", 1.5)}}) -- float - float = float 5.5
+---
+- [0, 5.5]
+...
+s:update({0}, {{'+', 2, ffi.new("float", 3.5)}}) -- float + float = float 9
+---
+- [0, 9]
+...
+s:update({0}, {{'-', 2, ffi.new("float", 9)}}) -- float + float = float 0
+---
+- [0, 0]
+...
+s:update({0}, {{'+', 2, ffi.new("float", 1.2)}}) -- float + float = float 1.2
+---
+- [0, 1.2000000476837]
+...
+-- overflow --
+s:replace{0, 0xfffffffffffffffeull}
+---
+- [0, 18446744073709551614]
+...
+s:update({0}, {{'+', 2, 1}}) -- ok
+---
+- [0, 18446744073709551615]
+...
+s:update({0}, {{'+', 2, 1}}) -- overflow
+---
+- error: Integer overflow when performing '+' operation on field 2
+...
+s:update({0}, {{'+', 2, 100500}}) -- overflow
+---
+- error: Integer overflow when performing '+' operation on field 2
+...
+s:replace{0, 1}
+---
+- [0, 1]
+...
+s:update({0}, {{'+', 2, 0xffffffffffffffffull}}) -- overflow
+---
+- error: Integer overflow when performing '+' operation on field 2
+...
+s:replace{0, -1}
+---
+- [0, -1]
+...
+s:update({0}, {{'+', 2, 0xffffffffffffffffull}}) -- ok
+---
+- [0, 18446744073709551614]
+...
+s:replace{0, 0}
+---
+- [0, 0]
+...
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- ok
+---
+- [0, -9223372036854775807]
+...
+s:replace{0, -1}
+---
+- [0, -1]
+...
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- ok
+---
+- [0, -9223372036854775808]
+...
+s:replace{0, -2}
+---
+- [0, -2]
+...
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- overflow
+---
+- error: Integer overflow when performing '-' operation on field 2
+...
+s:replace{0, 1}
+---
+- [0, 1]
+...
+s:update({0}, {{'-', 2, 0xffffffffffffffffull}}) -- overflow
+---
+- error: Integer overflow when performing '-' operation on field 2
+...
+s:replace{0, 0xffffffffffffffefull}
+---
+- [0, 18446744073709551599]
+...
+s:update({0}, {{'-', 2, -16}}) -- ok
+---
+- [0, 18446744073709551615]
+...
+s:update({0}, {{'-', 2, -16}}) -- overflow
+---
+- error: Integer overflow when performing '-' operation on field 2
+...
+s:replace{0, -0x4000000000000000ll}
+---
+- [0, -4611686018427387904]
+...
+s:update({0}, {{'+', 2, -0x4000000000000000ll}}) -- ok
+---
+- [0, -9223372036854775808]
+...
+s:replace{0, -0x4000000000000000ll}
+---
+- [0, -4611686018427387904]
+...
+s:update({0}, {{'+', 2, -0x4000000000000001ll}}) -- overflow
+---
+- error: Integer overflow when performing '+' operation on field 2
+...
+-- some wrong updates --
+s:update({0}, 0)
+---
+- error: Usage index:update(key, ops)
+...
+s:update({0}, {'+', 2, 2})
+---
+- error: Illegal parameters, update operation must be an array {op,..}
+...
+s:update({0}, {{}})
+---
+- error: Illegal parameters, update operation must be an array {op,..}, got empty
+ array
+...
+s:update({0}, {{'+'}})
+---
+- error: Unknown UPDATE operation
+...
+s:update({0}, {{'+', 0}})
+---
+- error: Unknown UPDATE operation
+...
+s:update({0}, {{'+', '+', '+'}})
+---
+- error: Illegal parameters, field id must be a number
+...
+s:update({0}, {{0, 0, 0}})
+---
+- error: Illegal parameters, update operation name must be a string
+...
+ops = {}
+---
+...
+for i = 1,10 do table.insert(ops, {'=', 2, '1234567890'}) end
+---
+...
+s:upsert({0}, ops)
+---
+...
+s:get{0}
+---
+- [0, '1234567890']
+...
+s:update({0}, {})
+---
+- [0, '1234567890']
+...
+map = setmetatable({}, { __serialize = 'map' })
+---
+...
+t = box.tuple.new({1, 2, 3})
+---
+...
+s:replace({1, 2, 3})
+---
+- [1, 2, 3]
+...
+t:update({{'=', 3, map}})
+---
+- [1, 2, {}]
+...
+s:update(1, {{'=', 3, map}})
+---
+- [1, 2, {}]
+...
+s:drop()
+---
+...
+-- Ephemeral index: methods: pairs, count, select (iterators)
+-- iterator (str)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 100 do s:replace({tostring(key)}) end
+---
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['10']
+ - ['100']
+ - ['11']
+ - ['12']
+ - ['13']
+ - ['14']
+ - ['15']
+ - ['16']
+ - ['17']
+ - ['18']
+ - ['19']
+ - ['2']
+ - ['20']
+ - ['21']
+ - ['22']
+ - ['23']
+ - ['24']
+ - ['25']
+ - ['26']
+ - ['27']
+ - ['28']
+ - ['29']
+ - ['3']
+ - ['30']
+ - ['31']
+ - ['32']
+ - ['33']
+ - ['34']
+ - ['35']
+ - ['36']
+ - ['37']
+ - ['38']
+ - ['39']
+ - ['4']
+ - ['40']
+ - ['41']
+ - ['42']
+ - ['43']
+ - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['10']
+ - ['100']
+ - ['11']
+ - ['12']
+ - ['13']
+ - ['14']
+ - ['15']
+ - ['16']
+ - ['17']
+ - ['18']
+ - ['19']
+ - ['2']
+ - ['20']
+ - ['21']
+ - ['22']
+ - ['23']
+ - ['24']
+ - ['25']
+ - ['26']
+ - ['27']
+ - ['28']
+ - ['29']
+ - ['3']
+ - ['30']
+ - ['31']
+ - ['32']
+ - ['33']
+ - ['34']
+ - ['35']
+ - ['36']
+ - ['37']
+ - ['38']
+ - ['39']
+ - ['4']
+ - ['40']
+ - ['41']
+ - ['42']
+ - ['43']
+ - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(tostring(44), {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(tostring(44), {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['99']
+ - ['98']
+ - ['97']
+ - ['96']
+ - ['95']
+ - ['94']
+ - ['93']
+ - ['92']
+ - ['91']
+ - ['90']
+ - ['9']
+ - ['89']
+ - ['88']
+ - ['87']
+ - ['86']
+ - ['85']
+ - ['84']
+ - ['83']
+ - ['82']
+ - ['81']
+ - ['80']
+ - ['8']
+ - ['79']
+ - ['78']
+ - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs(tostring(77), {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['99']
+ - ['98']
+ - ['97']
+ - ['96']
+ - ['95']
+ - ['94']
+ - ['93']
+ - ['92']
+ - ['91']
+ - ['90']
+ - ['9']
+ - ['89']
+ - ['88']
+ - ['87']
+ - ['86']
+ - ['85']
+ - ['84']
+ - ['83']
+ - ['82']
+ - ['81']
+ - ['80']
+ - ['8']
+ - ['79']
+ - ['78']
+ - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs(tostring(77), {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+s:drop()
+---
+...
+-- iterator (num)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for key = 1, 100 do s:replace({key}) end
+---
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+ - [2]
+ - [3]
+ - [4]
+ - [5]
+ - [6]
+ - [7]
+ - [8]
+ - [9]
+ - [10]
+ - [11]
+ - [12]
+ - [13]
+ - [14]
+ - [15]
+ - [16]
+ - [17]
+ - [18]
+ - [19]
+ - [20]
+ - [21]
+ - [22]
+ - [23]
+ - [24]
+ - [25]
+ - [26]
+ - [27]
+ - [28]
+ - [29]
+ - [30]
+ - [31]
+ - [32]
+ - [33]
+ - [34]
+ - [35]
+ - [36]
+ - [37]
+ - [38]
+ - [39]
+ - [40]
+ - [41]
+ - [42]
+ - [43]
+ - [44]
+ - [45]
+ - [46]
+ - [47]
+ - [48]
+ - [49]
+ - [50]
+ - [51]
+ - [52]
+ - [53]
+ - [54]
+ - [55]
+ - [56]
+ - [57]
+ - [58]
+ - [59]
+ - [60]
+ - [61]
+ - [62]
+ - [63]
+ - [64]
+ - [65]
+ - [66]
+ - [67]
+ - [68]
+ - [69]
+ - [70]
+ - [71]
+ - [72]
+ - [73]
+ - [74]
+ - [75]
+ - [76]
+ - [77]
+ - [78]
+ - [79]
+ - [80]
+ - [81]
+ - [82]
+ - [83]
+ - [84]
+ - [85]
+ - [86]
+ - [87]
+ - [88]
+ - [89]
+ - [90]
+ - [91]
+ - [92]
+ - [93]
+ - [94]
+ - [95]
+ - [96]
+ - [97]
+ - [98]
+ - [99]
+ - [100]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+ - [2]
+ - [3]
+ - [4]
+ - [5]
+ - [6]
+ - [7]
+ - [8]
+ - [9]
+ - [10]
+ - [11]
+ - [12]
+ - [13]
+ - [14]
+ - [15]
+ - [16]
+ - [17]
+ - [18]
+ - [19]
+ - [20]
+ - [21]
+ - [22]
+ - [23]
+ - [24]
+ - [25]
+ - [26]
+ - [27]
+ - [28]
+ - [29]
+ - [30]
+ - [31]
+ - [32]
+ - [33]
+ - [34]
+ - [35]
+ - [36]
+ - [37]
+ - [38]
+ - [39]
+ - [40]
+ - [41]
+ - [42]
+ - [43]
+ - [44]
+ - [45]
+ - [46]
+ - [47]
+ - [48]
+ - [49]
+ - [50]
+ - [51]
+ - [52]
+ - [53]
+ - [54]
+ - [55]
+ - [56]
+ - [57]
+ - [58]
+ - [59]
+ - [60]
+ - [61]
+ - [62]
+ - [63]
+ - [64]
+ - [65]
+ - [66]
+ - [67]
+ - [68]
+ - [69]
+ - [70]
+ - [71]
+ - [72]
+ - [73]
+ - [74]
+ - [75]
+ - [76]
+ - [77]
+ - [78]
+ - [79]
+ - [80]
+ - [81]
+ - [82]
+ - [83]
+ - [84]
+ - [85]
+ - [86]
+ - [87]
+ - [88]
+ - [89]
+ - [90]
+ - [91]
+ - [92]
+ - [93]
+ - [94]
+ - [95]
+ - [96]
+ - [97]
+ - [98]
+ - [99]
+ - [100]
+...
+t = {} for state, v in i:pairs(44, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [44]
+ - [45]
+ - [46]
+ - [47]
+ - [48]
+ - [49]
+ - [50]
+ - [51]
+ - [52]
+ - [53]
+ - [54]
+ - [55]
+ - [56]
+ - [57]
+ - [58]
+ - [59]
+ - [60]
+ - [61]
+ - [62]
+ - [63]
+ - [64]
+ - [65]
+ - [66]
+ - [67]
+ - [68]
+ - [69]
+ - [70]
+ - [71]
+ - [72]
+ - [73]
+ - [74]
+ - [75]
+ - [76]
+ - [77]
+ - [78]
+ - [79]
+ - [80]
+ - [81]
+ - [82]
+ - [83]
+ - [84]
+ - [85]
+ - [86]
+ - [87]
+ - [88]
+ - [89]
+ - [90]
+ - [91]
+ - [92]
+ - [93]
+ - [94]
+ - [95]
+ - [96]
+ - [97]
+ - [98]
+ - [99]
+ - [100]
+...
+t = {} for state, v in i:pairs(44, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [45]
+ - [46]
+ - [47]
+ - [48]
+ - [49]
+ - [50]
+ - [51]
+ - [52]
+ - [53]
+ - [54]
+ - [55]
+ - [56]
+ - [57]
+ - [58]
+ - [59]
+ - [60]
+ - [61]
+ - [62]
+ - [63]
+ - [64]
+ - [65]
+ - [66]
+ - [67]
+ - [68]
+ - [69]
+ - [70]
+ - [71]
+ - [72]
+ - [73]
+ - [74]
+ - [75]
+ - [76]
+ - [77]
+ - [78]
+ - [79]
+ - [80]
+ - [81]
+ - [82]
+ - [83]
+ - [84]
+ - [85]
+ - [86]
+ - [87]
+ - [88]
+ - [89]
+ - [90]
+ - [91]
+ - [92]
+ - [93]
+ - [94]
+ - [95]
+ - [96]
+ - [97]
+ - [98]
+ - [99]
+ - [100]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [100]
+ - [99]
+ - [98]
+ - [97]
+ - [96]
+ - [95]
+ - [94]
+ - [93]
+ - [92]
+ - [91]
+ - [90]
+ - [89]
+ - [88]
+ - [87]
+ - [86]
+ - [85]
+ - [84]
+ - [83]
+ - [82]
+ - [81]
+ - [80]
+ - [79]
+ - [78]
+ - [77]
+ - [76]
+ - [75]
+ - [74]
+ - [73]
+ - [72]
+ - [71]
+ - [70]
+ - [69]
+ - [68]
+ - [67]
+ - [66]
+ - [65]
+ - [64]
+ - [63]
+ - [62]
+ - [61]
+ - [60]
+ - [59]
+ - [58]
+ - [57]
+ - [56]
+ - [55]
+ - [54]
+ - [53]
+ - [52]
+ - [51]
+ - [50]
+ - [49]
+ - [48]
+ - [47]
+ - [46]
+ - [45]
+ - [44]
+ - [43]
+ - [42]
+ - [41]
+ - [40]
+ - [39]
+ - [38]
+ - [37]
+ - [36]
+ - [35]
+ - [34]
+ - [33]
+ - [32]
+ - [31]
+ - [30]
+ - [29]
+ - [28]
+ - [27]
+ - [26]
+ - [25]
+ - [24]
+ - [23]
+ - [22]
+ - [21]
+ - [20]
+ - [19]
+ - [18]
+ - [17]
+ - [16]
+ - [15]
+ - [14]
+ - [13]
+ - [12]
+ - [11]
+ - [10]
+ - [9]
+ - [8]
+ - [7]
+ - [6]
+ - [5]
+ - [4]
+ - [3]
+ - [2]
+ - [1]
+...
+t = {} for state, v in i:pairs(77, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [77]
+ - [76]
+ - [75]
+ - [74]
+ - [73]
+ - [72]
+ - [71]
+ - [70]
+ - [69]
+ - [68]
+ - [67]
+ - [66]
+ - [65]
+ - [64]
+ - [63]
+ - [62]
+ - [61]
+ - [60]
+ - [59]
+ - [58]
+ - [57]
+ - [56]
+ - [55]
+ - [54]
+ - [53]
+ - [52]
+ - [51]
+ - [50]
+ - [49]
+ - [48]
+ - [47]
+ - [46]
+ - [45]
+ - [44]
+ - [43]
+ - [42]
+ - [41]
+ - [40]
+ - [39]
+ - [38]
+ - [37]
+ - [36]
+ - [35]
+ - [34]
+ - [33]
+ - [32]
+ - [31]
+ - [30]
+ - [29]
+ - [28]
+ - [27]
+ - [26]
+ - [25]
+ - [24]
+ - [23]
+ - [22]
+ - [21]
+ - [20]
+ - [19]
+ - [18]
+ - [17]
+ - [16]
+ - [15]
+ - [14]
+ - [13]
+ - [12]
+ - [11]
+ - [10]
+ - [9]
+ - [8]
+ - [7]
+ - [6]
+ - [5]
+ - [4]
+ - [3]
+ - [2]
+ - [1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [100]
+ - [99]
+ - [98]
+ - [97]
+ - [96]
+ - [95]
+ - [94]
+ - [93]
+ - [92]
+ - [91]
+ - [90]
+ - [89]
+ - [88]
+ - [87]
+ - [86]
+ - [85]
+ - [84]
+ - [83]
+ - [82]
+ - [81]
+ - [80]
+ - [79]
+ - [78]
+ - [77]
+ - [76]
+ - [75]
+ - [74]
+ - [73]
+ - [72]
+ - [71]
+ - [70]
+ - [69]
+ - [68]
+ - [67]
+ - [66]
+ - [65]
+ - [64]
+ - [63]
+ - [62]
+ - [61]
+ - [60]
+ - [59]
+ - [58]
+ - [57]
+ - [56]
+ - [55]
+ - [54]
+ - [53]
+ - [52]
+ - [51]
+ - [50]
+ - [49]
+ - [48]
+ - [47]
+ - [46]
+ - [45]
+ - [44]
+ - [43]
+ - [42]
+ - [41]
+ - [40]
+ - [39]
+ - [38]
+ - [37]
+ - [36]
+ - [35]
+ - [34]
+ - [33]
+ - [32]
+ - [31]
+ - [30]
+ - [29]
+ - [28]
+ - [27]
+ - [26]
+ - [25]
+ - [24]
+ - [23]
+ - [22]
+ - [21]
+ - [20]
+ - [19]
+ - [18]
+ - [17]
+ - [16]
+ - [15]
+ - [14]
+ - [13]
+ - [12]
+ - [11]
+ - [10]
+ - [9]
+ - [8]
+ - [7]
+ - [6]
+ - [5]
+ - [4]
+ - [3]
+ - [2]
+ - [1]
+...
+t = {} for state, v in i:pairs(77, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [76]
+ - [75]
+ - [74]
+ - [73]
+ - [72]
+ - [71]
+ - [70]
+ - [69]
+ - [68]
+ - [67]
+ - [66]
+ - [65]
+ - [64]
+ - [63]
+ - [62]
+ - [61]
+ - [60]
+ - [59]
+ - [58]
+ - [57]
+ - [56]
+ - [55]
+ - [54]
+ - [53]
+ - [52]
+ - [51]
+ - [50]
+ - [49]
+ - [48]
+ - [47]
+ - [46]
+ - [45]
+ - [44]
+ - [43]
+ - [42]
+ - [41]
+ - [40]
+ - [39]
+ - [38]
+ - [37]
+ - [36]
+ - [35]
+ - [34]
+ - [33]
+ - [32]
+ - [31]
+ - [30]
+ - [29]
+ - [28]
+ - [27]
+ - [26]
+ - [25]
+ - [24]
+ - [23]
+ - [22]
+ - [21]
+ - [20]
+ - [19]
+ - [18]
+ - [17]
+ - [16]
+ - [15]
+ - [14]
+ - [13]
+ - [12]
+ - [11]
+ - [10]
+ - [9]
+ - [8]
+ - [7]
+ - [6]
+ - [5]
+ - [4]
+ - [3]
+ - [2]
+ - [1]
+...
+s:drop()
+---
+...
+-- iterator multi-part (num, num)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 100 do s:replace({key, key}) end
+---
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+ - [2, 2]
+ - [3, 3]
+ - [4, 4]
+ - [5, 5]
+ - [6, 6]
+ - [7, 7]
+ - [8, 8]
+ - [9, 9]
+ - [10, 10]
+ - [11, 11]
+ - [12, 12]
+ - [13, 13]
+ - [14, 14]
+ - [15, 15]
+ - [16, 16]
+ - [17, 17]
+ - [18, 18]
+ - [19, 19]
+ - [20, 20]
+ - [21, 21]
+ - [22, 22]
+ - [23, 23]
+ - [24, 24]
+ - [25, 25]
+ - [26, 26]
+ - [27, 27]
+ - [28, 28]
+ - [29, 29]
+ - [30, 30]
+ - [31, 31]
+ - [32, 32]
+ - [33, 33]
+ - [34, 34]
+ - [35, 35]
+ - [36, 36]
+ - [37, 37]
+ - [38, 38]
+ - [39, 39]
+ - [40, 40]
+ - [41, 41]
+ - [42, 42]
+ - [43, 43]
+ - [44, 44]
+ - [45, 45]
+ - [46, 46]
+ - [47, 47]
+ - [48, 48]
+ - [49, 49]
+ - [50, 50]
+ - [51, 51]
+ - [52, 52]
+ - [53, 53]
+ - [54, 54]
+ - [55, 55]
+ - [56, 56]
+ - [57, 57]
+ - [58, 58]
+ - [59, 59]
+ - [60, 60]
+ - [61, 61]
+ - [62, 62]
+ - [63, 63]
+ - [64, 64]
+ - [65, 65]
+ - [66, 66]
+ - [67, 67]
+ - [68, 68]
+ - [69, 69]
+ - [70, 70]
+ - [71, 71]
+ - [72, 72]
+ - [73, 73]
+ - [74, 74]
+ - [75, 75]
+ - [76, 76]
+ - [77, 77]
+ - [78, 78]
+ - [79, 79]
+ - [80, 80]
+ - [81, 81]
+ - [82, 82]
+ - [83, 83]
+ - [84, 84]
+ - [85, 85]
+ - [86, 86]
+ - [87, 87]
+ - [88, 88]
+ - [89, 89]
+ - [90, 90]
+ - [91, 91]
+ - [92, 92]
+ - [93, 93]
+ - [94, 94]
+ - [95, 95]
+ - [96, 96]
+ - [97, 97]
+ - [98, 98]
+ - [99, 99]
+ - [100, 100]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+ - [2, 2]
+ - [3, 3]
+ - [4, 4]
+ - [5, 5]
+ - [6, 6]
+ - [7, 7]
+ - [8, 8]
+ - [9, 9]
+ - [10, 10]
+ - [11, 11]
+ - [12, 12]
+ - [13, 13]
+ - [14, 14]
+ - [15, 15]
+ - [16, 16]
+ - [17, 17]
+ - [18, 18]
+ - [19, 19]
+ - [20, 20]
+ - [21, 21]
+ - [22, 22]
+ - [23, 23]
+ - [24, 24]
+ - [25, 25]
+ - [26, 26]
+ - [27, 27]
+ - [28, 28]
+ - [29, 29]
+ - [30, 30]
+ - [31, 31]
+ - [32, 32]
+ - [33, 33]
+ - [34, 34]
+ - [35, 35]
+ - [36, 36]
+ - [37, 37]
+ - [38, 38]
+ - [39, 39]
+ - [40, 40]
+ - [41, 41]
+ - [42, 42]
+ - [43, 43]
+ - [44, 44]
+ - [45, 45]
+ - [46, 46]
+ - [47, 47]
+ - [48, 48]
+ - [49, 49]
+ - [50, 50]
+ - [51, 51]
+ - [52, 52]
+ - [53, 53]
+ - [54, 54]
+ - [55, 55]
+ - [56, 56]
+ - [57, 57]
+ - [58, 58]
+ - [59, 59]
+ - [60, 60]
+ - [61, 61]
+ - [62, 62]
+ - [63, 63]
+ - [64, 64]
+ - [65, 65]
+ - [66, 66]
+ - [67, 67]
+ - [68, 68]
+ - [69, 69]
+ - [70, 70]
+ - [71, 71]
+ - [72, 72]
+ - [73, 73]
+ - [74, 74]
+ - [75, 75]
+ - [76, 76]
+ - [77, 77]
+ - [78, 78]
+ - [79, 79]
+ - [80, 80]
+ - [81, 81]
+ - [82, 82]
+ - [83, 83]
+ - [84, 84]
+ - [85, 85]
+ - [86, 86]
+ - [87, 87]
+ - [88, 88]
+ - [89, 89]
+ - [90, 90]
+ - [91, 91]
+ - [92, 92]
+ - [93, 93]
+ - [94, 94]
+ - [95, 95]
+ - [96, 96]
+ - [97, 97]
+ - [98, 98]
+ - [99, 99]
+ - [100, 100]
+...
+t = {} for state, v in i:pairs({44, 44}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [44, 44]
+ - [45, 45]
+ - [46, 46]
+ - [47, 47]
+ - [48, 48]
+ - [49, 49]
+ - [50, 50]
+ - [51, 51]
+ - [52, 52]
+ - [53, 53]
+ - [54, 54]
+ - [55, 55]
+ - [56, 56]
+ - [57, 57]
+ - [58, 58]
+ - [59, 59]
+ - [60, 60]
+ - [61, 61]
+ - [62, 62]
+ - [63, 63]
+ - [64, 64]
+ - [65, 65]
+ - [66, 66]
+ - [67, 67]
+ - [68, 68]
+ - [69, 69]
+ - [70, 70]
+ - [71, 71]
+ - [72, 72]
+ - [73, 73]
+ - [74, 74]
+ - [75, 75]
+ - [76, 76]
+ - [77, 77]
+ - [78, 78]
+ - [79, 79]
+ - [80, 80]
+ - [81, 81]
+ - [82, 82]
+ - [83, 83]
+ - [84, 84]
+ - [85, 85]
+ - [86, 86]
+ - [87, 87]
+ - [88, 88]
+ - [89, 89]
+ - [90, 90]
+ - [91, 91]
+ - [92, 92]
+ - [93, 93]
+ - [94, 94]
+ - [95, 95]
+ - [96, 96]
+ - [97, 97]
+ - [98, 98]
+ - [99, 99]
+ - [100, 100]
+...
+t = {} for state, v in i:pairs({44, 44}, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [45, 45]
+ - [46, 46]
+ - [47, 47]
+ - [48, 48]
+ - [49, 49]
+ - [50, 50]
+ - [51, 51]
+ - [52, 52]
+ - [53, 53]
+ - [54, 54]
+ - [55, 55]
+ - [56, 56]
+ - [57, 57]
+ - [58, 58]
+ - [59, 59]
+ - [60, 60]
+ - [61, 61]
+ - [62, 62]
+ - [63, 63]
+ - [64, 64]
+ - [65, 65]
+ - [66, 66]
+ - [67, 67]
+ - [68, 68]
+ - [69, 69]
+ - [70, 70]
+ - [71, 71]
+ - [72, 72]
+ - [73, 73]
+ - [74, 74]
+ - [75, 75]
+ - [76, 76]
+ - [77, 77]
+ - [78, 78]
+ - [79, 79]
+ - [80, 80]
+ - [81, 81]
+ - [82, 82]
+ - [83, 83]
+ - [84, 84]
+ - [85, 85]
+ - [86, 86]
+ - [87, 87]
+ - [88, 88]
+ - [89, 89]
+ - [90, 90]
+ - [91, 91]
+ - [92, 92]
+ - [93, 93]
+ - [94, 94]
+ - [95, 95]
+ - [96, 96]
+ - [97, 97]
+ - [98, 98]
+ - [99, 99]
+ - [100, 100]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [100, 100]
+ - [99, 99]
+ - [98, 98]
+ - [97, 97]
+ - [96, 96]
+ - [95, 95]
+ - [94, 94]
+ - [93, 93]
+ - [92, 92]
+ - [91, 91]
+ - [90, 90]
+ - [89, 89]
+ - [88, 88]
+ - [87, 87]
+ - [86, 86]
+ - [85, 85]
+ - [84, 84]
+ - [83, 83]
+ - [82, 82]
+ - [81, 81]
+ - [80, 80]
+ - [79, 79]
+ - [78, 78]
+ - [77, 77]
+ - [76, 76]
+ - [75, 75]
+ - [74, 74]
+ - [73, 73]
+ - [72, 72]
+ - [71, 71]
+ - [70, 70]
+ - [69, 69]
+ - [68, 68]
+ - [67, 67]
+ - [66, 66]
+ - [65, 65]
+ - [64, 64]
+ - [63, 63]
+ - [62, 62]
+ - [61, 61]
+ - [60, 60]
+ - [59, 59]
+ - [58, 58]
+ - [57, 57]
+ - [56, 56]
+ - [55, 55]
+ - [54, 54]
+ - [53, 53]
+ - [52, 52]
+ - [51, 51]
+ - [50, 50]
+ - [49, 49]
+ - [48, 48]
+ - [47, 47]
+ - [46, 46]
+ - [45, 45]
+ - [44, 44]
+ - [43, 43]
+ - [42, 42]
+ - [41, 41]
+ - [40, 40]
+ - [39, 39]
+ - [38, 38]
+ - [37, 37]
+ - [36, 36]
+ - [35, 35]
+ - [34, 34]
+ - [33, 33]
+ - [32, 32]
+ - [31, 31]
+ - [30, 30]
+ - [29, 29]
+ - [28, 28]
+ - [27, 27]
+ - [26, 26]
+ - [25, 25]
+ - [24, 24]
+ - [23, 23]
+ - [22, 22]
+ - [21, 21]
+ - [20, 20]
+ - [19, 19]
+ - [18, 18]
+ - [17, 17]
+ - [16, 16]
+ - [15, 15]
+ - [14, 14]
+ - [13, 13]
+ - [12, 12]
+ - [11, 11]
+ - [10, 10]
+ - [9, 9]
+ - [8, 8]
+ - [7, 7]
+ - [6, 6]
+ - [5, 5]
+ - [4, 4]
+ - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({77, 77}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [77, 77]
+ - [76, 76]
+ - [75, 75]
+ - [74, 74]
+ - [73, 73]
+ - [72, 72]
+ - [71, 71]
+ - [70, 70]
+ - [69, 69]
+ - [68, 68]
+ - [67, 67]
+ - [66, 66]
+ - [65, 65]
+ - [64, 64]
+ - [63, 63]
+ - [62, 62]
+ - [61, 61]
+ - [60, 60]
+ - [59, 59]
+ - [58, 58]
+ - [57, 57]
+ - [56, 56]
+ - [55, 55]
+ - [54, 54]
+ - [53, 53]
+ - [52, 52]
+ - [51, 51]
+ - [50, 50]
+ - [49, 49]
+ - [48, 48]
+ - [47, 47]
+ - [46, 46]
+ - [45, 45]
+ - [44, 44]
+ - [43, 43]
+ - [42, 42]
+ - [41, 41]
+ - [40, 40]
+ - [39, 39]
+ - [38, 38]
+ - [37, 37]
+ - [36, 36]
+ - [35, 35]
+ - [34, 34]
+ - [33, 33]
+ - [32, 32]
+ - [31, 31]
+ - [30, 30]
+ - [29, 29]
+ - [28, 28]
+ - [27, 27]
+ - [26, 26]
+ - [25, 25]
+ - [24, 24]
+ - [23, 23]
+ - [22, 22]
+ - [21, 21]
+ - [20, 20]
+ - [19, 19]
+ - [18, 18]
+ - [17, 17]
+ - [16, 16]
+ - [15, 15]
+ - [14, 14]
+ - [13, 13]
+ - [12, 12]
+ - [11, 11]
+ - [10, 10]
+ - [9, 9]
+ - [8, 8]
+ - [7, 7]
+ - [6, 6]
+ - [5, 5]
+ - [4, 4]
+ - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [100, 100]
+ - [99, 99]
+ - [98, 98]
+ - [97, 97]
+ - [96, 96]
+ - [95, 95]
+ - [94, 94]
+ - [93, 93]
+ - [92, 92]
+ - [91, 91]
+ - [90, 90]
+ - [89, 89]
+ - [88, 88]
+ - [87, 87]
+ - [86, 86]
+ - [85, 85]
+ - [84, 84]
+ - [83, 83]
+ - [82, 82]
+ - [81, 81]
+ - [80, 80]
+ - [79, 79]
+ - [78, 78]
+ - [77, 77]
+ - [76, 76]
+ - [75, 75]
+ - [74, 74]
+ - [73, 73]
+ - [72, 72]
+ - [71, 71]
+ - [70, 70]
+ - [69, 69]
+ - [68, 68]
+ - [67, 67]
+ - [66, 66]
+ - [65, 65]
+ - [64, 64]
+ - [63, 63]
+ - [62, 62]
+ - [61, 61]
+ - [60, 60]
+ - [59, 59]
+ - [58, 58]
+ - [57, 57]
+ - [56, 56]
+ - [55, 55]
+ - [54, 54]
+ - [53, 53]
+ - [52, 52]
+ - [51, 51]
+ - [50, 50]
+ - [49, 49]
+ - [48, 48]
+ - [47, 47]
+ - [46, 46]
+ - [45, 45]
+ - [44, 44]
+ - [43, 43]
+ - [42, 42]
+ - [41, 41]
+ - [40, 40]
+ - [39, 39]
+ - [38, 38]
+ - [37, 37]
+ - [36, 36]
+ - [35, 35]
+ - [34, 34]
+ - [33, 33]
+ - [32, 32]
+ - [31, 31]
+ - [30, 30]
+ - [29, 29]
+ - [28, 28]
+ - [27, 27]
+ - [26, 26]
+ - [25, 25]
+ - [24, 24]
+ - [23, 23]
+ - [22, 22]
+ - [21, 21]
+ - [20, 20]
+ - [19, 19]
+ - [18, 18]
+ - [17, 17]
+ - [16, 16]
+ - [15, 15]
+ - [14, 14]
+ - [13, 13]
+ - [12, 12]
+ - [11, 11]
+ - [10, 10]
+ - [9, 9]
+ - [8, 8]
+ - [7, 7]
+ - [6, 6]
+ - [5, 5]
+ - [4, 4]
+ - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({77, 77}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [76, 76]
+ - [75, 75]
+ - [74, 74]
+ - [73, 73]
+ - [72, 72]
+ - [71, 71]
+ - [70, 70]
+ - [69, 69]
+ - [68, 68]
+ - [67, 67]
+ - [66, 66]
+ - [65, 65]
+ - [64, 64]
+ - [63, 63]
+ - [62, 62]
+ - [61, 61]
+ - [60, 60]
+ - [59, 59]
+ - [58, 58]
+ - [57, 57]
+ - [56, 56]
+ - [55, 55]
+ - [54, 54]
+ - [53, 53]
+ - [52, 52]
+ - [51, 51]
+ - [50, 50]
+ - [49, 49]
+ - [48, 48]
+ - [47, 47]
+ - [46, 46]
+ - [45, 45]
+ - [44, 44]
+ - [43, 43]
+ - [42, 42]
+ - [41, 41]
+ - [40, 40]
+ - [39, 39]
+ - [38, 38]
+ - [37, 37]
+ - [36, 36]
+ - [35, 35]
+ - [34, 34]
+ - [33, 33]
+ - [32, 32]
+ - [31, 31]
+ - [30, 30]
+ - [29, 29]
+ - [28, 28]
+ - [27, 27]
+ - [26, 26]
+ - [25, 25]
+ - [24, 24]
+ - [23, 23]
+ - [22, 22]
+ - [21, 21]
+ - [20, 20]
+ - [19, 19]
+ - [18, 18]
+ - [17, 17]
+ - [16, 16]
+ - [15, 15]
+ - [14, 14]
+ - [13, 13]
+ - [12, 12]
+ - [11, 11]
+ - [10, 10]
+ - [9, 9]
+ - [8, 8]
+ - [7, 7]
+ - [6, 6]
+ - [5, 5]
+ - [4, 4]
+ - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+s:drop()
+---
+...
+-- iterator with tuple.new
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 100 do s:replace({tostring(key)}) end
+---
+...
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['10']
+ - ['100']
+ - ['11']
+ - ['12']
+ - ['13']
+ - ['14']
+ - ['15']
+ - ['16']
+ - ['17']
+ - ['18']
+ - ['19']
+ - ['2']
+ - ['20']
+ - ['21']
+ - ['22']
+ - ['23']
+ - ['24']
+ - ['25']
+ - ['26']
+ - ['27']
+ - ['28']
+ - ['29']
+ - ['3']
+ - ['30']
+ - ['31']
+ - ['32']
+ - ['33']
+ - ['34']
+ - ['35']
+ - ['36']
+ - ['37']
+ - ['38']
+ - ['39']
+ - ['4']
+ - ['40']
+ - ['41']
+ - ['42']
+ - ['43']
+ - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['10']
+ - ['100']
+ - ['11']
+ - ['12']
+ - ['13']
+ - ['14']
+ - ['15']
+ - ['16']
+ - ['17']
+ - ['18']
+ - ['19']
+ - ['2']
+ - ['20']
+ - ['21']
+ - ['22']
+ - ['23']
+ - ['24']
+ - ['25']
+ - ['26']
+ - ['27']
+ - ['28']
+ - ['29']
+ - ['3']
+ - ['30']
+ - ['31']
+ - ['32']
+ - ['33']
+ - ['34']
+ - ['35']
+ - ['36']
+ - ['37']
+ - ['38']
+ - ['39']
+ - ['4']
+ - ['40']
+ - ['41']
+ - ['42']
+ - ['43']
+ - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(box.tuple.new(tostring(44)), {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['44']
+ - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(box.tuple.new(tostring(44)), {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['45']
+ - ['46']
+ - ['47']
+ - ['48']
+ - ['49']
+ - ['5']
+ - ['50']
+ - ['51']
+ - ['52']
+ - ['53']
+ - ['54']
+ - ['55']
+ - ['56']
+ - ['57']
+ - ['58']
+ - ['59']
+ - ['6']
+ - ['60']
+ - ['61']
+ - ['62']
+ - ['63']
+ - ['64']
+ - ['65']
+ - ['66']
+ - ['67']
+ - ['68']
+ - ['69']
+ - ['7']
+ - ['70']
+ - ['71']
+ - ['72']
+ - ['73']
+ - ['74']
+ - ['75']
+ - ['76']
+ - ['77']
+ - ['78']
+ - ['79']
+ - ['8']
+ - ['80']
+ - ['81']
+ - ['82']
+ - ['83']
+ - ['84']
+ - ['85']
+ - ['86']
+ - ['87']
+ - ['88']
+ - ['89']
+ - ['9']
+ - ['90']
+ - ['91']
+ - ['92']
+ - ['93']
+ - ['94']
+ - ['95']
+ - ['96']
+ - ['97']
+ - ['98']
+ - ['99']
+...
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['99']
+ - ['98']
+ - ['97']
+ - ['96']
+ - ['95']
+ - ['94']
+ - ['93']
+ - ['92']
+ - ['91']
+ - ['90']
+ - ['9']
+ - ['89']
+ - ['88']
+ - ['87']
+ - ['86']
+ - ['85']
+ - ['84']
+ - ['83']
+ - ['82']
+ - ['81']
+ - ['80']
+ - ['8']
+ - ['79']
+ - ['78']
+ - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs(box.tuple.new(tostring(77)), {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['99']
+ - ['98']
+ - ['97']
+ - ['96']
+ - ['95']
+ - ['94']
+ - ['93']
+ - ['92']
+ - ['91']
+ - ['90']
+ - ['9']
+ - ['89']
+ - ['88']
+ - ['87']
+ - ['86']
+ - ['85']
+ - ['84']
+ - ['83']
+ - ['82']
+ - ['81']
+ - ['80']
+ - ['8']
+ - ['79']
+ - ['78']
+ - ['77']
+ - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+t = {} for state, v in i:pairs(box.tuple.new(tostring(77)), {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['76']
+ - ['75']
+ - ['74']
+ - ['73']
+ - ['72']
+ - ['71']
+ - ['70']
+ - ['7']
+ - ['69']
+ - ['68']
+ - ['67']
+ - ['66']
+ - ['65']
+ - ['64']
+ - ['63']
+ - ['62']
+ - ['61']
+ - ['60']
+ - ['6']
+ - ['59']
+ - ['58']
+ - ['57']
+ - ['56']
+ - ['55']
+ - ['54']
+ - ['53']
+ - ['52']
+ - ['51']
+ - ['50']
+ - ['5']
+ - ['49']
+ - ['48']
+ - ['47']
+ - ['46']
+ - ['45']
+ - ['44']
+ - ['43']
+ - ['42']
+ - ['41']
+ - ['40']
+ - ['4']
+ - ['39']
+ - ['38']
+ - ['37']
+ - ['36']
+ - ['35']
+ - ['34']
+ - ['33']
+ - ['32']
+ - ['31']
+ - ['30']
+ - ['3']
+ - ['29']
+ - ['28']
+ - ['27']
+ - ['26']
+ - ['25']
+ - ['24']
+ - ['23']
+ - ['22']
+ - ['21']
+ - ['20']
+ - ['2']
+ - ['19']
+ - ['18']
+ - ['17']
+ - ['16']
+ - ['15']
+ - ['14']
+ - ['13']
+ - ['12']
+ - ['11']
+ - ['100']
+ - ['10']
+ - ['1']
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+i:pairs({}, {iterator = 666 })
+---
+- error: Illegal parameters, Invalid iterator type
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:replace({1})
+---
+- [1]
+...
+s:replace({2})
+---
+- [2]
+...
+s:replace({3})
+---
+- [3]
+...
+s:replace({4})
+---
+- [4]
+...
+s:pairs(2, { iterator = 'GE' }):totable()
+---
+- - [2]
+ - [3]
+ - [4]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a')
+---
+...
+s:auto_increment{1}
+---
+- [1, 1]
+...
+s:auto_increment{2}
+---
+- [2, 2]
+...
+s:auto_increment{3}
+---
+- [3, 3]
+...
+s:auto_increment{4}
+---
+- [4, 4]
+...
+s:auto_increment{5}
+---
+- [5, 5]
+...
+s:pairs(3, 'GE'):totable()
+---
+- - [3, 3]
+ - [4, 4]
+ - [5, 5]
+...
+i:pairs(3, 'GE'):totable()
+---
+- - [3, 3]
+ - [4, 4]
+ - [5, 5]
+...
+s:pairs(3, {iterator = 'GE' }):totable()
+---
+- - [3, 3]
+ - [4, 4]
+ - [5, 5]
+...
+i:pairs(3, {iterator = 'GE' }):totable()
+---
+- - [3, 3]
+ - [4, 4]
+ - [5, 5]
+...
+s:pairs(3, 'EQ'):totable()
+---
+- - [3, 3]
+...
+i:pairs(3, 'EQ'):totable()
+---
+- - [3, 3]
+...
+s:pairs(3, {iterator = 'EQ' }):totable()
+---
+- - [3, 3]
+...
+i:pairs(3, {iterator = 'EQ' }):totable()
+---
+- - [3, 3]
+...
+s:pairs(3, 'GT'):totable()
+---
+- - [4, 4]
+ - [5, 5]
+...
+i:pairs(3, 'GT'):totable()
+---
+- - [4, 4]
+ - [5, 5]
+...
+s:pairs(3, {iterator = 'GT' }):totable()
+---
+- - [4, 4]
+ - [5, 5]
+...
+i:pairs(3, {iterator = 'GT' }):totable()
+---
+- - [4, 4]
+ - [5, 5]
+...
+i:select({3}, 'LE')
+---
+- - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+s:select({3}, 'LE')
+---
+- - [3, 3]
+ - [2, 2]
+ - [1, 1]
+...
+i:count({3}, 'GT')
+---
+- 2
+...
+s:count({3}, 'GT')
+---
+- 2
+...
+s:drop()
+---
+...
+-- implement lazy iterator positioning
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+---
+...
+itr1,itr2,itr3 = s:pairs{2}
+---
+...
+_ = s:replace{1, 4}
+---
+...
+r = {}
+---
+...
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+---
+...
+r
+---
+- - [2, 1]
+ - [2, 2]
+ - [2, 3]
+...
+itr1,itr2,itr3 = s:pairs({2}, {iterator = 'GE'})
+---
+...
+_ = s:replace{1, 5}
+---
+...
+r = {}
+---
+...
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+---
+...
+r
+---
+- - [2, 1]
+ - [2, 2]
+ - [2, 3]
+ - [3, 1]
+ - [3, 2]
+ - [3, 3]
+...
+itr1,itr2,itr3 = s:pairs({2}, {iterator = 'REQ'})
+---
+...
+s:replace{2, 4}
+---
+- [2, 4]
+...
+r = {}
+---
+...
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+---
+...
+r
+---
+- - [2, 4]
+ - [2, 3]
+ - [2, 2]
+ - [2, 1]
+...
+r = nil
+---
+...
+s:drop()
+---
+...
+-- make tree iterators stable
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for i = 1,10 do s:replace{i} end
+---
+...
+r = {}
+---
+...
+for k,v in s:pairs{} do table.insert(r, v[1]) s:delete(v[1]) end
+---
+...
+r
+---
+- - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+...
+s:select{}
+---
+- []
+...
+for i = 1,10 do s:replace{i} end
+---
+...
+r = {}
+---
+...
+for k,v in s:pairs({}, {iterator = 'REQ'}) do table.insert(r, v[1]) s:delete(v[1]) end
+---
+...
+r
+---
+- - 10
+ - 9
+ - 8
+ - 7
+ - 6
+ - 5
+ - 4
+ - 3
+ - 2
+ - 1
+...
+s:select{}
+---
+- []
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+---
+...
+r = {}
+---
+...
+for k,v in s:pairs{2} do table.insert(r, v) s:delete{v[1], v[2]} end
+---
+...
+r
+---
+- - [2, 1]
+ - [2, 2]
+ - [2, 3]
+...
+s:select{}
+---
+- - [1, 1]
+ - [1, 2]
+ - [1, 3]
+ - [3, 1]
+ - [3, 2]
+ - [3, 3]
+...
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+---
+...
+r = {}
+---
+...
+for k,v in s:pairs({3}, {iterator = 'REQ'}) do table.insert(r, v) s:delete{v[1], v[2]} end
+---
+...
+r
+---
+- - [3, 3]
+ - [3, 2]
+ - [3, 1]
+...
+s:select{}
+---
+- - [1, 1]
+ - [1, 2]
+ - [1, 3]
+ - [2, 1]
+ - [2, 2]
+ - [2, 3]
+...
+r = nil
+---
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({25})
+---
+...
+s:replace{25}
+---
+- [25]
+...
+state, value = gen(param,state)
+---
+...
+value
+---
+- [25]
+...
+state, value = gen(param,state)
+---
+...
+value
+---
+- null
+...
+gen,param,state = i:pairs({35})
+---
+...
+state, value = gen(param,state)
+---
+...
+value
+---
+- null
+...
+s:replace{35}
+---
+- [35]
+...
+state, value = gen(param,state)
+---
+- error: 'builtin/box/schema.lua:1247: usage: next(state)'
+...
+value
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({30}, {iterator = 'GE'})
+---
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [42]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [50]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [60]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+state
+---
+- null
+...
+value
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({40}, {iterator = 'LE'})
+---
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [20]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [15]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [10]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+state
+---
+- null
+...
+value
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({28}, {iterator = 'GE'})
+---
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [42]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [50]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [60]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [80]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({42}, {iterator = 'LE'})
+---
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [20]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [15]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [10]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [0]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({20}, {iterator = 'GT'})
+---
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [42]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [50]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [60]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [80]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({50}, {iterator = 'LT'})
+---
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [20]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [15]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [10]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [0]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({28}, {iterator = 'GT'})
+---
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [42]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [50]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [60]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [80]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+---
+...
+gen,param,state = i:pairs({42}, {iterator = 'LT'})
+---
+...
+s:replace{0}
+---
+- [0]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [40]
+...
+s:replace{42}
+---
+- [42]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [30]
+...
+s:replace{15}
+---
+- [15]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [20]
+...
+s:replace{32}
+---
+- [32]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [15]
+...
+s:replace{80}
+---
+- [80]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [10]
+...
+state, value = gen(param, state)
+---
+...
+value
+---
+- [0]
+...
+gen(param, state)
+---
+- null
+...
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+---
+- null
+...
+s:drop()
+---
+...
+-- Ephemeral space: methods: delete
+-- delete (str)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:replace({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+for key = 1, 10 do s:delete({tostring(key)}) end
+---
+...
+for key = 1, 10 do assert(s:get({tostring(key)}) == nil) end
+---
+...
+s:delete({tostring(7)})
+---
+...
+s:drop()
+---
+...
+-- delete (num)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:replace({key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key})) end
+---
+...
+t
+---
+- - [1]
+ - [2]
+ - [3]
+ - [4]
+ - [5]
+ - [6]
+ - [7]
+ - [8]
+ - [9]
+ - [10]
+...
+for key = 1, 10 do s:delete({key}) end
+---
+...
+for key = 1, 10 do assert(s:get({key}) == nil) end
+---
+...
+s:delete({7})
+---
+...
+s:drop()
+---
+...
+-- delete multi-part (num, num)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+for key = 1, 10 do s:replace({key, key}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+---
+...
+t
+---
+- - [1, 1]
+ - [2, 2]
+ - [3, 3]
+ - [4, 4]
+ - [5, 5]
+ - [6, 6]
+ - [7, 7]
+ - [8, 8]
+ - [9, 9]
+ - [10, 10]
+...
+for key = 1, 10 do s:delete({key, key}) end
+---
+...
+for key = 1, 10 do assert(s:get({key, key}) == nil) end
+---
+...
+s:delete({7, 7})
+---
+...
+s:drop()
+---
+...
+-- delete (str)
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+for key = 1, 10 do s:replace({tostring(key)}) end
+---
+...
+t = {}
+---
+...
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+---
+...
+t
+---
+- - ['1']
+ - ['2']
+ - ['3']
+ - ['4']
+ - ['5']
+ - ['6']
+ - ['7']
+ - ['8']
+ - ['9']
+ - ['10']
+...
+for key = 1, 10 do s:delete(box.tuple.new{tostring(key)}) end
+---
+...
+for key = 1, 10 do assert(s:get({tostring(key)}) == nil) end
+---
+...
+s:delete(box.tuple.new{tostring(7)})
+---
+...
+s:drop()
+---
+...
+-- Ephemeral space: methods: bsize, len
+utils = dofile('utils.lua')
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+idx = s:create_index('a')
+---
+...
+for i = 1, 13 do s:insert{ i, string.rep('x', i) } end
+---
+...
+s:len()
+---
+- 13
+...
+s:bsize()
+---
+- 130
+...
+utils.space_bsize(s)
+---
+- 130
+...
+for i = 1, 13, 2 do s:delete{ i } end
+---
+...
+s:len()
+---
+- 6
+...
+s:bsize()
+---
+- 60
+...
+utils.space_bsize(s)
+---
+- 60
+...
+for i = 2, 13, 2 do s:update( { i }, {{ ":", 2, i, 0, string.rep('y', i) }} ) end
+---
+...
+s:len()
+---
+- 6
+...
+s:bsize()
+---
+- 102
+...
+utils.space_bsize(s)
+---
+- 102
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'INTEGER'} })
+---
+...
+s:insert({1, "AAAA"})
+---
+- [1, 'AAAA']
+...
+s:insert({2, "AAAA"})
+---
+- [2, 'AAAA']
+...
+s:insert({3, "AAAA"})
+---
+- [3, 'AAAA']
+...
+s:insert({4, "AAAA"})
+---
+- [4, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+...
+i:max(2)
+---
+- [2, 'AAAA']
+...
+i:min(2)
+---
+- [2, 'AAAA']
+...
+i:count(2)
+---
+- 1
+...
+i:max()
+---
+- [4, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({20, "AAAA"})
+---
+- [20, 'AAAA']
+...
+s:insert({30, "AAAA"})
+---
+- [30, 'AAAA']
+...
+s:insert({40, "AAAA"})
+---
+- [40, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(15)
+---
+...
+i:min(15)
+---
+...
+i:count(15)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 7
+...
+s:insert({-2, "AAAA"})
+---
+- [-2, 'AAAA']
+...
+s:insert({-3, "AAAA"})
+---
+- [-3, 'AAAA']
+...
+s:insert({-4, "AAAA"})
+---
+- [-4, 'AAAA']
+...
+i:select()
+---
+- - [-4, 'AAAA']
+ - [-3, 'AAAA']
+ - [-2, 'AAAA']
+ - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(0)
+---
+...
+i:min(0)
+---
+...
+i:count(0)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [-4, 'AAAA']
+...
+i:count()
+---
+- 10
+...
+s:drop()
+---
+...
+-- number type
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'number'} })
+---
+...
+s:insert({1, "AAAA"})
+---
+- [1, 'AAAA']
+...
+s:insert({2, "AAAA"})
+---
+- [2, 'AAAA']
+...
+s:insert({3, "AAAA"})
+---
+- [3, 'AAAA']
+...
+s:insert({4, "AAAA"})
+---
+- [4, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+...
+i:max(2)
+---
+- [2, 'AAAA']
+...
+i:min(2)
+---
+- [2, 'AAAA']
+...
+i:count(2)
+---
+- 1
+...
+i:max()
+---
+- [4, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({20, "AAAA"})
+---
+- [20, 'AAAA']
+...
+s:insert({30, "AAAA"})
+---
+- [30, 'AAAA']
+...
+s:insert({40, "AAAA"})
+---
+- [40, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(15)
+---
+...
+i:min(15)
+---
+...
+i:count(15)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 7
+...
+s:insert({-2, "AAAA"})
+---
+- [-2, 'AAAA']
+...
+s:insert({-3, "AAAA"})
+---
+- [-3, 'AAAA']
+...
+s:insert({-4, "AAAA"})
+---
+- [-4, 'AAAA']
+...
+i:select()
+---
+- - [-4, 'AAAA']
+ - [-3, 'AAAA']
+ - [-2, 'AAAA']
+ - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(0)
+---
+...
+i:min(0)
+---
+...
+i:count(0)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [-4, 'AAAA']
+...
+i:count()
+---
+- 10
+...
+s:insert({1.5, "AAAA"})
+---
+- [1.5, 'AAAA']
+...
+s:insert({2.5, "AAAA"})
+---
+- [2.5, 'AAAA']
+...
+s:insert({3.5, "AAAA"})
+---
+- [3.5, 'AAAA']
+...
+s:insert({4.5, "AAAA"})
+---
+- [4.5, 'AAAA']
+...
+i:select()
+---
+- - [-4, 'AAAA']
+ - [-3, 'AAAA']
+ - [-2, 'AAAA']
+ - [1, 'AAAA']
+ - [1.5, 'AAAA']
+ - [2, 'AAAA']
+ - [2.5, 'AAAA']
+ - [3, 'AAAA']
+ - [3.5, 'AAAA']
+ - [4, 'AAAA']
+ - [4.5, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(1)
+---
+- [1, 'AAAA']
+...
+i:min(1)
+---
+- [1, 'AAAA']
+...
+i:count(1)
+---
+- 1
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [-4, 'AAAA']
+...
+i:count()
+---
+- 14
+...
+s:drop()
+---
+...
+-- str type
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert({'1', "AAAA"})
+---
+- ['1', 'AAAA']
+...
+s:insert({'2', "AAAA"})
+---
+- ['2', 'AAAA']
+...
+s:insert({'3', "AAAA"})
+---
+- ['3', 'AAAA']
+...
+s:insert({'4', "AAAA"})
+---
+- ['4', 'AAAA']
+...
+i:select()
+---
+- - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['3', 'AAAA']
+ - ['4', 'AAAA']
+...
+i:max('2')
+---
+- ['2', 'AAAA']
+...
+i:min('2')
+---
+- ['2', 'AAAA']
+...
+i:count('2')
+---
+- 1
+...
+i:max()
+---
+- ['4', 'AAAA']
+...
+i:min()
+---
+- ['1', 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({'20', "AAAA"})
+---
+- ['20', 'AAAA']
+...
+s:insert({'30', "AAAA"})
+---
+- ['30', 'AAAA']
+...
+s:insert({'40', "AAAA"})
+---
+- ['40', 'AAAA']
+...
+i:select()
+---
+- - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max('15')
+---
+...
+i:min('15')
+---
+...
+i:count('15')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- ['1', 'AAAA']
+...
+i:count()
+---
+- 7
+...
+s:insert({'-2', "AAAA"})
+---
+- ['-2', 'AAAA']
+...
+s:insert({'-3', "AAAA"})
+---
+- ['-3', 'AAAA']
+...
+s:insert({'-4', "AAAA"})
+---
+- ['-4', 'AAAA']
+...
+i:select()
+---
+- - ['-2', 'AAAA']
+ - ['-3', 'AAAA']
+ - ['-4', 'AAAA']
+ - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max('0')
+---
+...
+i:min('0')
+---
+...
+i:count('0')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- ['-2', 'AAAA']
+...
+i:count()
+---
+- 10
+...
+s:drop()
+---
+...
+-- num type
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert({1, "AAAA"})
+---
+- [1, 'AAAA']
+...
+s:insert({2, "AAAA"})
+---
+- [2, 'AAAA']
+...
+s:insert({3, "AAAA"})
+---
+- [3, 'AAAA']
+...
+s:insert({4, "AAAA"})
+---
+- [4, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+...
+i:max(2)
+---
+- [2, 'AAAA']
+...
+i:min(2)
+---
+- [2, 'AAAA']
+...
+i:count(2)
+---
+- 1
+...
+i:max()
+---
+- [4, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({20, "AAAA"})
+---
+- [20, 'AAAA']
+...
+s:insert({30, "AAAA"})
+---
+- [30, 'AAAA']
+...
+s:insert({40, "AAAA"})
+---
+- [40, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(15)
+---
+...
+i:min(15)
+---
+...
+i:count(15)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 7
+...
+s:drop()
+---
+...
+-- scalar type
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar'} })
+---
+...
+s:insert({1, "AAAA"})
+---
+- [1, 'AAAA']
+...
+s:insert({2, "AAAA"})
+---
+- [2, 'AAAA']
+...
+s:insert({3, "AAAA"})
+---
+- [3, 'AAAA']
+...
+s:insert({4, "AAAA"})
+---
+- [4, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+...
+i:max(2)
+---
+- [2, 'AAAA']
+...
+i:min(2)
+---
+- [2, 'AAAA']
+...
+i:count(2)
+---
+- 1
+...
+i:max()
+---
+- [4, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 4
+...
+s:insert({20, "AAAA"})
+---
+- [20, 'AAAA']
+...
+s:insert({30, "AAAA"})
+---
+- [30, 'AAAA']
+...
+s:insert({40, "AAAA"})
+---
+- [40, 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+...
+i:max(15)
+---
+...
+i:min(15)
+---
+...
+i:count(15)
+---
+- 0
+...
+i:max()
+---
+- [40, 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 7
+...
+s:insert({'1', "AAAA"})
+---
+- ['1', 'AAAA']
+...
+s:insert({'2', "AAAA"})
+---
+- ['2', 'AAAA']
+...
+s:insert({'3', "AAAA"})
+---
+- ['3', 'AAAA']
+...
+s:insert({'4', "AAAA"})
+---
+- ['4', 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+ - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['3', 'AAAA']
+ - ['4', 'AAAA']
+...
+i:max('2')
+---
+- ['2', 'AAAA']
+...
+i:min('2')
+---
+- ['2', 'AAAA']
+...
+i:count('2')
+---
+- 1
+...
+i:max()
+---
+- ['4', 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 11
+...
+s:insert({'20', "AAAA"})
+---
+- ['20', 'AAAA']
+...
+s:insert({'30', "AAAA"})
+---
+- ['30', 'AAAA']
+...
+s:insert({'40', "AAAA"})
+---
+- ['40', 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+ - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max('15')
+---
+...
+i:min('15')
+---
+...
+i:count('15')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 14
+...
+s:insert({'-2', "AAAA"})
+---
+- ['-2', 'AAAA']
+...
+s:insert({'-3', "AAAA"})
+---
+- ['-3', 'AAAA']
+...
+s:insert({'-4', "AAAA"})
+---
+- ['-4', 'AAAA']
+...
+i:select()
+---
+- - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+ - ['-2', 'AAAA']
+ - ['-3', 'AAAA']
+ - ['-4', 'AAAA']
+ - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max('0')
+---
+...
+i:min('0')
+---
+...
+i:count('0')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- [1, 'AAAA']
+...
+i:count()
+---
+- 17
+...
+s:insert({-2, "AAAA"})
+---
+- [-2, 'AAAA']
+...
+s:insert({-3, "AAAA"})
+---
+- [-3, 'AAAA']
+...
+s:insert({-4, "AAAA"})
+---
+- [-4, 'AAAA']
+...
+i:select()
+---
+- - [-4, 'AAAA']
+ - [-3, 'AAAA']
+ - [-2, 'AAAA']
+ - [1, 'AAAA']
+ - [2, 'AAAA']
+ - [3, 'AAAA']
+ - [4, 'AAAA']
+ - [20, 'AAAA']
+ - [30, 'AAAA']
+ - [40, 'AAAA']
+ - ['-2', 'AAAA']
+ - ['-3', 'AAAA']
+ - ['-4', 'AAAA']
+ - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max(0)
+---
+...
+i:min(0)
+---
+...
+i:count(0)
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- [-4, 'AAAA']
+...
+i:count()
+---
+- 20
+...
+s:drop()
+---
+...
+-- multi filed indices
+-- scalar int
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'INTEGER'} })
+---
+...
+s:insert({1, 1})
+---
+- [1, 1]
+...
+s:insert({1, 2})
+---
+- [1, 2]
+...
+s:insert({1, 3})
+---
+- [1, 3]
+...
+s:insert({1, -4})
+---
+- [1, -4]
+...
+i:select()
+---
+- - [1, -4]
+ - [1, 1]
+ - [1, 2]
+ - [1, 3]
+...
+i:max({1})
+---
+- [1, 3]
+...
+i:min({1})
+---
+- [1, -4]
+...
+i:count({1})
+---
+- 4
+...
+i:max({1, 0})
+---
+...
+i:min({1, 1})
+---
+- [1, 1]
+...
+i:count({1})
+---
+- 4
+...
+i:max()
+---
+- [1, 3]
+...
+i:min()
+---
+- [1, -4]
+...
+i:count()
+---
+- 4
+...
+s:insert({2, 1})
+---
+- [2, 1]
+...
+s:insert({2, 2})
+---
+- [2, 2]
+...
+s:insert({2, 3})
+---
+- [2, 3]
+...
+s:insert({2, -4})
+---
+- [2, -4]
+...
+i:select()
+---
+- - [1, -4]
+ - [1, 1]
+ - [1, 2]
+ - [1, 3]
+ - [2, -4]
+ - [2, 1]
+ - [2, 2]
+ - [2, 3]
+...
+i:max({2})
+---
+- [2, 3]
+...
+i:min({2})
+---
+- [2, -4]
+...
+i:count({2})
+---
+- 4
+...
+i:max({2, 0})
+---
+...
+i:min({2, 1})
+---
+- [2, 1]
+...
+i:count({2})
+---
+- 4
+...
+i:max()
+---
+- [2, 3]
+...
+i:min()
+---
+- [1, -4]
+...
+i:count()
+---
+- 8
+...
+s:drop()
+---
+...
+-- scalar str
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'string'} })
+---
+...
+s:insert({1, '1'})
+---
+- [1, '1']
+...
+s:insert({1, '2'})
+---
+- [1, '2']
+...
+s:insert({1, '3'})
+---
+- [1, '3']
+...
+s:insert({1, '-4'})
+---
+- [1, '-4']
+...
+i:select()
+---
+- - [1, '-4']
+ - [1, '1']
+ - [1, '2']
+ - [1, '3']
+...
+i:max({1})
+---
+- [1, '3']
+...
+i:min({1})
+---
+- [1, '-4']
+...
+i:count({1})
+---
+- 4
+...
+i:max({1, '0'})
+---
+...
+i:min({1, '1'})
+---
+- [1, '1']
+...
+i:count({1})
+---
+- 4
+...
+i:max()
+---
+- [1, '3']
+...
+i:min()
+---
+- [1, '-4']
+...
+i:count()
+---
+- 4
+...
+s:insert({2, '1'})
+---
+- [2, '1']
+...
+s:insert({2, '2'})
+---
+- [2, '2']
+...
+s:insert({2, '3'})
+---
+- [2, '3']
+...
+s:insert({2, '-4'})
+---
+- [2, '-4']
+...
+i:select()
+---
+- - [1, '-4']
+ - [1, '1']
+ - [1, '2']
+ - [1, '3']
+ - [2, '-4']
+ - [2, '1']
+ - [2, '2']
+ - [2, '3']
+...
+i:max({2})
+---
+- [2, '3']
+...
+i:min({2})
+---
+- [2, '-4']
+...
+i:count({2})
+---
+- 4
+...
+i:max({2, '0'})
+---
+...
+i:min({2, '1'})
+---
+- [2, '1']
+...
+i:count({2})
+---
+- 4
+...
+i:max()
+---
+- [2, '3']
+...
+i:min()
+---
+- [1, '-4']
+...
+i:count()
+---
+- 8
+...
+s:drop()
+---
+...
+-- min max count after many inserts
+string = require('string')
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar'} })
+---
+...
+long_string = string.rep('A', 650)
+---
+...
+for i = 1, 1000 do s:insert({i, long_string}) end
+---
+...
+i:max({100})
+---
+- [100, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:max({700})
+---
+- [700, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:min({100})
+---
+- [100, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:min({700})
+---
+- [700, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:count({2})
+---
+- 1
+...
+i:max()
+---
+- [1000, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:min()
+---
+- [1, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:count()
+---
+- 1000
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'INTEGER'} })
+---
+...
+for i = 1, 1000 do s:insert({i % 10, i, long_string}) end
+---
+...
+i:max({1, 100})
+---
+...
+i:max({2, 700})
+---
+...
+i:max({3})
+---
+- [3, 993, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:min({1, 10})
+---
+...
+i:min({1, 700})
+---
+...
+i:min({3})
+---
+- [3, 3, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:count({2})
+---
+- 100
+...
+i:max()
+---
+- [9, 999, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:min()
+---
+- [0, 10, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA']
+...
+i:count()
+---
+- 1000
+...
+s:drop()
+---
+...
+test_run:cmd("restart server default")
diff --git a/test/box/ephemeral_space.test.lua b/test/box/ephemeral_space.test.lua
index 211014c..ee03810 100644
--- a/test/box/ephemeral_space.test.lua
+++ b/test/box/ephemeral_space.test.lua
@@ -1,3 +1,4 @@
+test_run = require('test_run').new()
-- Ephemeral space: creation and dropping.
-- Simple creation.
@@ -168,3 +169,1696 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {table = false})
s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = box.NULL})
s:frommap({ddd = 1, aaa = 2, ccc = 3, bbb = 4}, {dummy = true})
s:drop()
+
+
+-- Ephemeral space: methods: insert
+s = box.schema.space.create_ephemeral({field_count = 3})
+i = s:create_index('a')
+s:insert{1}
+s:insert{2,2}
+s:insert{3,3,3}
+s:insert{4,4,4,4}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:insert({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+s:insert({tostring(7)})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+for key = 1, 10 do s:insert({key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+s:insert({7})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 10 do s:insert({key, key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+s:insert({7, 7})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:insert({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+s:insert(box.tuple.new{tostring(7)})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+index = s:create_index('a')
+s:insert(1)
+s:insert(1, 2)
+s:insert(1, 2, 3)
+s:insert{1}
+s:insert{2, 3}
+tmp = s:delete(1, 2, 3)
+s:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {3, 'unsigned'} })
+s:insert{1}
+s:insert{2, 3}
+s:insert{4, 5, 6}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert{"1"}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert{1}
+s:drop()
+
+
+-- Ephemeral space: methods: replace
+s = box.schema.space.create_ephemeral({field_count = 3})
+i = s:create_index('a')
+s:replace{1}
+s:replace{2, 2}
+s:replace{3, 3, 3}
+s:replace{4, 4, 4, 4}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:replace({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+_ = s:replace({tostring(7)})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+for key = 1, 10 do s:replace({key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+_ = s:replace({7})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 10 do s:replace({key, key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+s:replace({7, 7})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:replace({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+s:replace(box.tuple.new{tostring(7)})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+index = s:create_index('a')
+s:replace(1)
+s:replace(1, 2)
+s:replace(1, 2, 3)
+s:replace{1}
+s:replace{2, 3}
+tmp = s:delete(1, 2, 3)
+s:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {3, 'unsigned'} })
+s:replace{1}
+s:replace{2, 3}
+s:replace{4, 5, 6}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{"1"}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:replace{1}
+s:drop()
+
+
+-- Ephemeral space: methods: upsert
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:upsert({1, 0}, {{'+', 2, 1}})
+s:get{1}
+s:upsert({1, 0}, {{'+', 2, 1}})
+s:get{1}
+s:upsert({1, 0}, {{'+', 1, 1}})
+s:get{1}
+s:get{2}
+
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 1}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 10}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+for key = 1, 10 do s:delete({tostring(key)}) end
+for key = 1, 10 do s:upsert({tostring(key), 0}, {{'+', 2, 1}, {'=', 3, key}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 1}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 10}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+for key = 1, 10 do s:delete({key}) end
+for key = 1, 10 do s:upsert({key, 0}, {{'+', 2, 1}, {'=', 3, key}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 1}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 10}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+for key = 1, 10 do s:delete({key, key}) end
+for key = 1, 10 do s:upsert({key, key, 0}, {{'+', 3, 1}, {'=', 4, key}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+s:drop()
+
+test_run:cmd("setopt delimiter ';'");
+function less(a, b)
+ if type(a[2]) ~= type(b[2]) then
+ return type(a[2]) < type(b[2])
+ end
+ if a[2] == b[2] then
+ return a[1] < b[1]
+ end
+ if type(a[2]) == 'boolean' then
+ return a[2] == false and b[2] == true
+ end
+ return a[2] < b[2]
+end;
+test_run:cmd("setopt delimiter ''");
+function sort(t) table.sort(t, less) return t end
+
+-- upsert default tuple constraint
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+s:upsert({0, 'key', 0}, {{'+', 3, 1}})
+s:drop()
+
+-- upsert primary key modify (skipped)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:upsert({0, 0}, {{'+', 1, 1}, {'+', 2, 1}})
+s:get({0})
+s:drop()
+
+-- upsert with box.tuple.new
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:upsert({0, 0}, {{'+', 1, 1}, {'+', 2, 1}})
+s:get({0})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 1}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 10}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+for key = 1, 10 do s:delete({key, key}) end
+for key = 1, 10 do s:upsert(box.tuple.new{key, key, 0}, box.tuple.new{{'+', 3, 1}, {'=', 4, key}}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+s:upsert({0, 0}, {{'+', 2, 2}})
+s:select{0}
+tmp = s:delete{0}
+s:upsert({0, 0, 0}, {{'+', 2, 2}})
+s:select{0}
+tmp = s:delete{0}
+s:upsert({0}, {{'+', 2, 2}})
+s:select{0}
+s:replace{0, 1, 2, 4}
+s:upsert({0, 0, "you will not see it"}, {{'+', 2, 2}})
+s:select{0}
+s:replace{0, -0x4000000000000000ll}
+s:upsert({0}, {{'+', 2, -0x4000000000000001ll}}) -- overflow
+s:select{0}
+s:replace{0, "thing"}
+s:upsert({0, "nothing"}, {{'+', 2, 2}})
+s:select{0}
+tmp = s:delete{0}
+s:upsert({0, "thing"}, {{'+', 2, 2}})
+s:select{0}
+s:replace{0, 1, 2}
+s:upsert({0}, {{'!', 42, 42}})
+s:select{0}
+s:upsert({0}, {{'#', 42, 42}})
+s:select{0}
+s:upsert({0}, {{'=', 42, 42}})
+s:select{}
+s:replace{0, 1.5}
+s:select{}
+s:upsert({0}, {{'|', 1, 255}})
+s:select{0}
+s:replace{0, 1.5}
+s:replace{0, 'something to splice'}
+s:upsert({0}, {{':', 2, 1, 4, 'no'}})
+s:select{0}
+s:upsert({0}, {{':', 2, 1, 2, 'every'}})
+s:select{0}
+s:upsert({0}, {{':', 2, -100, 2, 'every'}})
+s:select{0}
+s:drop()
+
+s = box.schema.space.create_ephemeral({ field_count = 1 })
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert({1})
+s:select{}
+s:upsert({2, 2}, {{'+', 2, 1}})
+s:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral({ field_count = 2 })
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert({1, 1})
+s:select{}
+s:upsert({2, 2, 2}, {{'+', 3, 1}})
+s:upsert({3, 3}, {{'+', 2, 1}})
+s:select{}
+s:drop()
+
+test_run:cmd("setopt delimiter ';'")
+function anything_to_string(tab)
+ if tab == nil then
+ return 'nil'
+ end
+ local str = '['
+ local first_route = true
+ local t = 0
+ for k,f in pairs(tab) do
+ if not first_route then str = str .. ',' end
+ first_route = false
+ t = t + 1
+ if k ~= t then
+ str = str .. k .. '='
+ end
+ if type(f) == 'string' then
+ str = str .. "'" .. f .. "'"
+ elseif type (f) == 'number' then
+ str = str .. tostring(f)
+ elseif type (f) == 'table' or type (f) == 'cdata' then
+ str = str .. anything_to_string(f)
+ else
+ str = str .. '?'
+ end
+ end
+ str = str .. ']'
+ return str
+end;
+
+function things_equal(var1, var2)
+ local type1 = type(var1) == 'cdata' and 'table' or type(var1)
+ local type2 = type(var2) == 'cdata' and 'table' or type(var2)
+ if type1 ~= type2 then
+ return false
+ end
+ if type1 ~= 'table' then
+ return var1 == var2
+ end
+ for k,v in pairs(var1) do
+ if not things_equal(v, var2[k]) then
+ return false
+ end
+ end
+ for k,v in pairs(var2) do
+ if not things_equal(v, var1[k]) then
+ return false
+ end
+ end
+ return true
+end;
+
+function copy_thing(t)
+ if type(t) ~= 'table' then
+ return t
+ end
+ local res = {}
+ for k,v in pairs(t) do
+ res[copy_thing(k)] = copy_thing(v)
+ end
+ return res
+end;
+
+function test(space, key_tuple, ops, expect)
+ space:upsert(key_tuple, ops)
+ if (things_equal(space:select{}, expect)) then
+ return 'upsert('.. anything_to_string(key_tuple) .. ', ' ..
+ anything_to_string(ops) .. ', ' ..
+ ') OK ' .. anything_to_string(space:select{})
+ end
+ return 'upsert('.. anything_to_string(key_tuple) .. ', ' ..
+ anything_to_string(ops) .. ', ' ..
+ ') FAILED, got ' .. anything_to_string(space:select{}) ..
+ ' expected ' .. anything_to_string(expect)
+end;
+test_run:cmd("setopt delimiter ''");
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:upsert({1}, {{'!', 2, 100}}) -- must fail on checking tuple
+s:upsert({'a'}, {{'a', 2, 100}}) -- must fail on checking ops
+s:upsert({'a'}, {{'!', 2, 'ups1'}}) -- 'fast' upsert via insert in one index
+s:upsert({'a', 'b'}, {{'!', 2, 'ups2'}}) -- 'fast' upsert via update in one index
+s:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert({1, 1, 1})
+s:insert({2, 2, 2})
+s:insert({3, 3, 3})
+s:select{}
+s:upsert({2, 18, 76}, {})
+s:upsert({4, 4, 4}, {})
+s:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+
+t = {1, '1', 1, 'qwerty'}
+s:insert(t)
+
+-- all good operations, one op, equivalent to update
+test(s, t, {{'+', 3, 5}}, {{1, '1', 6, 'qwerty'}})
+test(s, t, {{'-', 3, 3}}, {{1, '1', 3, 'qwerty'}})
+test(s, t, {{'&', 3, 5}}, {{1, '1', 1, 'qwerty'}})
+test(s, t, {{'|', 3, 8}}, {{1, '1', 9, 'qwerty'}})
+test(s, t, {{'^', 3, 12}}, {{1, '1', 5, 'qwerty'}})
+test(s, t, {{':', 4, 2, 4, "uer"}}, {{1, '1', 5, 'query'}})
+test(s, t, {{'!', 4, 'answer'}}, {{1, '1', 5, 'answer', 'query'}})
+test(s, t, {{'#', 5, 1}}, {{1, '1', 5, 'answer'}})
+test(s, t, {{'!', -1, 1}}, {{1, '1', 5, 'answer', 1}})
+test(s, t, {{'!', -1, 2}}, {{1, '1', 5, 'answer', 1, 2}})
+test(s, t, {{'!', -1, 3}}, {{1, '1', 5, 'answer', 1, 2 ,3}})
+test(s, t, {{'#', 5, 100500}}, {{1, '1', 5, 'answer'}})
+test(s, t, {{'=', 4, 'qwerty'}}, {{1, '1', 5, 'qwerty'}})
+
+-- same check for negative posistion
+test(s, t, {{'+', -2, 5}}, {{1, '1', 10, 'qwerty'}})
+test(s, t, {{'-', -2, 3}}, {{1, '1', 7, 'qwerty'}})
+test(s, t, {{'&', -2, 5}}, {{1, '1', 5, 'qwerty'}})
+test(s, t, {{'|', -2, 8}}, {{1, '1', 13, 'qwerty'}})
+test(s, t, {{'^', -2, 12}}, {{1, '1', 1, 'qwerty'}})
+test(s, t, {{':', -1, 2, 4, "uer"}}, {{1, '1', 1, 'query'}})
+test(s, t, {{'!', -2, 'answer'}}, {{1, '1', 1, 'answer', 'query'}})
+test(s, t, {{'#', -1, 1}}, {{1, '1', 1, 'answer'}})
+test(s, t, {{'=', -1, 'answer!'}}, {{1, '1', 1, 'answer!'}})
+
+-- selective test for good multiple ops
+test(s, t, {{'+', 3, 2}, {'!', 4, 42}}, {{1, '1', 3, 42, 'answer!'}})
+test(s, t, {{'!', 1, 666}, {'#', 1, 1}, {'+', 3, 2}}, {{1, '1', 5, 42, 'answer!'}})
+test(s, t, {{'!', 3, 43}, {'+', 4, 2}}, {{1, '1', 43, 7, 42, 'answer!'}})
+test(s, t, {{'#', 3, 2}, {'=', 3, 1}, {'=', 4, '1'}}, {{1, '1', 1, '1'}})
+
+-- all bad operations, one op, equivalent to update but error is supressed
+test(s, t, {{'+', 4, 3}}, {{1, '1', 1, '1'}})
+test(s, t, {{'-', 4, 3}}, {{1, '1', 1, '1'}})
+test(s, t, {{'&', 4, 1}}, {{1, '1', 1, '1'}})
+test(s, t, {{'|', 4, 1}}, {{1, '1', 1, '1'}})
+test(s, t, {{'^', 4, 1}}, {{1, '1', 1, '1'}})
+test(s, t, {{':', 3, 2, 4, "uer"}}, {{1, '1', 1, '1'}})
+test(s, t, {{'!', 18, 'answer'}}, {{1, '1', 1, '1'}})
+test(s, t, {{'#', 18, 1}}, {{1, '1', 1, '1'}})
+test(s, t, {{'=', 18, 'qwerty'}}, {{1, '1', 1, '1'}})
+
+-- selective test for good/bad multiple ops mix
+test(s, t, {{'+', 3, 1}, {'+', 4, 1}}, {{1, '1', 2, '1'}})
+test(s, t, {{'-', 4, 1}, {'-', 3, 1}}, {{1, '1', 1, '1'}})
+test(s, t, {{'#', 18, 1}, {'|', 3, 14}, {'!', 18, '!'}}, {{1, '1', 15, '1'}})
+test(s, t, {{'^', 42, 42}, {':', 1, 1, 1, ''}, {'^', 3, 8}}, {{1, '1', 7, '1'}})
+test(s, t, {{'&', 3, 1}, {'&', 2, 1}, {'&', 4, 1}}, {{1, '1', 1, '1'}})
+
+-- broken ops must raise an exception and discarded
+'dump ' .. anything_to_string(s:select{})
+test(s, t, {{'&', 'a', 3}, {'+', 3, 3}}, {{1, '1', 1, '1'}})
+test(s, t, {{'+', 3, 3}, {'&', 3, 'a'}}, {{1, '1', 1, '1'}})
+test(s, t, {{'+', 3}, {'&', 3, 'a'}}, {{1, '1', 1, '1'}})
+test(s, t, {{':', 3, 3}}, {{1, '1', 1, '1'}})
+test(s, t, {{':', 3, 3, 3}}, {{1, '1', 1, '1'}})
+test(s, t, {{'?', 3, 3}}, {{1, '1', 1, '1'}})
+'dump ' .. anything_to_string(s:select{})
+
+-- -- ignoring ops for insert upsert
+test(s, {2, '2', 2, '2'}, {{}}, {{1, '1', 1, '1'}})
+test(s, {3, '3', 3, '3'}, {{'+', 3, 3}}, {{1, '1', 1, '1'}, {3, '3', 3, '3'}})
+
+t[1] = 1
+test(s, t, {{'+', 3, 3}, {'+', 4, 3}}, {{1, '1', 4, '1'}, {3, '3', 3, '3'}})
+t[1] = 2
+test(s, t, {{'-', 4, 1}}, {{1, '1', 4, '1'}, {2, '1', 1, 'qwerty'}, {3, '3', 3, '3'}})
+t[1] = 3
+test(s, t, {{':', 3, 3, 3, ''}, {'|', 3, 4}}, {{1, '1', 4, '1'}, {2, '1', 1, 'qwerty'}, {3, '3', 7, '3'}})
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+s:replace({1, 1, 1})
+box.snapshot()
+s:upsert({1, 1}, {{'+', 2, 2}})
+s:upsert({1, 1}, {{'+', 3, 4}})
+s:select()
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+s:upsert({1}, {})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', {parts = {1, 'unsigned', 3, 'unsigned'}})
+s:upsert({100, 100, 100}, {{'+', 2, 200}})
+s:upsert({200, 100, 200}, {{'+', 2, 300}})
+s:upsert({300, 100, 300}, {{'+', 2, 400}})
+i:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', {parts = {2, 'unsigned', 3, 'unsigned'}})
+s:upsert({100, 100, 100}, {{'+', 1, 200}})
+s:upsert({200, 100, 200}, {{'+', 1, 300}})
+s:upsert({300, 100, 300}, {{'+', 1, 400}})
+i:select{}
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', {parts = {3, 'unsigned', 2, 'unsigned'}})
+s:upsert({100, 100, 100}, {{'+', 1, 200}})
+s:upsert({200, 100, 200}, {{'+', 1, 300}})
+s:upsert({300, 100, 300}, {{'+', 1, 400}})
+i:select{}
+s:drop()
+
+
+-- Ephemeral index: methods: update
+
+s = box.schema.space.create_ephemeral()
+
+-- test delete field
+i = s:create_index('a')
+s:insert{1000001, 1000002, 1000003, 1000004, 1000005}
+s:update({1000001}, {{'#', 1, 1}})
+s:update({1000001}, {{'#', 1, "only one record please"}})
+i:drop()
+
+-- test arithmetic
+i = s:create_index('a')
+s:insert{1, 0}
+s:update(1, {{'+', 2, 10}})
+s:update(1, {{'+', 2, 15}})
+s:update(1, {{'-', 2, 5}})
+s:update(1, {{'-', 2, 20}})
+s:update(1, {{'|', 2, 0x9}})
+s:update(1, {{'|', 2, 0x6}})
+s:update(1, {{'&', 2, 0xabcde}})
+s:update(1, {{'&', 2, 0x2}})
+s:update(1, {{'^', 2, 0xa2}})
+s:update(1, {{'^', 2, 0xa2}})
+i:drop()
+
+-- test delete multiple fields
+i = s:create_index('a')
+s:insert{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
+s:update({0}, {{'#', 42, 1}})
+s:update({0}, {{'#', 4, 'abirvalg'}})
+s:update({0}, {{'#', 2, 1}, {'#', 4, 2}, {'#', 6, 1}})
+s:update({0}, {{'#', 4, 3}})
+s:update({0}, {{'#', 5, 123456}})
+s:update({0}, {{'#', 3, 4294967295}})
+s:update({0}, {{'#', 2, 0}})
+i:drop()
+
+-- test insert field
+i = s:create_index('a')
+s:insert{1, 3, 6, 9}
+s:update({1}, {{'!', 2, 2}})
+s:update({1}, {{'!', 4, 4}, {'!', 4, 5}, {'!', 5, 7}, {'!', 5, 8}})
+s:update({1}, {{'!', 10, 10}, {'!', 10, 11}, {'!', 10, 12}})
+i:drop()
+
+i = s:create_index('a')
+s:insert{1, 'tuple'}
+s:update({1}, {{'#', 2, 1}, {'!', 2, 'inserted tuple'}, {'=', 3, 'set tuple'}})
+i:drop()
+
+i = s:create_index('a')
+s:insert{1, 'tuple'}
+s:update({1}, {{'=', 2, 'set tuple'}, {'!', 2, 'inserted tuple'}, {'#', 3, 1}})
+s:update({1}, {{'!', 1, 3}, {'!', 1, 2}})
+i:drop()
+
+-- test update's assign opearations
+i = s:create_index('a')
+s:replace{1, 'field string value'}
+s:update({1}, {{'=', 2, 'new field string value'}, {'=', 3, 42}, {'=', 4, 0xdeadbeef}})
+
+-- test multiple update opearations on the same field
+s:update({1}, {{'+', 3, 16}, {'&', 4, 0xffff0000}, {'|', 4, 0x0000a0a0}, {'^', 4, 0xffff00aa}})
+
+-- test update splice operation
+s:replace{1953719668, 'something to splice'}
+s:update(1953719668, {{':', 2, 1, 4, 'no'}})
+s:update(1953719668, {{':', 2, 1, 2, 'every'}})
+
+-- check an incorrect offset
+s:update(1953719668, {{':', 2, 100, 2, 'every'}})
+s:update(1953719668, {{':', 2, -100, 2, 'every'}})
+i:drop()
+
+i = s:create_index('a')
+s:insert{1953719668, 'hello', 'october', '20th'}:unpack()
+i:drop()
+
+i = s:create_index('a')
+s:insert{1953719668, 'hello world'}
+s:update(1953719668, {{'=', 2, 'bye, world'}})
+s:delete{1953719668}
+
+s:replace({10, 'abcde'})
+s:update(10, {{':', 2, 0, 0, '!'}})
+s:update(10, {{':', 2, 1, 0, '('}})
+s:update(10, {{':', 2, 2, 0, '({'}})
+s:update(10, {{':', 2, -1, 0, ')'}})
+s:update(10, {{':', 2, -2, 0, '})'}})
+
+-- test update delete operations
+s:update({1}, {{'#', 4, 1}, {'#', 3, 1}})
+
+-- test update insert operations
+s:update({1}, {{'!', 2, 1}, {'!', 2, 2}, {'!', 2, 3}, {'!', 2, 4}})
+
+-- s:update: zero field
+s:insert{48}
+s:update(48, {{'=', 0, 'hello'}})
+
+-- s:update: push/pop fields
+s:insert{1684234849}
+s:update({1684234849}, {{'#', 2, 1}})
+s:update({1684234849}, {{'!', -1, 'push1'}})
+s:update({1684234849}, {{'!', -1, 'push2'}})
+s:update({1684234849}, {{'!', -1, 'push3'}})
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap1'}})
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap2'}})
+s:update({1684234849}, {{'#', 2, 1}, {'!', -1, 'swap3'}})
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop1'}})
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop2'}})
+s:update({1684234849}, {{'#', -1, 1}, {'!', -1, 'noop3'}})
+
+--
+-- negative indexes
+--
+
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', 0, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -1, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -3, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -5, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -6, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -7, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'!', -100500, 'Test'}})
+
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', 0, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -1, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -3, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -5, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -6, 'Test'}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'=', -100500, 'Test'}})
+
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', 0, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -1, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -3, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -5, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -6, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'+', -100500, 100}})
+
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', 0, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -1, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -3, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -5, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -6, 100}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'|', -100500, 100}})
+
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', 0, 1}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -1, 1}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -3, 1}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -5, 1}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -6, 1}})
+box.tuple.new({1, 2, 3, 4, 5}):update({{'#', -100500, 1}})
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+s:insert{1, 2, 3}
+s:update({1})
+s:update({1}, {'=', 1, 1})
+s:drop()
+
+ffi = require('ffi')
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+
+s:insert{0, -1}
+-- + --
+s:update({0}, {{'+', 2, "a"}}) -- err
+s:update({0}, {{'+', 2, 10}}) -- neg(ative) + pos(itive) = pos(itive) 9
+s:update({0}, {{'+', 2, 5}}) -- pos + pos = pos 14
+s:update({0}, {{'+', 2, -4}}) -- pos + neg = pos 10
+s:update({0}, {{'+', 2, -22}}) -- pos + neg = neg -12
+s:update({0}, {{'+', 2, -3}}) -- neg + neg = neg -15
+s:update({0}, {{'+', 2, 7}}) -- neg + pos = neg -8
+-- - --
+s:update({0}, {{'-', 2, "a"}}) -- err
+s:update({0}, {{'-', 2, 16}}) -- neg(ative) - pos(itive) = neg(ative) -24
+s:update({0}, {{'-', 2, -4}}) -- neg - neg = neg 20
+s:update({0}, {{'-', 2, -32}}) -- neg - neg = pos 12
+s:update({0}, {{'-', 2, 3}}) -- pos - pos = pos 9
+s:update({0}, {{'-', 2, -5}}) -- pos - neg = pos 14
+s:update({0}, {{'-', 2, 17}}) -- pos - pos = neg -3
+-- bit --
+s:replace{0, 0} -- 0
+s:update({0}, {{'|', 2, 24}}) -- 24
+s:update({0}, {{'|', 2, 2}}) -- 26
+s:update({0}, {{'&', 2, 50}}) -- 18
+s:update({0}, {{'^', 2, 6}}) -- 20
+s:update({0}, {{'|', 2, -1}}) -- err
+s:update({0}, {{'&', 2, -1}}) -- err
+s:update({0}, {{'^', 2, -1}}) -- err
+s:replace{0, -1} -- -1
+s:update({0}, {{'|', 2, 2}}) -- err
+s:update({0}, {{'&', 2, 40}}) -- err
+s:update({0}, {{'^', 2, 6}}) -- err
+s:replace{0, 1.5} -- 1.5
+s:update({0}, {{'|', 2, 2}}) -- err
+s:update({0}, {{'&', 2, 40}}) -- err
+s:update({0}, {{'^', 2, 6}}) -- err
+-- double
+s:replace{0, 5} -- 5
+s:update({0}, {{'+', 2, 1.5}}) -- int + double = double 6.5
+s:update({0}, {{'|', 2, 2}}) -- err (double!)
+s:update({0}, {{'-', 2, 0.5}}) -- double - double = double 6
+s:update({0}, {{'+', 2, 1.5}}) -- double + double = double 7.5
+-- float
+s:replace{0, ffi.new("float", 1.5)} -- 1.5
+s:update({0}, {{'+', 2, 2}}) -- float + int = float 3.5
+s:update({0}, {{'+', 2, ffi.new("float", 3.5)}}) -- float + int = float 7
+s:update({0}, {{'|', 2, 2}}) -- err (float!)
+s:update({0}, {{'-', 2, ffi.new("float", 1.5)}}) -- float - float = float 5.5
+s:update({0}, {{'+', 2, ffi.new("float", 3.5)}}) -- float + float = float 9
+s:update({0}, {{'-', 2, ffi.new("float", 9)}}) -- float + float = float 0
+s:update({0}, {{'+', 2, ffi.new("float", 1.2)}}) -- float + float = float 1.2
+-- overflow --
+s:replace{0, 0xfffffffffffffffeull}
+s:update({0}, {{'+', 2, 1}}) -- ok
+s:update({0}, {{'+', 2, 1}}) -- overflow
+s:update({0}, {{'+', 2, 100500}}) -- overflow
+s:replace{0, 1}
+s:update({0}, {{'+', 2, 0xffffffffffffffffull}}) -- overflow
+s:replace{0, -1}
+s:update({0}, {{'+', 2, 0xffffffffffffffffull}}) -- ok
+s:replace{0, 0}
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- ok
+s:replace{0, -1}
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- ok
+s:replace{0, -2}
+s:update({0}, {{'-', 2, 0x7fffffffffffffffull}}) -- overflow
+s:replace{0, 1}
+s:update({0}, {{'-', 2, 0xffffffffffffffffull}}) -- overflow
+s:replace{0, 0xffffffffffffffefull}
+s:update({0}, {{'-', 2, -16}}) -- ok
+s:update({0}, {{'-', 2, -16}}) -- overflow
+s:replace{0, -0x4000000000000000ll}
+s:update({0}, {{'+', 2, -0x4000000000000000ll}}) -- ok
+s:replace{0, -0x4000000000000000ll}
+s:update({0}, {{'+', 2, -0x4000000000000001ll}}) -- overflow
+-- some wrong updates --
+s:update({0}, 0)
+s:update({0}, {'+', 2, 2})
+s:update({0}, {{}})
+s:update({0}, {{'+'}})
+s:update({0}, {{'+', 0}})
+s:update({0}, {{'+', '+', '+'}})
+s:update({0}, {{0, 0, 0}})
+
+ops = {}
+for i = 1,10 do table.insert(ops, {'=', 2, '1234567890'}) end
+s:upsert({0}, ops)
+
+s:get{0}
+s:update({0}, {})
+
+map = setmetatable({}, { __serialize = 'map' })
+t = box.tuple.new({1, 2, 3})
+s:replace({1, 2, 3})
+
+t:update({{'=', 3, map}})
+s:update(1, {{'=', 3, map}})
+
+s:drop()
+
+-- Ephemeral index: methods: pairs, count, select (iterators)
+
+-- iterator (str)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 100 do s:replace({tostring(key)}) end
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(tostring(44), {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(tostring(44), {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(tostring(77), {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(tostring(77), {iterator = 'LT'}) do table.insert(t, v) end
+t
+s:drop()
+
+-- iterator (num)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+for key = 1, 100 do s:replace({key}) end
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(44, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(44, {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(77, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(77, {iterator = 'LT'}) do table.insert(t, v) end
+t
+s:drop()
+
+-- iterator multi-part (num, num)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 100 do s:replace({key, key}) end
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({44, 44}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({44, 44}, {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({77, 77}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({77, 77}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+s:drop()
+
+-- iterator with tuple.new
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 100 do s:replace({tostring(key)}) end
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'ALL'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new(tostring(44)), {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new(tostring(44)), {iterator = 'GT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new(tostring(77)), {iterator = 'LE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new{}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(box.tuple.new(tostring(77)), {iterator = 'LT'}) do table.insert(t, v) end
+t
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+i:pairs({}, {iterator = 666 })
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+s:replace({1})
+s:replace({2})
+s:replace({3})
+s:replace({4})
+s:pairs(2, { iterator = 'GE' }):totable()
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a')
+s:auto_increment{1}
+s:auto_increment{2}
+s:auto_increment{3}
+s:auto_increment{4}
+s:auto_increment{5}
+
+s:pairs(3, 'GE'):totable()
+i:pairs(3, 'GE'):totable()
+s:pairs(3, {iterator = 'GE' }):totable()
+i:pairs(3, {iterator = 'GE' }):totable()
+
+s:pairs(3, 'EQ'):totable()
+i:pairs(3, 'EQ'):totable()
+s:pairs(3, {iterator = 'EQ' }):totable()
+i:pairs(3, {iterator = 'EQ' }):totable()
+
+s:pairs(3, 'GT'):totable()
+i:pairs(3, 'GT'):totable()
+s:pairs(3, {iterator = 'GT' }):totable()
+i:pairs(3, {iterator = 'GT' }):totable()
+
+i:select({3}, 'LE')
+s:select({3}, 'LE')
+
+i:count({3}, 'GT')
+s:count({3}, 'GT')
+
+s:drop()
+
+-- implement lazy iterator positioning
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+
+itr1,itr2,itr3 = s:pairs{2}
+_ = s:replace{1, 4}
+r = {}
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+r
+
+itr1,itr2,itr3 = s:pairs({2}, {iterator = 'GE'})
+_ = s:replace{1, 5}
+r = {}
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+r
+
+itr1,itr2,itr3 = s:pairs({2}, {iterator = 'REQ'})
+s:replace{2, 4}
+r = {}
+for k,v in itr1,itr2,itr3 do table.insert(r, v) end
+r
+
+r = nil
+s:drop()
+
+-- make tree iterators stable
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+
+for i = 1,10 do s:replace{i} end
+r = {}
+for k,v in s:pairs{} do table.insert(r, v[1]) s:delete(v[1]) end
+r
+s:select{}
+
+for i = 1,10 do s:replace{i} end
+r = {}
+for k,v in s:pairs({}, {iterator = 'REQ'}) do table.insert(r, v[1]) s:delete(v[1]) end
+r
+s:select{}
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+r = {}
+for k,v in s:pairs{2} do table.insert(r, v) s:delete{v[1], v[2]} end
+r
+s:select{}
+
+for i = 1,3 do for j = 1,3 do s:replace{i, j} end end
+r = {}
+for k,v in s:pairs({3}, {iterator = 'REQ'}) do table.insert(r, v) s:delete{v[1], v[2]} end
+r
+s:select{}
+
+r = nil
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({25})
+s:replace{25}
+state, value = gen(param,state)
+value
+state, value = gen(param,state)
+value
+
+gen,param,state = i:pairs({35})
+state, value = gen(param,state)
+value
+s:replace{35}
+state, value = gen(param,state)
+value
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({30}, {iterator = 'GE'})
+state, value = gen(param, state)
+value
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+state
+value
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({40}, {iterator = 'LE'})
+state, value = gen(param, state)
+value
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+state
+value
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({28}, {iterator = 'GE'})
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({42}, {iterator = 'LE'})
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({20}, {iterator = 'GT'})
+state, value = gen(param, state)
+value
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({50}, {iterator = 'LT'})
+state, value = gen(param, state)
+value
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({28}, {iterator = 'GT'})
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{10} s:replace{20} s:replace{30} s:replace{40} s:replace{50} s:replace{60}
+
+gen,param,state = i:pairs({42}, {iterator = 'LT'})
+s:replace{0}
+state, value = gen(param, state)
+value
+s:replace{42}
+state, value = gen(param, state)
+value
+s:replace{15}
+state, value = gen(param, state)
+value
+s:replace{32}
+state, value = gen(param, state)
+value
+s:replace{80}
+state, value = gen(param, state)
+value
+state, value = gen(param, state)
+value
+gen(param, state)
+-- test iterator dummy function, invoked when it's out of bounds
+gen(param, state)
+
+s:drop()
+
+
+-- Ephemeral space: methods: delete
+
+-- delete (str)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:replace({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+for key = 1, 10 do s:delete({tostring(key)}) end
+for key = 1, 10 do assert(s:get({tostring(key)}) == nil) end
+
+s:delete({tostring(7)})
+s:drop()
+
+-- delete (num)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+for key = 1, 10 do s:replace({key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key})) end
+t
+for key = 1, 10 do s:delete({key}) end
+for key = 1, 10 do assert(s:get({key}) == nil) end
+s:delete({7})
+s:drop()
+
+-- delete multi-part (num, num)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+for key = 1, 10 do s:replace({key, key}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({key, key})) end
+t
+for key = 1, 10 do s:delete({key, key}) end
+for key = 1, 10 do assert(s:get({key, key}) == nil) end
+s:delete({7, 7})
+s:drop()
+
+-- delete (str)
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+for key = 1, 10 do s:replace({tostring(key)}) end
+t = {}
+for key = 1, 10 do table.insert(t, s:get({tostring(key)})) end
+t
+for key = 1, 10 do s:delete(box.tuple.new{tostring(key)}) end
+for key = 1, 10 do assert(s:get({tostring(key)}) == nil) end
+
+s:delete(box.tuple.new{tostring(7)})
+s:drop()
+
+-- Ephemeral space: methods: bsize, len
+
+utils = dofile('utils.lua')
+
+s = box.schema.space.create_ephemeral()
+idx = s:create_index('a')
+
+for i = 1, 13 do s:insert{ i, string.rep('x', i) } end
+
+s:len()
+s:bsize()
+utils.space_bsize(s)
+
+for i = 1, 13, 2 do s:delete{ i } end
+
+s:len()
+s:bsize()
+utils.space_bsize(s)
+
+for i = 2, 13, 2 do s:update( { i }, {{ ":", 2, i, 0, string.rep('y', i) }} ) end
+
+s:len()
+s:bsize()
+utils.space_bsize(s)
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'INTEGER'} })
+
+s:insert({1, "AAAA"})
+s:insert({2, "AAAA"})
+s:insert({3, "AAAA"})
+s:insert({4, "AAAA"})
+
+i:select()
+i:max(2)
+i:min(2)
+i:count(2)
+i:max()
+i:min()
+i:count()
+
+s:insert({20, "AAAA"})
+s:insert({30, "AAAA"})
+s:insert({40, "AAAA"})
+
+i:select()
+i:max(15)
+i:min(15)
+i:count(15)
+i:max()
+i:min()
+i:count()
+
+s:insert({-2, "AAAA"})
+s:insert({-3, "AAAA"})
+s:insert({-4, "AAAA"})
+
+i:select()
+i:max(0)
+i:min(0)
+i:count(0)
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- number type
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'number'} })
+
+s:insert({1, "AAAA"})
+s:insert({2, "AAAA"})
+s:insert({3, "AAAA"})
+s:insert({4, "AAAA"})
+
+i:select()
+i:max(2)
+i:min(2)
+i:count(2)
+i:max()
+i:min()
+i:count()
+
+s:insert({20, "AAAA"})
+s:insert({30, "AAAA"})
+s:insert({40, "AAAA"})
+
+i:select()
+i:max(15)
+i:min(15)
+i:count(15)
+i:max()
+i:min()
+i:count()
+
+s:insert({-2, "AAAA"})
+s:insert({-3, "AAAA"})
+s:insert({-4, "AAAA"})
+
+i:select()
+i:max(0)
+i:min(0)
+i:count(0)
+i:max()
+i:min()
+i:count()
+
+s:insert({1.5, "AAAA"})
+s:insert({2.5, "AAAA"})
+s:insert({3.5, "AAAA"})
+s:insert({4.5, "AAAA"})
+
+i:select()
+i:max(1)
+i:min(1)
+i:count(1)
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- str type
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert({'1', "AAAA"})
+s:insert({'2', "AAAA"})
+s:insert({'3', "AAAA"})
+s:insert({'4', "AAAA"})
+
+i:select()
+i:max('2')
+i:min('2')
+i:count('2')
+i:max()
+i:min()
+i:count()
+
+s:insert({'20', "AAAA"})
+s:insert({'30', "AAAA"})
+s:insert({'40', "AAAA"})
+
+i:select()
+i:max('15')
+i:min('15')
+i:count('15')
+i:max()
+i:min()
+i:count()
+
+s:insert({'-2', "AAAA"})
+s:insert({'-3', "AAAA"})
+s:insert({'-4', "AAAA"})
+
+i:select()
+i:max('0')
+i:min('0')
+i:count('0')
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- num type
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert({1, "AAAA"})
+s:insert({2, "AAAA"})
+s:insert({3, "AAAA"})
+s:insert({4, "AAAA"})
+
+i:select()
+i:max(2)
+i:min(2)
+i:count(2)
+i:max()
+i:min()
+i:count()
+
+s:insert({20, "AAAA"})
+s:insert({30, "AAAA"})
+s:insert({40, "AAAA"})
+
+i:select()
+i:max(15)
+i:min(15)
+i:count(15)
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- scalar type
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar'} })
+s:insert({1, "AAAA"})
+s:insert({2, "AAAA"})
+s:insert({3, "AAAA"})
+s:insert({4, "AAAA"})
+
+i:select()
+i:max(2)
+i:min(2)
+i:count(2)
+i:max()
+i:min()
+i:count()
+
+s:insert({20, "AAAA"})
+s:insert({30, "AAAA"})
+s:insert({40, "AAAA"})
+
+i:select()
+i:max(15)
+i:min(15)
+i:count(15)
+i:max()
+i:min()
+i:count()
+s:insert({'1', "AAAA"})
+s:insert({'2', "AAAA"})
+s:insert({'3', "AAAA"})
+s:insert({'4', "AAAA"})
+
+i:select()
+i:max('2')
+i:min('2')
+i:count('2')
+i:max()
+i:min()
+i:count()
+
+s:insert({'20', "AAAA"})
+s:insert({'30', "AAAA"})
+s:insert({'40', "AAAA"})
+
+i:select()
+i:max('15')
+i:min('15')
+i:count('15')
+i:max()
+i:min()
+i:count()
+
+s:insert({'-2', "AAAA"})
+s:insert({'-3', "AAAA"})
+s:insert({'-4', "AAAA"})
+
+i:select()
+i:max('0')
+i:min('0')
+i:count('0')
+i:max()
+i:min()
+i:count()
+
+s:insert({-2, "AAAA"})
+s:insert({-3, "AAAA"})
+s:insert({-4, "AAAA"})
+
+i:select()
+i:max(0)
+i:min(0)
+i:count(0)
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- multi filed indices
+
+-- scalar int
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'INTEGER'} })
+
+s:insert({1, 1})
+s:insert({1, 2})
+s:insert({1, 3})
+s:insert({1, -4})
+
+i:select()
+i:max({1})
+i:min({1})
+i:count({1})
+i:max({1, 0})
+i:min({1, 1})
+i:count({1})
+i:max()
+i:min()
+i:count()
+
+s:insert({2, 1})
+s:insert({2, 2})
+s:insert({2, 3})
+s:insert({2, -4})
+
+i:select()
+i:max({2})
+i:min({2})
+i:count({2})
+i:max({2, 0})
+i:min({2, 1})
+i:count({2})
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- scalar str
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'string'} })
+
+s:insert({1, '1'})
+s:insert({1, '2'})
+s:insert({1, '3'})
+s:insert({1, '-4'})
+
+i:select()
+i:max({1})
+i:min({1})
+i:count({1})
+i:max({1, '0'})
+i:min({1, '1'})
+i:count({1})
+i:max()
+i:min()
+i:count()
+
+s:insert({2, '1'})
+s:insert({2, '2'})
+s:insert({2, '3'})
+s:insert({2, '-4'})
+
+i:select()
+i:max({2})
+i:min({2})
+i:count({2})
+i:max({2, '0'})
+i:min({2, '1'})
+i:count({2})
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+-- min max count after many inserts
+
+string = require('string')
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar'} })
+
+long_string = string.rep('A', 650)
+for i = 1, 1000 do s:insert({i, long_string}) end
+
+i:max({100})
+i:max({700})
+i:min({100})
+i:min({700})
+i:count({2})
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'scalar', 2, 'INTEGER'} })
+
+for i = 1, 1000 do s:insert({i % 10, i, long_string}) end
+
+i:max({1, 100})
+i:max({2, 700})
+i:max({3})
+i:min({1, 10})
+i:min({1, 700})
+i:min({3})
+i:count({2})
+i:max()
+i:min()
+i:count()
+
+s:drop()
+
+test_run:cmd("restart server default")
--
2.7.4
^ permalink raw reply [flat|nested] 12+ messages in thread