diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml
index 9f95b4d54731379862dd233ace2665859810f4e0..34f1c140681796660cd744b8930cd50b2da9bd8b 100644
--- a/doc/user/stored-procedures.xml
+++ b/doc/user/stored-procedures.xml
@@ -908,11 +908,11 @@ localhost> lua box.counter.dec(0, 'top.mail.ru')
 
 <variablelist>
     <title>Package <code xml:id="box.tuple" xreflabel="box.tuple">box.tuple</code></title>
-    <para>The package contains no functions, but stands for
-    <code>box.tuple</code> userdata type. It is possible to access individual
-    tuple fields using an index, select a range of fields, iterate
-    over all fields in a tuple or convert a tuple to a Lua table.
-    Tuples are immutable.</para>
+    <para>The package stands for <code>box.tuple</code> userdata
+    type. It is possible to access individual tuple fields using
+    an index, select a range of fields, iterate over all fields in
+    a tuple or convert a tuple to a Lua table.  Tuples are
+    immutable.</para>
     <varlistentry>
         <term><emphasis role="lua"> </emphasis></term>
         <listitem><para>
@@ -1000,6 +1000,19 @@ localhost> lua t:find(1, 'abc')
 
         </para></listitem>
     </varlistentry>
+    <varlistentry>
+        <term><emphasis role="lua">box.tuple.new(...)</emphasis></term>
+        <listitem><para>
+        Construct a new tuple from a Lua table or a scalar. 
+        </para>
+            <bridgehead renderas="sect4">Example</bridgehead>
+            <programlisting>localhost> lua box.tuple.new({tonumber64('18446744073709551615'), 'string', 1})
+--- 
+ - 18446744073709551615: {'string', 1}
+... 
+</programlisting>
+        </listitem>
+    </varlistentry>
 </variablelist>
 
 <variablelist>
diff --git a/src/box/box.lua b/src/box/box.lua
index 2f68c47aa841c94a1b694fe96d50c675ffb4f146..e067fa0d4a02a4deec50878c56c6094d6c562626 100644
--- a/src/box/box.lua
+++ b/src/box/box.lua
@@ -244,11 +244,15 @@ function box.on_reload_configuration()
     space_mt.replace = function(space, ...) return box.replace(space.n, ...) end
     space_mt.delete = function(space, ...) return box.delete(space.n, ...) end
     space_mt.truncate = function(space)
-        local pk = space.index[0].idx
-        local part_count = pk:part_count()
-        while #pk > 0 do
-            for k, v in pk.next, pk, nil do
-                space:delete(v:slice(0, part_count))
+        local pk = space.index[0]
+        while #pk.idx > 0 do
+            for _k, t in pk.idx.next, pk.idx, nil do
+                local key = {};
+                -- ipairs does not work because pk.key_field is zero-indexed
+                for _k2, key_field in pairs(pk.key_field) do
+                    table.insert(key, t[key_field.fieldno])
+                end
+                space:delete(unpack(key))
             end
         end
     end
diff --git a/src/box/box_lua.m b/src/box/box_lua.m
index ea505c424c7879367a5c055a2a40e53945b28980..fabd7617549c925fd548e64d7ab77d81d4f76934 100644
--- a/src/box/box_lua.m
+++ b/src/box/box_lua.m
@@ -79,6 +79,9 @@ static const char *tuplelib_name = "box.tuple";
 static void
 lbox_pushtuple(struct lua_State *L, struct tuple *tuple);
 
+static struct tuple *
+lua_totuple(struct lua_State *L, int index);
+
 static inline struct tuple *
 lua_checktuple(struct lua_State *L, int narg)
 {
@@ -100,6 +103,17 @@ lua_istuple(struct lua_State *L, int narg)
 	return tuple;
 }
 
+static int
+lbox_tuple_new(lua_State *L)
+{
+	int argc = lua_gettop(L);
+	if (argc < 1)
+		luaL_error(L, "tuple.new(): bad arguments");
+	struct tuple *tuple = lua_totuple(L, 1);
+	lbox_pushtuple(L, tuple);
+	return 1;
+}
+
 static int
 lbox_tuple_gc(struct lua_State *L)
 {
@@ -495,7 +509,7 @@ lbox_tuple_pairs(struct lua_State *L)
 	return 3;
 }
 
