or metrics routine) and calls DML executor. However, it isn't available
for other modules (i.e. declared as static). On the other hand, it seems
rid of redundant space lookup. Thus, lets rename it to
* Box: callbacks into the request processor.
* (master->slave propagation).
+ * However, it makes space lookup. If space is already obtained,
+ * one can simply use internal box_process_rw().
+ * Execute request on given space.
/*
* The function assumes the cursor is open on _schema.
- * Increment max_id and store updated tuple in the cursor
- * object.
+ * Increment max_id and store updated value it output parameter.
*/
-int tarantoolSqlite3IncrementMaxid(BtCursor *pCur)
+int tarantoolSqlite3IncrementMaxid(uint64_t *space_max_id)
{
- assert(pCur->curFlags & BTCF_TaCursor);
/* ["max_id"] */
static const char key[] = {
(char)0x91, /* MsgPack array(1) */
@@ -1035,6 +1050,8 @@ int tarantoolSqlite3IncrementMaxid(BtCursor *pCur)
struct tuple *res = NULL;
int rc;
+ struct space *space_schema = space_by_id(BOX_SCHEMA_ID);
+ assert(space_schema != NULL);
struct request request;
memset(&request, 0, sizeof(request));
request.tuple = ops;
@@ -1042,18 +1059,14 @@ int tarantoolSqlite3IncrementMaxid(BtCursor *pCur)
request.key = key;
request.key_end = key + sizeof(key);
request.type = IPROTO_UPDATE;
- request.space_id = pCur->space->def->id;
- rc = box_process_rw(&request, pCur->space, &res);
+ request.space_id = space_schema->def->id;
+ rc = box_process_rw(&request, space_schema, &res);
if (rc != 0 || res == NULL) {
return SQL_TARANTOOL_ERROR;
}
- if (pCur->last_tuple != NULL) {
- box_tuple_unref(pCur->last_tuple);
- }
- box_tuple_ref(res);
- pCur->last_tuple = res;
- pCur->eState = CURSOR_VALID;
- return SQLITE_OK;
+ rc = tuple_field_u64(res, 1, space_max_id);
+ (*space_max_id)++;
+ return rc == 0 ? SQLITE_OK : SQL_TARANTOOL_ERROR;
}
/*
@@ -1633,25 +1646,20 @@ int tarantoolSqlite3EphemeralGetMaxId(BtCursor *pCur, uint32_t fieldno,
}
/**
- * Extract maximum integer value from:
- * @param index space_id
- * @param index_id
- * @param field number fieldno
- * @param[out] fetched value in max_id
+ * Extract next id from _sequence space.
+ * If index is empty - return 0 in max_id and success status
*
+ * @param[out] max_id Fetched value.
* @retval 0 on success, -1 otherwise.
- *
- * If index is empty - return 0 in max_id and success status
*/
int
-tarantoolSqlGetMaxId(BtCursor *cur, uint32_t fieldno,
- uint64_t *max_id)
+tarantoolSqlNextSeqId(uint64_t *max_id)
{
char key[16];
struct tuple *tuple;
char *key_end = mp_encode_array(key, 0);
- if (box_index_max(cur->space->def->id, cur->index->def->iid,
- key, key_end, &tuple) != 0)
+ if (box_index_max(BOX_SEQUENCE_ID, 0 /* PK */, key,
+ key_end, &tuple) != 0)
return -1;
/* Index is empty */
@@ -1660,5 +1668,5 @@ tarantoolSqlGetMaxId(BtCursor *cur, uint32_t fieldno,
return 0;
}
- return tuple_field_u64(tuple, fieldno, max_id);
+ return tuple_field_u64(tuple, 0, max_id);
}
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index d5b0f6001..db7ffe24e 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2018,7 +2018,8 @@ sqlite3EndTable(Parse * pParse, /* Parse context */
sqlite3OpenTable(pParse, iCursor, sys_sequence,
OP_OpenWrite);
reg_seq_id = ++pParse->nMem;
- sqlite3VdbeAddOp3(v, OP_NextId, iCursor, 0, reg_seq_id);
+ sqlite3VdbeAddOp3(v, OP_NextSequenceId, iCursor, 0,
+ reg_seq_id);
reg_seq_record = emitNewSysSequenceRecord(pParse,
reg_seq_id,
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -77,6 +77,7 @@ int tarantoolSqlite3Count(BtCursor * pCur, i64 * pnEntry);
int tarantoolSqlite3Insert(BtCursor * pCur);
int tarantoolSqlite3Replace(BtCursor * pCur);
int tarantoolSqlite3Delete(BtCursor * pCur, u8 flags);
+int sql_delete_by_key(struct space *space, char *key, uint32_t key_size);
int tarantoolSqlite3ClearTable(struct space *space);
/* Rename table pTab with zNewName by inserting new tuple to _space.
@@ -112,11 +113,10 @@ int tarantoolSqlite3IdxKeyCompare(BtCursor * pCur, UnpackedRecord * pUnpacked,
int *res);
/*
- * The function assumes the cursor is open on _schema.
- * Increment max_id and store updated tuple in the cursor
- * object.
+ * The function assumes to be applied on _schema space.
+ * Increment max_id and store updated id in given argument.
*/
-int tarantoolSqlite3IncrementMaxid(BtCursor * pCur);
+int tarantoolSqlite3IncrementMaxid(uint64_t *space_max_id);
/*
* Render "format" array for _space entry.
@@ -147,8 +147,6 @@ int tarantoolSqlite3MakeIdxParts(Index * index, void *buf);
int tarantoolSqlite3MakeIdxOpts(Index * index, const char *zSql, void *buf);
/*
- * Fetch maximum value from ineger column number `fieldno` of space_id/index_id
- * Return 0 on success, -1 otherwise
+ * Fetch next id from _sequence space.
*/
-int tarantoolSqlGetMaxId(BtCursor *cur, uint32_t fieldno,
- uint64_t * max_id);
+int tarantoolSqlNextSeqId(uint64_t *max_id);
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 0ae682f9e..3d9ac8e26 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -3830,28 +3830,16 @@ case OP_Sequence: { /* out2 */
break;
}
-/* Opcode: NextId P1 P2 P3 * *
- * Synopsis: r[P3]=get_max(space_index[P1]{Column[P2]})
+/* Opcode: NextSequenceId * P2 * * *
+ * Synopsis: r[P2]=get_max(_sequence)
*
- * Get next Id of the table. P1 is a table cursor, P2 is column
- * number. Return in P3 maximum id found in provided column,
+ * Get next Id of the _sequence space.
+ * Return in P2 maximum id found in _sequence,
* incremented by one.
- *
- * This opcode is Tarantool specific and will segfault in case
- * of SQLite cursor.
*/
-case OP_NextId: { /* out3 */
- VdbeCursor *pC; /* The VDBE cursor */
- int p2; /* Column number, which stores the id */
- pC = p->apCsr[pOp->p1];
- p2 = pOp->p2;
- pOut = &aMem[pOp->p3];
-
- /* This opcode is Tarantool specific. */
- assert(pC->uc.pCursor->curFlags & BTCF_TaCursor);
-
- tarantoolSqlGetMaxId(pC->uc.pCursor, p2,
- (uint64_t *) &pOut->u.i);
+case OP_NextSequenceId: {
+ pOut = &aMem[pOp->p2];
+ tarantoolSqlNextSeqId((uint64_t *) &pOut->u.i);
pOut->u.i += 1;
pOut->flags = MEM_Int;
@@ -4495,6 +4483,85 @@ case OP_IdxInsert: { /* in2 */
break;
}
+/* Opcode: SInsert P1 P2 * * P5
+ * Synopsis: space id = P1, key = r[P2]
+ *
+ * This opcode is used only during DDL routine.
+ * In contrast to ordinary insertion, insertion to system spaces
+ * such as _space or _index will lead to schema changes.
+ * Thus, usage of space pointers is going to be impossible,
+ * as far as pointers can be expired since compilation time.
+ *
+ * If P5 is set to OPFLAG_NCHANGE, account overall changes
+ * made to database.
+ */
+case OP_SInsert: {
+ assert(pOp->p1 > 0);
+ assert(pOp->p2 >= 0);
+
+ pIn2 = &aMem[pOp->p2];
+ struct space *space = space_by_id(pOp->p1);
+ assert(space != NULL);
+ assert(space_is_system(space));
+ /* Create surrogate cursor to pass to SQL bindings. */
+ BtCursor surrogate_cur;
+ surrogate_cur.space = space;
+ surrogate_cur.key = pIn2->z;
+ surrogate_cur.nKey = pIn2->n;
+ surrogate_cur.curFlags = BTCF_TaCursor;
+ rc = tarantoolSqlite3Insert(&surrogate_cur);
+ if (rc)
+ goto abort_due_to_error;
+ if (pOp->p5 & OPFLAG_NCHANGE)
+ p->nChange++;
+ break;
+}
+
+/* Opcode: SDelete P1 P2 * * P5
+ * Synopsis: space id = P1, key = r[P2]
+ *
+ * This opcode is used only during DDL routine.
+ * Delete entry with given key from system space.
+ *
+ * If P5 is set to OPFLAG_NCHANGE, account overall changes
+ * made to database.
+ */
+case OP_SDelete: {
+ assert(pOp->p1 > 0);
+ assert(pOp->p2 >= 0);
+
+ pIn2 = &aMem[pOp->p2];
+ struct space *space = space_by_id(pOp->p1);
+ assert(space != NULL);
+ assert(space_is_system(space));
+ rc = sql_delete_by_key(space, pIn2->z, pIn2->n);
+ if (rc)
+ goto abort_due_to_error;
+ if (pOp->p5 & OPFLAG_NCHANGE)
+ p->nChange++;
+ break;
+}
+
+/* Opcode: SIDtoPtr P1 P2 * * *
+ * Synopsis: space id = P1, space[out] = r[P2]
+ *
+ * This opcode makes look up by space id and save found space
+ * into register, specified by the content of register P2.
+ * Such trick is needed during DLL routine, since schema may
+ * change and pointers become expired.
+ */
+case OP_SIDtoPtr: {
+ assert(pOp->p1 > 0);
+ assert(pOp->p2 >= 0);
+
+ pIn2 = out2Prerelease(p, pOp);
+ struct space *space = space_by_id(pOp->p1);
+ assert(space != NULL);
+ pIn2->u.p = (void *) space;
+ pIn2->flags = MEM_Ptr;
+ break;
+}
+
/* Opcode: IdxDelete P1 P2 P3 * *
* Synopsis: key=r[P2@P3]
*
@@ -5424,22 +5491,19 @@ case OP_Init: { /* jump */
/* Opcode: IncMaxid P1 * * * *
*
- * The cursor (P1) should be open on _schema.
- * Increment the max_id (max space id) and store updated tuple in the
- * cursor.
+ * Increment the max_id from _schema (max space id)
+ * and store updated id in register specified by first operand.
+ * It is system opcode and must be used only during DDL routine.
*/
case OP_IncMaxid: {
- VdbeCursor *pC;
-
- assert(pOp->p1>=0 && pOp->p1<p->nCursor);
- pC = p->apCsr[pOp->p1];
- assert(pC != 0);
+ assert(pOp->p1 > 0);
+ pOut = &aMem[pOp->p1];
- rc = tarantoolSqlite3IncrementMaxid(pC->uc.pCursor);
+ rc = tarantoolSqlite3IncrementMaxid((uint64_t*) &pOut->u.i);
if (rc!=SQLITE_OK) {
goto abort_due_to_error;
}
- pC->nullRow = 0;
+ pOut->flags = MEM_Int;
break;
}
--
2.15.1