[Tarantool-patches] [PATCH] box: introduce "current" for sequence

olegrok at tarantool.org olegrok at tarantool.org
Fri Mar 6 19:34:16 MSK 2020


From: Oleg Babin <babinoleg at mail.ru>

This patch introduces "current" function for
sequences. It returns current value of
specified sequence or throws an error
if sequence is not initialized ("next" called
at least once).

This patch partitially reverts 3ff1f1e36e14381c0ebb5862943d4da281254767
Closes #4752

@TarantoolBot document
Title: sequence:current()

New function returns current value of sequence
of throws an error if used before sequence
initialization.

Example

```lua
sq = box.schema.sequence.create('test')
---
...
sq:current()
---
- error: Sequence is not initialized yet
...
sq:next()
---
- 1
...
sq:current()
---
- 1
...
sq:set(42)
---
...
sq:current()
---
- 42
...
```
---
Issue: https://github.com/tarantool/tarantool/issues/4752
Branch: https://github.com/tarantool/tarantool/tree/olegrok/4752-sequence-current
 src/box/box.cc             | 14 ++++++++
 src/box/box.h              | 12 +++++++
 src/box/errcode.h          |  1 +
 src/box/lua/schema.lua     |  4 +++
 src/box/lua/sequence.c     | 12 +++++++
 src/box/sequence.c         | 12 ++++---
 src/box/sequence.h         |  7 ++--
 src/box/sql/vdbe.c         |  5 ++-
 test/box/misc.result       |  1 +
 test/box/sequence.result   | 68 +++++++++++++++++++++++++++++++++++++-
 test/box/sequence.test.lua | 22 ++++++++++++
 11 files changed, 149 insertions(+), 9 deletions(-)

diff --git a/src/box/box.cc b/src/box/box.cc
index 09dd67ab4..a5052dba4 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1414,6 +1414,20 @@ box_sequence_next(uint32_t seq_id, int64_t *result)
 	*result = value;
 	return 0;
 }