-static const struct luaL_reg lbox_tuple_meta [] = {
+static const struct luaL_reg lbox_tuple_meta[] = {
 	{"__gc", lbox_tuple_gc},
 	{"__len", lbox_tuple_len},
 	{"__index", lbox_tuple_index},
@@ -510,6 +524,11 @@ static const struct luaL_reg lbox_tuple_meta [] = {
 	{NULL, NULL}
 };
 
+static const struct luaL_reg lbox_tuplelib[] = {
+	{"new", lbox_tuple_new},
+	{NULL, NULL}
+};
+
 /* }}} */
 
 /** {{{ box.index Lua library: access to spaces and indexes
@@ -1012,8 +1031,8 @@ lua_table_to_tuple(struct lua_State *L, int index)
 	return tuple;
 }
 
-static void
-port_add_lua_ret(struct port *port, struct lua_State *L, int index)
+static struct tuple*
+lua_totuple(struct lua_State *L, int index)
 {
 	int type = lua_type(L, index);
 	struct tuple *tuple;
@@ -1073,6 +1092,13 @@ port_add_lua_ret(struct port *port, struct lua_State *L, int index)
 		tnt_raise(ClientError, :ER_PROC_RET, lua_typename(L, type));
 		break;
 	}
+	return tuple;
+}
+
+static void
+port_add_lua_ret(struct port *port, struct lua_State *L, int index)
+{
+	struct tuple *tuple = lua_totuple(L, index);
 	@try {
 		port_add_tuple(port, tuple, BOX_RETURN_TUPLE);
 	} @finally {
@@ -1230,6 +1256,8 @@ mod_lua_init(struct lua_State *L)
 {
 	/* box, box.tuple */
 	tarantool_lua_register_type(L, tuplelib_name, lbox_tuple_meta);
+	luaL_register(L, tuplelib_name, lbox_tuplelib);
+	lua_pop(L, 1);
 	luaL_register(L, "box", boxlib);
 	lua_pop(L, 1);
 	/* box.index */
diff --git a/src/box/index.m b/src/box/index.m
index ca67def06477c481d5127e5a2bb62815f7d4e0b6..6e7f1fdaf4992958d3e47413d816aa106ef5bad1 100644
--- a/src/box/index.m
+++ b/src/box/index.m
@@ -46,19 +46,6 @@ static struct index_traits hash_index_traits = {
 const char *field_data_type_strs[] = {"NUM", "NUM64", "STR", "\0"};
 const char *index_type_strs[] = { "HASH", "TREE", "\0" };
 
-static struct tuple *
-iterator_next_equal(struct iterator *it __attribute__((unused)))
-{
-	return NULL;
-}
-
-static struct tuple *
-iterator_first_equal(struct iterator *it)
-{
-	it->next_equal = iterator_next_equal;
-	return it->next(it);
-}
-
 static void
 check_key_parts(struct key_def *key_def,
 		int part_count, bool partial_key_allowed)
@@ -261,25 +248,38 @@ check_key_parts(struct key_def *key_def,
 
 /* }}} */
 
-/* {{{ HashIndex -- base class for all hashes. ********************/
+/* {{{ HashIndex Iterators ****************************************/
 
-struct hash_iterator {
+struct hash_i32_iterator {
 	struct iterator base; /* Must be the first member. */
 	struct mh_i32ptr_t *hash;
 	mh_int_t h_pos;
 };
 
-static struct hash_iterator *
-hash_iterator(struct iterator *it)
+struct hash_i64_iterator {
+	struct iterator base;
+	struct mh_i64ptr_t *hash;
+	mh_int_t h_pos;
+};
+
+struct hash_lstr_iterator {
+	struct iterator base;
+	struct mh_lstrptr_t *hash;
+	mh_int_t h_pos;
+};
+
+void
+hash_iterator_free(struct iterator *iterator)
 {
-	return (struct hash_iterator *) it;
+	assert(iterator->free == hash_iterator_free);
+	free(iterator);
 }
 
 struct tuple *
-hash_iterator_next(struct iterator *iterator)
+hash_iterator_i32_ge(struct iterator *ptr)
 {
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(ptr->free == hash_iterator_free);
+	struct hash_i32_iterator *it = (struct hash_i32_iterator *) ptr;
 
 	while (it->h_pos < mh_end(it->hash)) {
 		if (mh_exist(it->hash, it->h_pos))
@@ -289,13 +289,64 @@ hash_iterator_next(struct iterator *iterator)
 	return NULL;
 }
 
-void
-hash_iterator_free(struct iterator *iterator)
+struct tuple *
+hash_iterator_i64_ge(struct iterator *ptr)
 {
-	assert(iterator->next == hash_iterator_next);
-	free(iterator);
+	assert(ptr->free == hash_iterator_free);
+	struct hash_i64_iterator *it = (struct hash_i64_iterator *) ptr;
+
+	while (it->h_pos < mh_end(it->hash)) {
+		if (mh_exist(it->hash, it->h_pos))
+			return mh_value(it->hash, it->h_pos++);
+		it->h_pos++;
+	}
+	return NULL;
+}
+
+struct tuple *
+hash_iterator_lstr_ge(struct iterator *ptr)
+{
+	assert(ptr->free == hash_iterator_free);
+	struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) ptr;
+
+	while (it->h_pos < mh_end(it->hash)) {
+		if (mh_exist(it->hash, it->h_pos))
+			return mh_value(it->hash, it->h_pos++);
+		it->h_pos++;
+	}
+	return NULL;
+}
+
+static struct tuple *
+hash_iterator_eq_next(struct iterator *it __attribute__((unused)))
+{
+	return NULL;
+}
+
+static struct tuple *
+hash_iterator_i32_eq(struct iterator *it)
+{
+	it->next_equal = hash_iterator_eq_next;
+	return hash_iterator_i32_ge(it);
+}
+
+static struct tuple *
+hash_iterator_i64_eq(struct iterator *it)
+{
+	it->next_equal = hash_iterator_eq_next;
+	return hash_iterator_i64_ge(it);
+}
+
+static struct tuple *
+hash_iterator_lstr_eq(struct iterator *it)
+{
+	it->next_equal = hash_iterator_eq_next;
+	return hash_iterator_lstr_ge(it);
 }
 
+/* }}} */
+
+/* {{{ HashIndex -- base class for all hashes. ********************/
 
 @implementation HashIndex
 
@@ -370,17 +421,6 @@ hash_iterator_free(struct iterator *iterator)
 	return [self findUnsafe :field :1];
 }
 
-- (struct iterator *) allocIterator
-{
-	struct hash_iterator *it = malloc(sizeof(struct hash_iterator));
-	if (it) {
-		memset(it, 0, sizeof(struct hash_iterator));
-		it->base.next = hash_iterator_next;
-		it->base.free = hash_iterator_free;
-	}
-	return (struct iterator *) it;
-}
-
 @end
 
 /* }}} */
@@ -479,10 +519,21 @@ int32_key_to_value(void *key)
 #endif
 }
 
+- (struct iterator *) allocIterator
+{
+	struct hash_i32_iterator *it = malloc(sizeof(struct hash_i32_iterator));
+	if (it) {
+		memset(it, 0, sizeof(*it));
+		it->base.next = hash_iterator_i32_ge;
+		it->base.free = hash_iterator_free;
+	}
+	return (struct iterator *) it;
+}
+
 - (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type
 {
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_i32_ge);
+	struct hash_i32_iterator *it = (struct hash_i32_iterator *) iterator;
 
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
@@ -499,11 +550,11 @@ int32_key_to_value(void *key)
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
 
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_i32_ge);
+	struct hash_i32_iterator *it = (struct hash_i32_iterator *) iterator;
 
 	u32 num = int32_key_to_value(key);
-	it->base.next_equal = iterator_first_equal;
+	it->base.next_equal = hash_iterator_i32_eq;
 	it->h_pos = mh_i32ptr_get(int_hash, num);
 	it->hash = int_hash;
 }
@@ -602,17 +653,28 @@ int64_key_to_value(void *key)
 #endif
 }
 
+- (struct iterator *) allocIterator
+{
+	struct hash_i64_iterator *it = malloc(sizeof(struct hash_i64_iterator));
+	if (it) {
+		memset(it, 0, sizeof(*it));
+		it->base.next = hash_iterator_i64_ge;
+		it->base.free = hash_iterator_free;
+	}
+	return (struct iterator *) it;
+}
+
 - (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type
 {
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_i64_ge);
+	struct hash_i64_iterator *it = (struct hash_i64_iterator *) iterator;
 
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
 
 	it->base.next_equal = 0; /* Should not be used if not positioned. */
 	it->h_pos = mh_begin(int64_hash);
-	it->hash = (struct mh_i32ptr_t *) int64_hash;
+	it->hash = int64_hash;
 }
 
 - (void) initIteratorUnsafe: (struct iterator *) iterator :(enum iterator_type) type
@@ -622,14 +684,14 @@ int64_key_to_value(void *key)
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
 
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_i64_ge);
+	struct hash_i64_iterator *it = (struct hash_i64_iterator *) iterator;
 
 	u64 num = int64_key_to_value(key);
 
