[tarantool-patches] [PATCH v3 7/7] box: methods for ephemeral space and its index
imeevma at tarantool.org
imeevma at tarantool.org
Tue Jul 24 14:58:22 MSK 2018
This patch defines most methods for index of
ephemeral space and ephemeral space.
Closes #3375.
---
src/box/box.cc | 64 ++-
src/box/box.h | 21 +
src/box/index.cc | 158 ++++++++
src/box/index.h | 137 +++++++
src/box/lua/index.c | 422 +++++++++++++++++++-
src/box/lua/misc.cc | 10 +-
src/box/lua/misc.h | 9 +
src/box/lua/schema.lua | 156 ++++++++
test/box/ephemeral_space.result | 802 +++++++++++++++++++++++++++++++++++++-
test/box/ephemeral_space.test.lua | 240 ++++++++++++
test/engine/iterator.result | 2 +-
11 files changed, 1992 insertions(+), 29 deletions(-)
diff --git a/src/box/box.cc b/src/box/box.cc
index e811496..40d0f24 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1099,16 +1099,11 @@ box_process1(struct request *request, box_tuple_t **result)
return box_process_rw(request, space, result);
}
-int
-box_select(uint32_t space_id, uint32_t index_id,
- int iterator, uint32_t offset, uint32_t limit,
- const char *key, const char *key_end,
- struct port *port)
+static inline int
+box_select_impl(struct space *space, uint32_t index_id,
+ int iterator, uint32_t offset, uint32_t limit,
+ const char *key, 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");
@@ -1116,11 +1111,6 @@ box_select(uint32_t space_id, uint32_t index_id,
return -1;
}
- struct space *space = space_cache_find(space_id);
- if (space == NULL)
- return -1;
- if (access_check_space(space, PRIV_R) != 0)
- return -1;
struct index *index = index_find(space, index_id);
if (index == NULL)
return -1;
@@ -1135,16 +1125,10 @@ box_select(uint32_t space_id, uint32_t index_id,
return -1;
});
- struct txn *txn;
- if (txn_begin_ro_stmt(space, &txn) != 0)
- return -1;
-
struct iterator *it = index_create_iterator(index, type,
key, part_count);
- if (it == NULL) {
- txn_rollback_stmt();
+ if (it == NULL)
return -1;
- }
int rc = 0;
uint32_t found = 0;
@@ -1167,9 +1151,36 @@ box_select(uint32_t space_id, uint32_t index_id,
if (rc != 0) {
port_destroy(port);
+ return -1;
+ }
+ return 0;
+}
+
+int
+box_select(uint32_t space_id, 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);
+
+ struct space *space = space_cache_find(space_id);
+ if (space == NULL)
+ return -1;
+ if (access_check_space(space, PRIV_R) != 0)
+ return -1;
+ struct txn *txn;
+ if (txn_begin_ro_stmt(space, &txn) != 0)
+ return -1;
+
+ if (box_select_impl(space, index_id, iterator, offset, limit, key,
+ port) != 0) {
txn_rollback_stmt();
return -1;
}
+
txn_commit_ro_stmt(txn);
return 0;
}
@@ -1251,6 +1262,17 @@ 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;
+ return box_select_impl(space, index_id, iterator, offset, limit, key,
+ port);
+}
+
+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 e582fbc..40fc31b 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -404,6 +404,27 @@ int
box_process1(struct request *request, box_tuple_t **result);
/**
+ * Select the number of tuple matched conditions.
+ *
+ * \param space ephemeral space.
+ * \param index_id id of index for select.
+ * \param iterator iterator to use for select.
+ * \param offset offset for select.
+ * \param limit limit for select.
+ * \param key key for select.
+ * \param key_end end of \a key.
+ * \param port port to save result of select to.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+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);
+
+/**
* Execute an INSERT request for ephemeral spaces.
*
* \param space ephemeral space.
diff --git a/src/box/index.cc b/src/box/index.cc
index 372e0f3..e2cb4f0 100644
--- a/src/box/index.cc
+++ b/src/box/index.cc
@@ -198,6 +198,15 @@ box_index_len(uint32_t space_id, uint32_t index_id)
}
ssize_t
+box_index_len_ephemeral(struct space *space, uint32_t index_id)
+{
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return -1;
+ return index_size(index);
+}
+
+ssize_t
box_index_bsize(uint32_t space_id, uint32_t index_id)
{
struct space *space;
@@ -208,6 +217,15 @@ box_index_bsize(uint32_t space_id, uint32_t index_id)
return index_bsize(index);
}
+ssize_t
+box_index_bsize_ephemeral(struct space *space, uint32_t index_id)
+{
+ struct index *index = index_find(space, index_id);
+ if (index == NULL)
+ return 0;
+ return index_bsize(index);
+}
+
int
box_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd,
box_tuple_t **result)
@@ -226,6 +244,19 @@ box_index_random(uint32_t space_id, uint32_t index_id, uint32_t rnd,
}
int
+box_index_random_ephemeral(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_index_get(uint32_t space_id, uint32_t index_id, const char *key,
const char *key_end, box_tuple_t **result)
{
@@ -259,6 +290,29 @@ box_index_get(uint32_t space_id, uint32_t index_id, const char *key,
}
int
+box_index_get_ephemeral(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;
+ if (*result != NULL)
+ tuple_bless(*result);
+ return 0;
+}
+
+int
box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
const char *key_end, box_tuple_t **result)
{
@@ -291,6 +345,29 @@ box_index_min(uint32_t space_id, uint32_t index_id, const char *key,
}
int
+box_index_min_ephemeral(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_index_max(uint32_t space_id, uint32_t index_id, const char *key,
const char *key_end, box_tuple_t **result)
{
@@ -322,6 +399,29 @@ box_index_max(uint32_t space_id, uint32_t index_id, const char *key,
return 0;
}
+int
+box_index_max_ephemeral(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_index_count(uint32_t space_id, uint32_t index_id, int type,
const char *key, const char *key_end)
@@ -354,6 +454,30 @@ box_index_count(uint32_t space_id, uint32_t index_id, int type,
return count;
}
+ssize_t
+box_index_count_ephemeral(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 ************************************************/
@@ -391,6 +515,30 @@ box_index_iterator(uint32_t space_id, uint32_t index_id, int type,
return it;
}
+box_iterator_t *
+box_index_iterator_ephemeral(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);
+ return it;
+}
+
int
box_iterator_next(box_iterator_t *itr, box_tuple_t **result)
{
@@ -435,6 +583,16 @@ box_index_compact(uint32_t space_id, uint32_t index_id)
return 0;
}
+int
+box_index_compact_ephemeral(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 73ee000..83e30bf 100644
--- a/src/box/index.h
+++ b/src/box/index.h
@@ -236,6 +236,143 @@ 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.
+ *
+ * \param space - ephemeral space.
+ * \param index_id - index identifier.
+ *
+ * \retval -1 on error.
+ * \retval >= 0 on success.
+ */
+ssize_t
+box_index_len_ephemeral(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 -1 on error.
+ * \retval >= 0 on success.
+ */
+ssize_t
+box_index_bsize_ephemeral(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_index_random_ephemeral(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_index_get_ephemeral(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result);
+
+/**
+ * Return 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_index_min_ephemeral(struct space *space, uint32_t index_id, const char *key,
+ const char *key_end, box_tuple_t **result);
+
+/**
+ * Return 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.
+ */
+int
+box_index_max_ephemeral(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.
+ */
+ssize_t
+box_index_count_ephemeral(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_index_iterator_ephemeral(struct space *space, uint32_t index_id, int type,
+ const char *key, const char *key_end);
+
+/**
+ * Trigger index compaction.
+ *
+ * \param space ephemeral space.
+ * \param index_id index identifier.
+ *
+ * \retval -1 on error.
+ * \retval 0 on success.
+ */
+int
+box_index_compact_ephemeral(struct space *space, uint32_t index_id);
+
struct iterator {
/**
* Iterate to the next tuple.
diff --git a/src/box/lua/index.c b/src/box/lua/index.c
index ef89c39..79427e8 100644
--- a/src/box/lua/index.c
+++ b/src/box/lua/index.c
@@ -35,7 +35,9 @@
#include "box/info.h"
#include "box/lua/info.h"
#include "box/lua/tuple.h"
-#include "box/lua/misc.h" /* lbox_encode_tuple_on_gc() */
+#include "box/lua/misc.h"
+#include "box/port.h"
+#include "box/box.h"
/** {{{ box.index Lua library: access to spaces and indexes
*/
@@ -58,6 +60,30 @@ lbox_insert(lua_State *L)
return luaT_pushtupleornil(L, result);
}
+/**
+ * Insert tuple into ephemeral space.
+ *
+ * @param L Lua stack to get space and tuple from.
+ *
+ * @retval not nil tuple that was inserted.
+ * @retval nil error.
+ */
+static int
+lbox_insert_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 2)
+ return luaL_error(L, "Usage space:insert(tuple)");
+
+ struct space *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);
+}
+
static int
lbox_replace(lua_State *L)
{
@@ -74,6 +100,31 @@ lbox_replace(lua_State *L)
return luaT_pushtupleornil(L, result);
}
+/**
+ * Replace tuple from ephemeral space.
+ *
+ * @param L Lua stack to get space and tuple from.
+ *
+ * @retval not nil tuple that was inserted.
+ * @retval nil error.
+ */
+static int
+lbox_replace_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 2)
+ return luaL_error(L, "Usage space:replace(tuple)");
+
+ struct space *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);
+}
+
static int
lbox_index_update(lua_State *L)
{
@@ -96,6 +147,36 @@ lbox_index_update(lua_State *L)
return luaT_pushtupleornil(L, result);
}
+/**
+ * Update tuple matched provided key.
+ *
+ * @param L Lua stack to get space, index_id, key and ops from.
+ *
+ * @retval not nil tuple - result of update.
+ * @retval nil error.
+ */
+static int
+lbox_index_update_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) ||
+ (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL) ||
+ (!lua_istable(L, 4) && luaT_istuple(L, 4) == NULL))
+ return luaL_error(L, "Usage index:update(key, ops)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+ size_t ops_len;
+ const char *ops = lbox_encode_tuple_on_gc(L, 4, &ops_len);
+
+ struct tuple *result;
+ if (box_ephemeral_update(space, index_id, key, key + key_len,
+ ops, ops + ops_len, 1, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
static int
lbox_upsert(lua_State *L)
{
@@ -117,6 +198,35 @@ lbox_upsert(lua_State *L)
return luaT_pushtupleornil(L, result);
}
+/**
+ * Insert or update tuple from ephemeral space.
+ *
+ * @param L Lua stack to get space, tuple and ops from.
+ *
+ * @retval not nil tuple - result of upsert.
+ * @retval nil error.
+ */
+static int
+lbox_upsert_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 ||
+ (!lua_istable(L, 2) && luaT_istuple(L, 2) == NULL) ||
+ (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL))
+ return luaL_error(L, "Usage index:upsert(key, ops)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ size_t tuple_len;
+ const char *tuple = lbox_encode_tuple_on_gc(L, 2, &tuple_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, tuple, tuple + tuple_len,
+ ops, ops + ops_len, 1, &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
static int
lbox_index_delete(lua_State *L)
{
@@ -135,6 +245,73 @@ lbox_index_delete(lua_State *L)
return luaT_pushtupleornil(L, result);
}
+/**
+ * Delete tuple matched the provided key.
+ *
+ * @param L Lua stack to get space, index_id and key from.
+ *
+ * @retval not nil tuple that was deleted.
+ * @retval nil error.
+ */
+static int
+lbox_index_delete_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_isnumber(L, 2) ||
+ (!lua_istable(L, 3) && luaT_istuple(L, 3) == NULL))
+ return luaL_error(L, "Usage index:delete(key)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+ struct tuple *result;
+ if (box_ephemeral_delete(space, index_id, key, key + key_len,
+ &result) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, result);
+}
+
+/**
+ * Push number of element in the index on stack.
+ *
+ * @param L Lua stack to get space from.
+ *
+ * @retval number number number of return values.
+ */
+static int
+lbox_index_len_ephemeral(struct lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage: index:len()");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+
+ lua_pushnumber(L, box_index_len_ephemeral(space, index_id));
+ return 1;
+}
+
+/**
+ * Push number of bytes used in memory by index on stack.
+ *
+ * @param L Lua stack to get space from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_bsize_ephemeral(struct lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage: index:bsize()");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+
+ lua_pushnumber(L, box_index_bsize_ephemeral(space, index_id));
+ return 1;
+}
+
static int
lbox_index_random(lua_State *L)
{
@@ -152,6 +329,30 @@ lbox_index_random(lua_State *L)
return luaT_pushtupleornil(L, tuple);
}
+/**
+ * Return a random tuple from the index.
+ *
+ * @param L Lua stack to get space and seed from.
+ *
+ * @retval not nil random tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_random_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+ return luaL_error(L, "Usage index:random(seed)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ uint32_t rnd = lua_tonumber(L, 3);
+
+ struct tuple *tuple;
+ if (box_index_random_ephemeral(space, index_id, rnd, &tuple) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, tuple);
+}
+
static int
lbox_index_get(lua_State *L)
{
@@ -169,6 +370,32 @@ lbox_index_get(lua_State *L)
return luaT_pushtupleornil(L, tuple);
}
+/**
+ * Return a tuple from the index by given key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_get_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage index:get(key)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+ struct tuple *tuple;
+ if (box_index_get_ephemeral(space, index_id, key, key + key_len,
+ &tuple) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, tuple);
+}
+
static int
lbox_index_min(lua_State *L)
{
@@ -186,6 +413,32 @@ lbox_index_min(lua_State *L)
return luaT_pushtupleornil(L, tuple);
}
+/**
+ * Return first (minimal) tuple from the index matched provided
+ * key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_min_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage index:min(key)");
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+ struct tuple *tuple;
+ if (box_index_min_ephemeral(space, index_id, key, key + key_len,
+ &tuple) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, tuple);
+}
+
static int
lbox_index_max(lua_State *L)
{
@@ -203,6 +456,33 @@ lbox_index_max(lua_State *L)
return luaT_pushtupleornil(L, tuple);
}
+/**
+ * Return last (maximal) tuple from the index matched provided
+ * key.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval not nil matched tuple.
+ * @retval nil error.
+ */
+static int
+lbox_index_max_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 3 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage index:max(key)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 3, &key_len);
+
+ struct tuple *tuple;
+ if (box_index_max_ephemeral(space, index_id, key, key + key_len,
+ &tuple) != 0)
+ return luaT_error(L);
+ return luaT_pushtupleornil(L, tuple);
+}
+
static int
lbox_index_count(lua_State *L)
{
@@ -226,6 +506,65 @@ lbox_index_count(lua_State *L)
return 1;
}
+/**
+ * Count tuples matched provided key and push this number on
+ * stack.
+ *
+ * @param L Lua stack to get space and key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_count_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+ return luaL_error(L, "Usage index:count(type, key)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ uint32_t iterator = lua_tonumber(L, 3);
+ size_t key_len;
+ const char *key = lbox_encode_tuple_on_gc(L, 4, &key_len);
+
+ ssize_t count = box_index_count_ephemeral(space, index_id, iterator,
+ key, key + key_len);
+ if (count == -1)
+ return luaT_error(L);
+ lua_pushinteger(L, count);
+ return 1;
+}
+
+/**
+ * Select tuples matched conditions and push them on stack as
+ * table.
+ *
+ * @param L Lua stack to get space, iterator, offset, limit and
+ * key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_select_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 5) {
+ return luaL_error(L, "Usage index:select(iterator, offset, "\
+ "limit, key)");
+ }
+ struct space *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 void
box_index_init_iterator_types(struct lua_State *L, int idx)
{
@@ -264,6 +603,40 @@ lbox_index_iterator(lua_State *L)
return 1;
}
+/**
+ * Creates iterator for ephemeral space according to given type
+ * and pushes it on stack.
+ *
+ * @param L Lua stack to get space, index_id, iterator type and
+ * encoded with msgpack key from.
+ *
+ * @retval number number of return values.
+ */
+static int
+lbox_index_iterator_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 4 || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
+ return luaL_error(L, "Usage index:iterator(type, key)");
+
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+ uint32_t iterator = lua_tonumber(L, 3);
+ size_t mpkey_len;
+ /* Key encoded by Lua */
+ const char *mpkey = lua_tolstring(L, 4, &mpkey_len);
+ struct iterator *it =
+ box_index_iterator_ephemeral(space, index_id, 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;
+}
+
static int
lbox_iterator_next(lua_State *L)
{
@@ -328,6 +701,24 @@ lbox_index_compact(lua_State *L)
return 0;
}
+/**
+ * Run index compaction.
+ *
+ * @param L Lua stack to get space and key from.
+ */
+static int
+lbox_index_compact_ephemeral(lua_State *L)
+{
+ if (lua_gettop(L) != 2 || !lua_isnumber(L, 2))
+ return luaL_error(L, "Usage index:compact()");
+ struct space *space = lua_checkephemeralspace(L, 1);
+ uint32_t index_id = lua_tonumber(L, 2);
+
+ if (box_index_compact_ephemeral(space, index_id) != 0)
+ return luaT_error(L);
+ return 0;
+}
+
/* }}} */
void
@@ -340,6 +731,12 @@ box_lua_index_init(struct lua_State *L)
CTID_STRUCT_ITERATOR_REF = luaL_ctypeid(L, "struct iterator&");
assert(CTID_STRUCT_ITERATOR_REF != 0);
+ lua_getfield(L, LUA_GLOBALSINDEX, "box");
+ lua_getfield(L, -1, "internal");
+ lua_newtable(L);
+ lua_setfield(L, -2, "index_ephemeral_methods");
+ lua_pop(L, 2); /* box, internal */
+
static const struct luaL_Reg indexlib [] = {
{NULL, NULL}
};
@@ -370,4 +767,27 @@ box_lua_index_init(struct lua_State *L)
luaL_register(L, "box.internal", boxlib_internal);
lua_pop(L, 1);
+
+ static const struct luaL_Reg ephemeral_index_lib[] = {
+ {"insert", lbox_insert_ephemeral},
+ {"replace", lbox_replace_ephemeral},
+ {"update", lbox_index_update_ephemeral},
+ {"upsert", lbox_upsert_ephemeral},
+ {"delete", lbox_index_delete_ephemeral},
+ {"len", lbox_index_len_ephemeral},
+ {"bsize", lbox_index_bsize_ephemeral},
+ {"random", lbox_index_random_ephemeral},
+ {"select", lbox_index_select_ephemeral},
+ {"get", lbox_index_get_ephemeral},
+ {"min", lbox_index_min_ephemeral},
+ {"max", lbox_index_max_ephemeral},
+ {"count", lbox_index_count_ephemeral},
+ {"iterator", lbox_index_iterator_ephemeral},
+ {"compact", lbox_index_compact_ephemeral},
+ {NULL, NULL}
+ };
+
+ luaL_register(L, "box.internal.index_ephemeral_methods",
+ ephemeral_index_lib);
+ lua_pop(L, 1);
}
diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc
index 13ca18c..32ffb20 100644
--- a/src/box/lua/misc.cc
+++ b/src/box/lua/misc.cc
@@ -70,11 +70,7 @@ lua_checkephemeralspace(struct lua_State *L, int idx)
return *(struct space **) data;
}
-/* }}} */
-
-/** {{{ Lua/C implementation of index:select(): used only by Vinyl **/
-
-static inline void
+void
lbox_port_to_table(lua_State *L, struct port *port_base)
{
struct port_tuple *port = port_tuple(port_base);
@@ -87,6 +83,10 @@ lbox_port_to_table(lua_State *L, struct port *port_base)
}
}
+/* }}} */
+
+/** {{{ Lua/C implementation of index:select(): used only by Vinyl **/
+
static int
lbox_select(lua_State *L)
{
diff --git a/src/box/lua/misc.h b/src/box/lua/misc.h
index 6162baa..6859142 100644
--- a/src/box/lua/misc.h
+++ b/src/box/lua/misc.h
@@ -54,6 +54,15 @@ lbox_encode_tuple_on_gc(struct lua_State *L, int idx, size_t *p_len);
struct space *
lua_checkephemeralspace(struct lua_State *L, int idx);
+/**
+ * Transform given port to Lua table.
+ *
+ * @param L Lua stack to push table to.
+ * @param port_base port to transform.
+ */
+void
+lbox_port_to_table(lua_State *L, struct port *port_base);
+
void
box_lua_misc_init(struct lua_State *L);
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index cc8c66b..3b40401 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1098,6 +1098,8 @@ local index_new_ephemeral = box.internal.space.index_new_ephemeral
box.internal.space.index_new_ephemeral = nil
local index_delete_ephemeral = box.internal.space.index_delete_ephemeral
box.internal.space.index_delete_ephemeral = nil
+local index_ephemeral_methods = box.internal.index_ephemeral_methods
+box.internal.index_ephemeral_methods = nil
local index_ephemeral_mt = {}
local create_ephemeral_index = function(space, name, options)
@@ -1234,6 +1236,13 @@ local function check_index_arg(index, method)
error(string.format(fmt, method, method))
end
end
+local function check_index_arg_ephemeral(index, method)
+ if type(index) ~= 'table' or type(index.space) ~= 'table' or
+ param_type(index.space.space) ~= 'cdata' then
+ local fmt = 'Use index:%s(...) instead of index.%s(...)'
+ error(string.format(fmt, method, method))
+ end
+end
box.internal.check_index_arg = check_index_arg -- for net.box
-- Helper function to check that space have primary key and return it
@@ -1642,6 +1651,81 @@ space_mt.__index = space_mt
-- Metatable for primary index of ephemeral space
index_ephemeral_mt.drop = drop_ephemeral_index
+index_ephemeral_mt.update = function(index, key, ops)
+ check_index_arg_ephemeral(index, 'update')
+ key = keify(key)
+ return index_ephemeral_methods.update(index.space.space, index.id, key, ops)
+end
+index_ephemeral_mt.delete = function(index, key)
+ check_index_arg_ephemeral(index, 'delete')
+ key = keify(key)
+ return index_ephemeral_methods.delete(index.space.space, index.id, key)
+end
+index_ephemeral_mt.len = function(index)
+ check_index_arg_ephemeral(index, 'len')
+ local ret = index_ephemeral_methods.len(index.space.space, index.id)
+ if ret == -1 then
+ box.error()
+ end
+ return tonumber(ret)
+end
+index_ephemeral_mt.__len = index_ephemeral_mt.len
+index_ephemeral_mt.bsize = function(index)
+ check_index_arg_ephemeral(index, 'bsize')
+ local ret = index_ephemeral_methods.bsize(index.space.space, index.id)
+ if ret == -1 then
+ box.error()
+ end
+ return tonumber(ret)
+end
+index_ephemeral_mt.random = function(index, rnd)
+ check_index_arg_ephemeral(index, 'random')
+ rnd = rnd or math.random()
+ return index_ephemeral_methods.random(index.space.space, index.id, rnd);
+end
+index_ephemeral_mt.get = function(index, key)
+ check_index_arg_ephemeral(index, 'get')
+ key = keify(key)
+ return index_ephemeral_methods.get(index.space.space, index.id, key)
+end
+index_ephemeral_mt.select = function(index, key, opts)
+ check_index_arg_ephemeral(index, 'select')
+ local key = keify(key)
+ local iterator, offset, limit = check_select_opts(opts, #key == 0)
+ return index_ephemeral_methods.select(index.space.space, iterator, offset, limit, key)
+end
+index_ephemeral_mt.min = function(index, key)
+ check_index_arg_ephemeral(index, 'min')
+ key = keify(key)
+ return index_ephemeral_methods.min(index.space.space, index.id, key);
+end
+index_ephemeral_mt.max = function(index, key)
+ check_index_arg_ephemeral(index, 'max')
+ key = keify(key)
+ return index_ephemeral_methods.max(index.space.space, index.id, key);
+end
+index_ephemeral_mt.count = function(index, key, opts)
+ check_index_arg_ephemeral(index, 'count')
+ key = keify(key)
+ local itype = check_iterator_type(opts, #key == 0);
+ return index_ephemeral_methods.count(index.space.space, index.id, itype,
+ key);
+end
+index_ephemeral_mt.pairs = function(index, key, opts)
+ check_index_arg_ephemeral(index, 'pairs')
+ 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.space.space, index.id,
+ itype, keymp);
+ return fun.wrap(iterator_gen_luac, keybuf,
+ ffi.gc(cdata, builtin.box_iterator_free))
+end
+index_ephemeral_mt.compact = function(index)
+ check_index_arg_ephemeral(index, 'compact')
+ return index_ephemeral_methods.compact(index.space.space, index.id)
+end
index_ephemeral_mt.__index = index_ephemeral_mt
-- Metatable for ephemeral space
@@ -1665,9 +1749,81 @@ space_ephemeral_mt.bsize = function(space)
check_ephemeral_space_arg(space, 'bsize')
return builtin.space_bsize(space.space)
end
+space_ephemeral_mt.auto_increment = function(space, tuple)
+ check_ephemeral_space_arg(space, 'auto_increment')
+ local max_tuple = check_primary_index(space):max()
+ local max = 0
+ if max_tuple ~= nil then
+ max = max_tuple[1]
+ end
+ table.insert(tuple, 1, max + 1)
+ return space:insert(tuple)
+end
+space_ephemeral_mt.insert = function(space, tuple)
+ check_ephemeral_space_arg(space, 'insert')
+ return index_ephemeral_methods.insert(space.space, tuple);
+end
+space_ephemeral_mt.replace = function(space, tuple)
+ check_ephemeral_space_arg(space, 'replace')
+ return index_ephemeral_methods.replace(space.space, tuple);
+end
+space_ephemeral_mt.upsert = function(space, tuple_key, ops, deprecated)
+ check_ephemeral_space_arg(space, 'upsert')
+ 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 index_ephemeral_methods.upsert(space.space, tuple_key, ops);
+end
+space_ephemeral_mt.pairs = function(space, key, opts)
+ check_ephemeral_space_arg(space, 'pairs')
+ local pk = 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(space)
+ check_ephemeral_space_arg(space, 'truncate')
+ local index = space.index[0]
+ local name = index.name
+ local options = index.options
+ index:drop()
+ space:create_index(name, options)
+end
space_ephemeral_mt.create_index = create_ephemeral_index
space_ephemeral_mt.drop = box.schema.space.drop_ephemeral
space_ephemeral_mt.__index = space_ephemeral_mt
+space_ephemeral_mt.put = space_ephemeral_methods.replace
+space_ephemeral_mt.update = function(space, key, ops)
+ check_ephemeral_space_arg(space, 'update')
+ return check_primary_index(space):update(key, ops)
+end
+space_ephemeral_mt.delete = function(space, key)
+ check_ephemeral_space_arg(space, 'delete')
+ return check_primary_index(space):delete(key)
+end
+space_ephemeral_mt.get = function(space, key)
+ check_ephemeral_space_arg(space, 'get')
+ return check_primary_index(space):get(key)
+end
+space_ephemeral_mt.select = function(space, key, opts)
+ check_ephemeral_space_arg(space, 'select')
+ return check_primary_index(space):select(key, opts)
+end
+space_ephemeral_mt.count = function(space, key, opts)
+ check_ephemeral_space_arg(space, 'count')
+ return check_primary_index(space):count(key, opts)
+end
+space_ephemeral_mt.len = function(space)
+ check_ephemeral_space_arg(space, 'len')
+ return check_primary_index(space):len()
+end
box.schema.index_mt = base_index_mt
box.schema.memtx_index_mt = memtx_index_mt
diff --git a/test/box/ephemeral_space.result b/test/box/ephemeral_space.result
index 4ef395f..3137f63 100644
--- a/test/box/ephemeral_space.result
+++ b/test/box/ephemeral_space.result
@@ -135,7 +135,7 @@ s:frommap({ddd = 1, aaa = 2, ccc = 3, eee = 4})
...
s:frommap()
---
-- error: 'builtin/box/schema.lua:1659: Usage: space:frommap(map, opts)'
+- error: 'builtin/box/schema.lua:1743: Usage: space:frommap(map, opts)'
...
s:frommap({})
---
@@ -245,3 +245,803 @@ i = s:create_index('a', {type = 'bitset', parts = {1, 'unsigned', 2, 'unsigned'}
- error: 'Can''t create or modify index ''a'' in space ''ephemeral'': primary key
must be unique'
...
+-- Ephemeral space: methods
+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,2}
+---
+- [2, 2, 2]
+...
+s:drop()
+---
+...
+s = box.schema.space.create_ephemeral()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:insert{'1'}
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:insert{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert{1}
+---
+- [1]
+...
+s:get{1}
+---
+- [1]
+...
+s:insert{1}
+---
+- error: Duplicate key exists in unique index 'a' in space 'ephemeral'
+...
+s:insert{'1'}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:replace{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:get{1}
+---
+- [1]
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{'1'}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:get{'1'}
+---
+- ['1']
+...
+s:replace{'1'}
+---
+- ['1']
+...
+s:replace{1}
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected string'
+...
+i:drop()
+---
+...
+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:upsert({'1'}, {{'!', 2, 100}})
+---
+- error: 'Tuple field 1 type does not match one required by operation: expected unsigned'
+...
+s:upsert({1}, {{'a', 2, 100}})
+---
+- error: Unknown UPDATE operation
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:insert{1, 2, 3, 4, 5}
+---
+- [1, 2, 3, 4, 5]
+...
+s:update({1}, {{'#', 1, 1}})
+---
+- error: Attempt to modify a tuple field which is part of index 'a' in space 'ephemeral'
+...
+s:update({1}, {{'#', 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()
+---
+...
+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()
+---
+...
+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()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+---
+...
+s:insert{'1'}
+---
+- ['1']
+...
+s:insert{'5'}
+---
+- ['5']
+...
+s:insert{'6'}
+---
+- ['6']
+...
+s:insert{'11'}
+---
+- ['11']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['11']
+ - ['5']
+ - ['6']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['1']
+ - ['11']
+ - ['5']
+ - ['6']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['5']
+ - ['6']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+ - ['5']
+ - ['11']
+ - ['1']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['5']
+ - ['11']
+ - ['1']
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['6']
+ - ['5']
+ - ['11']
+ - ['1']
+...
+t = {} for state, v in i:pairs('5', {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - ['11']
+ - ['1']
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:insert{1}
+---
+- [1]
+...
+s:insert{5}
+---
+- [5]
+...
+s:insert{11}
+---
+- [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+ - [5]
+ - [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+ - [5]
+ - [11]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5]
+ - [11]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+ - [5]
+ - [1]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5]
+ - [1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11]
+ - [5]
+ - [1]
+...
+t = {} for state, v in i:pairs(5, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1]
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+---
+...
+s:insert{1, 1}
+---
+- [1, 1]
+...
+s:insert{5, 5}
+---
+- [5, 5]
+...
+s:insert{11, 11}
+---
+- [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'ALL'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+ - [5, 5]
+ - [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+ - [5, 5]
+ - [11, 11]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5, 5]
+ - [11, 11]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'GT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+ - [5, 5]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LE'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [5, 5]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [11, 11]
+ - [5, 5]
+ - [1, 1]
+...
+t = {} for state, v in i:pairs({5, 5}, {iterator = 'LT'}) do table.insert(t, v) end
+---
+...
+t
+---
+- - [1, 1]
+...
+i:drop()
+---
+...
+i = s:create_index('a')
+---
+...
+s:auto_increment{1}
+---
+- [1, 1]
+...
+s:auto_increment{2}
+---
+- [2, 2]
+...
+s:auto_increment{3}
+---
+- [3, 3]
+...
+s:pairs(2, 'GE'):totable()
+---
+- - [2, 2]
+ - [3, 3]
+...
+i:count({2}, 'GT')
+---
+- 1
+...
+i:drop()
+---
+...
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+---
+...
+s:replace{1}
+---
+- [1]
+...
+s:replace{2}
+---
+- [2]
+...
+s:delete{1}
+---
+- [1]
+...
+s:delete{2}
+---
+- [2]
+...
+s:select()
+---
+- []
+...
+i:drop()
+---
+...
+s:drop()
+---
+...
+test_run = require('test_run').new()
+---
+...
+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
+...
+idx:drop()
+---
+...
+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']
+...
+s:select()
+---
+- - ['1', 'AAAA']
+ - ['2', 'AAAA']
+ - ['20', 'AAAA']
+ - ['3', 'AAAA']
+ - ['30', 'AAAA']
+ - ['4', 'AAAA']
+ - ['40', 'AAAA']
+...
+i:max('15')
+---
+...
+i:min('15')
+---
+...
+s:count('15')
+---
+- 0
+...
+i:max()
+---
+- ['40', 'AAAA']
+...
+i:min()
+---
+- ['1', 'AAAA']
+...
+s: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()
+---
+...
+test_run:cmd("restart server default")
diff --git a/test/box/ephemeral_space.test.lua b/test/box/ephemeral_space.test.lua
index 93211c6..4c2bf22 100644
--- a/test/box/ephemeral_space.test.lua
+++ b/test/box/ephemeral_space.test.lua
@@ -89,3 +89,243 @@ i:drop()
i = s:create_index('a', {id = 10})
i = s:create_index('a', {type = 'bitset', parts = {1, 'unsigned', 2, 'unsigned'}})
+
+-- Ephemeral space: methods
+
+s = box.schema.space.create_ephemeral({field_count = 3})
+i = s:create_index('a')
+
+s:insert{1}
+s:insert{2,2,2}
+
+s:drop()
+
+s = box.schema.space.create_ephemeral()
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert{'1'}
+s:get{'1'}
+s:insert{'1'}
+s:insert{1}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert{1}
+s:get{1}
+s:insert{1}
+s:insert{'1'}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:replace{'1'}
+s:get{'1'}
+s:replace{'1'}
+s:replace{1}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{1}
+s:get{1}
+s:replace{1}
+s:replace{'1'}
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:replace{'1'}
+s:get{'1'}
+s:replace{'1'}
+s:replace{1}
+i:drop()
+
+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:upsert({'1'}, {{'!', 2, 100}})
+s:upsert({1}, {{'a', 2, 100}})
+
+i:drop()
+
+i = s:create_index('a')
+s:insert{1, 2, 3, 4, 5}
+s:update({1}, {{'#', 1, 1}})
+s:update({1}, {{'#', 1, "only one record please"}})
+i:drop()
+
+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()
+
+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()
+
+
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'string'} })
+s:insert{'1'}
+s:insert{'5'}
+s:insert{'6'}
+s:insert{'11'}
+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('5', {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs('5', {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('5', {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('5', {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:insert{1}
+s:insert{5}
+s:insert{11}
+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(5, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs(5, {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(5, {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(5, {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned', 2, 'unsigned'} })
+s:insert{1, 1}
+s:insert{5, 5}
+s:insert{11, 11}
+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({5, 5}, {iterator = 'GE'}) do table.insert(t, v) end
+t
+t = {} for state, v in i:pairs({5, 5}, {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({5, 5}, {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({5, 5}, {iterator = 'LT'}) do table.insert(t, v) end
+t
+i:drop()
+
+i = s:create_index('a')
+s:auto_increment{1}
+s:auto_increment{2}
+s:auto_increment{3}
+s:pairs(2, 'GE'):totable()
+i:count({2}, 'GT')
+i:drop()
+
+i = s:create_index('a', { type = 'tree', parts = {1, 'unsigned'} })
+s:replace{1}
+s:replace{2}
+s:delete{1}
+s:delete{2}
+s:select()
+i:drop()
+s:drop()
+
+test_run = require('test_run').new()
+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)
+idx:drop()
+
+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"})
+
+s:select()
+i:max('15')
+i:min('15')
+s:count('15')
+i:max()
+i:min()
+s: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()
+
+test_run:cmd("restart server default")
diff --git a/test/engine/iterator.result b/test/engine/iterator.result
index f39a15a..9e39a32 100644
--- a/test/engine/iterator.result
+++ b/test/engine/iterator.result
@@ -4213,7 +4213,7 @@ s:replace{35}
...
state, value = gen(param,state)
---
-- error: 'builtin/box/schema.lua:1180: usage: next(param, state)'
+- error: 'builtin/box/schema.lua:1182: usage: next(param, state)'
...
value
---
--
2.7.4
More information about the Tarantool-patches
mailing list