+
+int
+box_sequence_current(uint32_t seq_id, int64_t *result)
+{
+	struct sequence *seq = sequence_cache_find(seq_id);
+	if (seq == NULL)
+		return -1;
+	if (access_check_sequence(seq) != 0)
+		return -1;
+	if (sequence_get_value(seq, result) != 0)
+		return -1;
+	return 0;
+}
+
 int
 box_sequence_set(uint32_t seq_id, int64_t value)
 {
diff --git a/src/box/box.h b/src/box/box.h
index f37a945eb..8fb723630 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -423,6 +423,18 @@ box_truncate(uint32_t space_id);
 API_EXPORT int
 box_sequence_next(uint32_t seq_id, int64_t *result);
 
+/**
+ * Returns current value of sequence.
+ *
+ * \param seq_id sequence identifier
+ * \param[out] result pointer to a variable where the current sequence
+ * value will be stored on success
+ * \retval -1 on error (check box_error_last())
+ * \retval 0 on success
+ */
+API_EXPORT int
+box_sequence_current(uint32_t seq_id, int64_t *result);
+
 /**
  * Set a sequence value.
  *
diff --git a/src/box/errcode.h b/src/box/errcode.h
index d7ec97e8c..444171778 100644
--- a/src/box/errcode.h
+++ b/src/box/errcode.h
@@ -264,6 +264,7 @@ struct errcode_record {
 	/*209 */_(ER_SESSION_SETTING_INVALID_VALUE,	"Session setting %s expected a value of type %s") \
 	/*210 */_(ER_SQL_PREPARE,		"Failed to prepare SQL statement: %s") \
 	/*211 */_(ER_WRONG_QUERY_ID,		"Prepared statement with id %u does not exist") \
+	/*212 */_(ER_SEQUENCE_NOT_STARTED,		"Sequence '%s' is not started") \
 
 /*
  * !IMPORTANT! Please follow instructions at start of the file
diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua
index f537c3cec..0cd747350 100644
--- a/src/box/lua/schema.lua
+++ b/src/box/lua/schema.lua
@@ -1812,6 +1812,10 @@ sequence_mt.next = function(self)
     return internal.sequence.next(self.id)
 end
 
+sequence_mt.current = function(self)
+    return internal.sequence.current(self.id)
+end
+
 sequence_mt.set = function(self, value)
     return internal.sequence.set(self.id, value)
 end
diff --git a/src/box/lua/sequence.c b/src/box/lua/sequence.c
index bf0714c1a..ae4b5d3ce 100644
--- a/src/box/lua/sequence.c
+++ b/src/box/lua/sequence.c
@@ -49,6 +49,17 @@ lbox_sequence_next(struct lua_State *L)
 	return 1;
 }
 
+static int
+lbox_sequence_current(struct lua_State *L)
+{
+	uint32_t seq_id = luaL_checkinteger(L, 1);
+	int64_t result;
+	if (box_sequence_current(seq_id, &result) != 0)
+		luaT_error(L);
+	luaL_pushint64(L, result);
+	return 1;
+}
+
 static int
 lbox_sequence_set(struct lua_State *L)
 {
@@ -174,6 +185,7 @@ box_lua_sequence_init(struct lua_State *L)
 {
 	static const struct luaL_Reg sequence_internal_lib[] = {
 		{"next", lbox_sequence_next},
+		{"current", lbox_sequence_current},
 		{"set", lbox_sequence_set},
 		{"reset", lbox_sequence_reset},
 		{NULL, NULL}
diff --git a/src/box/sequence.c b/src/box/sequence.c
index 5ebfa2747..4afbc2666 100644
--- a/src/box/sequence.c
+++ b/src/box/sequence.c
@@ -367,14 +367,18 @@ sequence_data_iterator_create(void)
 	return &iter->base;
 }
 
-int64_t
-sequence_get_value(struct sequence *seq)
+int
+sequence_get_value(struct sequence *seq, int64_t *result)
 {
 	uint32_t key = seq->def->id;
 	uint32_t hash = sequence_hash(key);
 	uint32_t pos = light_sequence_find_key(&sequence_data_index, hash, key);
-	assert(pos != light_sequence_end);
+	if (pos == light_sequence_end) {
+		diag_set(ClientError, ER_SEQUENCE_NOT_STARTED, seq->def->name);
+		return -1;
+	}
 	struct sequence_data data = light_sequence_get(&sequence_data_index,
 						       pos);
-	return data.value;
+	*result = data.value;
+	return 0;
 }
diff --git a/src/box/sequence.h b/src/box/sequence.h
index a164da9af..8c442872a 100644
--- a/src/box/sequence.h
+++ b/src/box/sequence.h
@@ -171,10 +171,11 @@ sequence_data_iterator_create(void);
  * Get last element of given sequence.
  *
  * @param seq sequence to get value from.
- * @retval last element of sequence.
+ * @result value of sequence.
+ * Return 0 on success, -1 if sequence is not initialized.
  */
-int64_t
-sequence_get_value(struct sequence *seq);
+int
+sequence_get_value(struct sequence *seq, int64_t *result);
 
 #if defined(__cplusplus)
 } /* extern "C" */
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 912a10153..0de07ca1d 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4328,7 +4328,10 @@ case OP_IdxInsert: {
 		p->nChange++;
 	if (pOp->p3 > 0 && ((aMem[pOp->p3].flags) & MEM_Null) != 0) {
 		assert(space->sequence != NULL);
-		int64_t value = sequence_get_value(space->sequence);
+		int64_t value;
+		if (sequence_get_value(space->sequence, &value) != 0) {
+			goto abort_due_to_error;
+		}
 		if (vdbe_add_new_autoinc_id(p, value) != 0)
 			goto abort_due_to_error;
 	}
diff --git a/test/box/misc.result b/test/box/misc.result
index 5ac5e0f26..047591b60 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -636,6 +636,7 @@ t;
   209: box.error.SESSION_SETTING_INVALID_VALUE
   210: box.error.SQL_PREPARE
   211: box.error.WRONG_QUERY_ID
+  212: box.error.SEQUENCE_NOT_STARTED
 ...
 test_run:cmd("setopt delimiter ''");
 ---
diff --git a/test/box/sequence.result b/test/box/sequence.result
index 0a6cfee2c..2eee1ba99 100644
--- a/test/box/sequence.result
+++ b/test/box/sequence.result
@@ -188,10 +188,18 @@ sq.step, sq.min, sq.max, sq.start, sq.cycle
 - 1
 - false
 ...
+sq:current()  -- error
+---
+- error: Sequence 'test' is not started
+...
 sq:next() -- 1
 ---
 - 1
 ...
+sq:current()  -- 1
+---
+- 1
+...
 sq:next() -- 2
 ---
 - 2
@@ -199,6 +207,10 @@ sq:next() -- 2
 sq:set(100)
 ---
 ...
+sq:current()  -- 100
+---
+- 100
+...
 sq:next() -- 101
 ---
 - 101
@@ -210,6 +222,10 @@ sq:next() -- 102
 sq:reset()
 ---
 ...
+sq:current()  -- error
+---
+- error: Sequence 'test' is not started
+...
 sq:next() -- 1
 ---
 - 1
@@ -233,10 +249,18 @@ sq.step, sq.min, sq.max, sq.start, sq.cycle
 - -1
 - false
 ...
+sq:current()  -- error
+---
+- error: Sequence 'test' is not started
+...
 sq:next() -- -1
 ---
 - -1
 ...
+sq:current()  -- -1
+---
+- -1
+...
 sq:next() -- -2
 ---
 - -2
@@ -244,6 +268,10 @@ sq:next() -- -2
 sq:set(-100)
 ---
 ...
+sq:current()  -- -100
+---
+- -100
+...
 sq:next() -- -101
 ---
 - -101
@@ -255,6 +283,10 @@ sq:next() -- -102
 sq:reset()
 ---
 ...
+sq:current()  -- error
+---
+- error: Sequence 'test' is not started
+...
 sq:next() -- -1
 ---
 - -1
@@ -1428,7 +1460,7 @@ box.schema.user.info()
     - _priv
   - - session,usage
     - universe
-    - 
+    -
   - - alter
     - user
     - user
@@ -2289,3 +2321,37 @@ box.space._space_sequence:update({s.id}, {{'=', 2, t[2]}})
 s:drop()
 ---
 ...
+--
+-- gh-4752: introduce sequence:current() method which
+-- fetches current sequence value but doesn't modify
+-- sequence itself.
+--
+sq = box.schema.sequence.create('test')
+---
+...
+sq:current()
+---
+- error: Sequence 'test' is not started
+...
+sq:next()
+---
+- 1
+...
+sq:current()
+---
+- 1
+...
+sq:set(42)
+---
+...
+sq:current()
+---
+- 42
+...
+sq:current()
+---
+- 42
+...
+sq:drop()
+---
+...
diff --git a/test/box/sequence.test.lua b/test/box/sequence.test.lua
index 8e00571e5..2342178e3 100644
--- a/test/box/sequence.test.lua
+++ b/test/box/sequence.test.lua
@@ -58,12 +58,16 @@ box.sequence.test == nil
 -- Default ascending sequence.
 sq = box.schema.sequence.create('test')
 sq.step, sq.min, sq.max, sq.start, sq.cycle
+sq:current()  -- error
 sq:next() -- 1
+sq:current()  -- 1
 sq:next() -- 2
 sq:set(100)
+sq:current()  -- 100
 sq:next() -- 101
 sq:next() -- 102
 sq:reset()
+sq:current()  -- error
 sq:next() -- 1
 sq:next() -- 2
 sq:drop()
@@ -71,12 +75,16 @@ sq:drop()
 -- Default descending sequence.
 sq = box.schema.sequence.create('test', {step = -1})
 sq.step, sq.min, sq.max, sq.start, sq.cycle
+sq:current()  -- error
 sq:next() -- -1
+sq:current()  -- -1
 sq:next() -- -2
 sq:set(-100)
+sq:current()  -- -100
 sq:next() -- -101
 sq:next() -- -102
 sq:reset()
+sq:current()  -- error
 sq:next() -- -1
 sq:next() -- -2
 sq:drop()
@@ -780,3 +788,17 @@ pk = s:create_index('pk', {sequence = true})
 t = box.space._space_sequence:get({s.id})
 box.space._space_sequence:update({s.id}, {{'=', 2, t[2]}})
 s:drop()
+
+--
+-- gh-4752: introduce sequence:current() method which
+-- fetches current sequence value but doesn't modify
+-- sequence itself.
+--
+sq = box.schema.sequence.create('test')
+sq:current()
+sq:next()
+sq:current()
+sq:set(42)
+sq:current()
+sq:current()
+sq:drop()
-- 
2.23.0



More information about the Tarantool-patches mailing list