-	it->base.next_equal = iterator_first_equal;
+	it->base.next_equal = hash_iterator_i64_eq;
 	it->h_pos = mh_i64ptr_get(int64_hash, num);
-	it->hash = (struct mh_i32ptr_t *) int64_hash;
+	it->hash = int64_hash;
 }
 @end
 
@@ -720,17 +782,29 @@ int64_key_to_value(void *key)
 #endif
 }
 
+- (struct iterator *) allocIterator
+{
+	struct hash_lstr_iterator *it = malloc(sizeof(struct hash_lstr_iterator));
+	if (it) {
+		memset(it, 0, sizeof(*it));
+		it->base.next = hash_iterator_lstr_ge;
+		it->base.free = hash_iterator_free;
+	}
+	return (struct iterator *) it;
+}
+
+
 - (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type
 {
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_lstr_ge);
+	struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) iterator;
 
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
 
 	it->base.next_equal = 0; /* Should not be used if not positioned. */
 	it->h_pos = mh_begin(str_hash);
-	it->hash = (struct mh_i32ptr_t *) str_hash;
+	it->hash = str_hash;
 }
 
 - (void) initIteratorUnsafe: (struct iterator *) iterator
@@ -741,12 +815,12 @@ int64_key_to_value(void *key)
 	if (type == ITER_REVERSE)
 		tnt_raise(IllegalParams, :"hash iterator is forward only");
 
