From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 4070020A9C for ; Thu, 12 Jul 2018 07:16:21 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TlnvxqpNQMX9 for ; Thu, 12 Jul 2018 07:16:21 -0400 (EDT) Received: from smtp38.i.mail.ru (smtp38.i.mail.ru [94.100.177.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 7AFC826DB1 for ; Thu, 12 Jul 2018 07:16:19 -0400 (EDT) Received: from [185.6.245.156] (port=53176 helo=mimeev-ThinkPad-T460p.mail.msk) by smtp38.i.mail.ru with esmtpa (envelope-from ) id 1fdZa5-0004rM-Fq for tarantool-patches@freelists.org; Thu, 12 Jul 2018 14:16:17 +0300 From: imeevma@tarantool.org Subject: [tarantool-patches] [PATCH 5/5] Methods for ephemeral space and its index Date: Thu, 12 Jul 2018 14:16:16 +0300 Message-Id: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org 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 @@ -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