-	assert(iterator->next == hash_iterator_next);
-	struct hash_iterator *it = hash_iterator(iterator);
+	assert(iterator->next == hash_iterator_lstr_ge);
+	struct hash_lstr_iterator *it = (struct hash_lstr_iterator *) iterator;
 
-	it->base.next_equal = iterator_first_equal;
+	it->base.next_equal = hash_iterator_lstr_eq;
 	it->h_pos = mh_lstrptr_get(str_hash, key);
-	it->hash = (struct mh_i32ptr_t *) str_hash;
+	it->hash = str_hash;
 }
 @end
 
diff --git a/test/big/lua.result b/test/big/lua.result
index 6698c0b0fdd27fa686b9f4ea6f2367fddede0481..e6b2e3261694f82d0316c3e9f109cc6aa3da3178 100644
--- a/test/big/lua.result
+++ b/test/big/lua.result
@@ -557,3 +557,37 @@ error: 'Duplicate key exists in unique index 1'
 lua box.space[1]:truncate()
 ---
 ...
+#
+# A test case for Bug #1042798
+# Truncate hangs when primary key is not in linear or starts at the first field
+# https://bugs.launchpad.net/tarantool/+bug/1042798
+#
+lua for k, f in pairs(box.space[23].index[0].key_field) do print(k, ' => ', f.fieldno) end
+---
+0 => 2
+1 => 1
+...
+lua box.insert(23, 1, 2, 3, 4)
+---
+ - 1: {2, 3, 4}
+...
+lua box.insert(23, 10, 20, 30, 40)
+---
+ - 10: {20, 30, 40}
+...
+lua box.insert(23, 20, 30, 40, 50)
+---
+ - 20: {30, 40, 50}
+...
+lua for _k, v in box.space[23]:pairs() do print(v) end
+---
+1: {2, 3, 4}
+10: {20, 30, 40}
+20: {30, 40, 50}
+...
+lua box.space[23]:truncate()
+---
+...
+lua for _k, v in box.space[23]:pairs() do print(v) end
+---
+...
diff --git a/test/big/lua.test b/test/big/lua.test
index a3f0bdf005338f714637f88f69cc126b0767a809..2f90fb5ef18ac6297cfefebbf07ccf2ec013ac6b 100644
--- a/test/big/lua.test
+++ b/test/big/lua.test
@@ -205,3 +205,20 @@ print """# Test that we print index number in error ER_INDEX_VIOLATION"""
 exec admin "lua box.space[1]:insert(1, 'hello', 'world')"
 exec admin "lua box.space[1]:insert(2, 'hello', 'world')"
 exec admin "lua box.space[1]:truncate()"
+
+print """#
+# A test case for Bug #1042798
+# Truncate hangs when primary key is not in linear or starts at the first field
+# https://bugs.launchpad.net/tarantool/+bug/1042798
+#"""
+
+# Print key fields in pk
+exec admin "lua for k, f in pairs(box.space[23].index[0].key_field) do print(k, ' => ', f.fieldno) end"
+exec admin "lua box.insert(23, 1, 2, 3, 4)"
+exec admin "lua box.insert(23, 10, 20, 30, 40)"
+exec admin "lua box.insert(23, 20, 30, 40, 50)"
+exec admin "lua for _k, v in box.space[23]:pairs() do print(v) end"
+# Truncate must not hang
+exec admin "lua box.space[23]:truncate()"
+# Empty result
+exec admin "lua for _k, v in box.space[23]:pairs() do print(v) end"
diff --git a/test/big/tarantool.cfg b/test/big/tarantool.cfg
index 6bea4bc90024896075b87899402ed716a53277fa..06c6c576a70f5f7e656e2be8e45395bea327c757 100644
--- a/test/big/tarantool.cfg
+++ b/test/big/tarantool.cfg
@@ -243,3 +243,12 @@ space[19].index[0].key_field[0].fieldno = 0
 space[19].index[0].key_field[0].type = "NUM"
 space[19].index[0].key_field[1].fieldno = 2
 space[19].index[0].key_field[1].type = "NUM"
+
+# Space #23, https://bugs.launchpad.net/tarantool/+bug/1042798
+space[23].enabled = 1
+space[23].index[0].type = "TREE"
+space[23].index[0].unique = 1
+space[23].index[0].key_field[0].fieldno = 2
+space[23].index[0].key_field[0].type = "NUM"
+space[23].index[0].key_field[1].fieldno = 1
+space[23].index[0].key_field[1].type = "NUM"
diff --git a/test/box/lua.result b/test/box/lua.result
index 429192fad9f45fa5a4a1f06108f5c440b317a94c..3b091689e690971ce16c65b4ad5fb0636a2bbc15 100644
--- a/test/box/lua.result
+++ b/test/box/lua.result
@@ -15,29 +15,30 @@ lua for n in pairs(box) do print('  - box.', n) end
   - box.fiber
   - box.select_reverse_range
   - box.uuid
-  - box.ipc
+  - box.select_limit
   - box.delete
-  - box.replace
   - box.space
+  - box.replace
   - box.cfg
   - box.on_reload_configuration
+  - box.counter
   - box.select_range
   - box.insert
-  - box.counter
   - box.auto_increment
+  - box.update
   - box.info
   - box.session
   - box.uuid_hex
-  - box.update
+  - box.select
   - box.dostring
   - box.process
-  - box.select_limit
+  - box.ipc
   - box.slab
-  - box.select
+  - box.stat
   - box.flags
   - box.unpack
+  - box.tuple
   - box.index
-  - box.stat
   - box.pack
 ...
 lua box.pack()
@@ -1731,3 +1732,24 @@ lua tostring(tonumber64(tonumber64(3)))
 ---
  - 3ULL
 ...
+# box.tuple.new test
+lua box.tuple.new()
+---
+error: 'tuple.new(): bad arguments'
+...
+lua box.tuple.new(1)
+---
+ - 1: {}
+...
+lua box.tuple.new('string')
+---
+ - 'string': {}
+...
+lua box.tuple.new(tonumber64('18446744073709551615'))
+---
+ - 18446744073709551615: {}
+...
+lua box.tuple.new({tonumber64('18446744073709551615'), 'string', 1})
+---
+ - 18446744073709551615: {'string', 1}
+...
diff --git a/test/box/lua.test b/test/box/lua.test
index 5b869eb5ed4ad752d8263ce2f31ef8cc621cc488..778f01daa7358c7824529dd340301c3f8969af3b 100644
--- a/test/box/lua.test
+++ b/test/box/lua.test
@@ -577,3 +577,10 @@ exec admin "lua bit.bor(1, 2)"
 print """# A test case for Bug#1061747 'tonumber64 is not transitive'"""
 exec admin "lua tonumber64(tonumber64(2))"
 exec admin "lua tostring(tonumber64(tonumber64(3)))"
+
+print """# box.tuple.new test"""
+exec admin "lua box.tuple.new()"
+exec admin "lua box.tuple.new(1)"
+exec admin "lua box.tuple.new('string')"
+exec admin "lua box.tuple.new(tonumber64('18446744073709551615'))"
+exec admin "lua box.tuple.new({tonumber64('18446744073709551615'), 'string', 1})"