[patches] [sql 6/9] sql: added mechanism to emulate ROWID
Nikita Pettik
korablev at tarantool.org
Tue Jan 23 23:19:17 MSK 2018
It is worth mentioning, that there are two types of ephemeral tables:
one holds rows as they are inserted (all rows turn out to be distinct);
another adds ROWID column in order to hold equal rows.
Inasmuch as original ROWID mechanism is to be removed, the purpose of this
patch is to emulate ROWID behavior for ephemeral tables.
- Substituted all ephemeral table opcodes which don't rely on SQLite's ROWID
with Tarantool ones.
- Implemeted opcode OP_NextIdEphemeral to emulate behavior of ROWID feature.
In current implemetation ROWID is not hidden PK index, but just another one
column to keep in table equal tuples.
- Substituted old ephemeral tables with ROWID for
INSERT INTO ... SELECT ... FROM statement. It utilizes ephemeral tables as
intermediate holder for data from SELET (before it is inserted to table).
Part of #2680
Signed-off-by: Nikita Pettik <korablev at tarantool.org>
---
src/box/sql.c | 42 +++++++++++++++++
src/box/sql/btree.c | 4 ++
src/box/sql/insert.c | 24 ++++++----
src/box/sql/opcodes.c | 91 ++++++++++++++++++------------------
src/box/sql/opcodes.h | 104 +++++++++++++++++++++---------------------
src/box/sql/select.c | 8 ++--
src/box/sql/tarantoolInt.h | 3 ++
src/box/sql/vdbe.c | 25 ++++++++++
test/sql-tap/insert1.test.lua | 2 +-
9 files changed, 193 insertions(+), 110 deletions(-)
diff --git a/src/box/sql.c b/src/box/sql.c
index 10ea655c9..bb25c72da 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -390,6 +390,19 @@ int tarantoolSqlite3MovetoUnpacked(BtCursor *pCur, UnpackedRecord *pIdxKey,
return rc;
}
+int tarantoolSqlite3EphemeralCount(struct BtCursor *pCur, i64 *pnEntry)
+{
+ assert(pCur->curFlags & BTCF_TEphemCursor);
+
+ struct ta_cursor *c = pCur->pTaCursor;
+ assert(c);
+ assert(c->ephem_space);
+
+ struct index *primary_index = *c->ephem_space->index;
+ *pnEntry = index_size(primary_index);
+ return SQLITE_OK;
+}
+
int tarantoolSqlite3Count(BtCursor *pCur, i64 *pnEntry)
{
assert(pCur->curFlags & BTCF_TaCursor);
@@ -1727,6 +1740,35 @@ sql_debug_info(struct info_handler *h)
info_end(h);
}
+int tarantoolSqlite3EphemeralGetMaxId(BtCursor *pCur, uint32_t fieldno,
+ uint64_t *max_id)
+{
+ assert(pCur->pTaCursor);
+ struct ta_cursor *c = pCur->pTaCursor;
+ struct space *ephem_space = c->ephem_space;
+ assert(ephem_space);
+ struct index *primary_index = *ephem_space->index;
+
+ char key[16];
+ mp_encode_array(key, 0);
+ struct tuple *tuple;
+
+ uint32_t part_count = primary_index->def->key_def->part_count;
+ if (index_max(primary_index, key, part_count, &tuple) != 0) {
+ return SQLITE_TARANTOOL_ERROR;
+ }
+ if (tuple != NULL && tuple_bless(tuple) == NULL)
+ return SQLITE_TARANTOOL_ERROR;
+
+ if (tuple == NULL) {
+ *max_id = 0;
+ return SQLITE_OK;
+ }
+ tuple_field_u64(tuple, fieldno, max_id);
+
+ return SQLITE_OK;
+}
+
/**
* Extract maximum integer value from:
* @param index space_id
diff --git a/src/box/sql/btree.c b/src/box/sql/btree.c
index 9ed5d3d41..d13ae5801 100644
--- a/src/box/sql/btree.c
+++ b/src/box/sql/btree.c
@@ -7467,6 +7467,10 @@ sqlite3BtreeCount(BtCursor * pCur, i64 * pnEntry)
return tarantoolSqlite3Count(pCur, pnEntry);
}
+ if (pCur->curFlags & BTCF_TEphemCursor) {
+ return tarantoolSqlite3EphemeralCount(pCur, pnEntry);
+ }
+
if (pCur->pgnoRoot == 0) {
*pnEntry = 0;
return SQLITE_OK;
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index f4efbe02c..81776aaee 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -564,24 +564,30 @@ sqlite3Insert(Parse * pParse, /* Parser context */
* M: ...
*/
int regRec; /* Register to hold packed record */
- int regTempRowid; /* Register to hold temp table ROWID */
+ int regTempId; /* Register to hold temp table ID */
+ int regCopy; /* Register to keep copy of registers from select */
int addrL; /* Label "L" */
srcTab = pParse->nTab++;
regRec = sqlite3GetTempReg(pParse);
- regTempRowid = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
+ regCopy = sqlite3GetTempRange(pParse, nColumn);
+ regTempId = sqlite3GetTempReg(pParse);
+ KeyInfo *pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, 1+nColumn, 0);
+ sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, srcTab, nColumn+1,
+ 0, (char*)pKeyInfo, P4_KEYINFO);
addrL = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect,
- nColumn, regRec);
- sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec,
- regTempRowid);
+ sqlite3VdbeAddOp3(v, OP_NextIdEphemeral, srcTab, 2, regTempId);
+ sqlite3VdbeAddOp3(v, OP_Copy, regFromSelect, regCopy, nColumn-1);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regCopy,
+ nColumn + 1, regRec);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, srcTab, regRec);
+
sqlite3VdbeGoto(v, addrL);
sqlite3VdbeJumpHere(v, addrL);
sqlite3ReleaseTempReg(pParse, regRec);
- sqlite3ReleaseTempReg(pParse, regTempRowid);
+ sqlite3ReleaseTempReg(pParse, regTempId);
+ sqlite3ReleaseTempRange(pParse, regCopy, nColumn);
}
} else {
/* This is the case if the data for the INSERT is coming from a
diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c
index f27568be3..b91784db3 100644
--- a/src/box/sql/opcodes.c
+++ b/src/box/sql/opcodes.c
@@ -125,51 +125,52 @@ const char *sqlite3OpcodeName(int i){
/* 111 */ "ColumnsUsed" OpHelp(""),
/* 112 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
/* 113 */ "NextId" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
- /* 114 */ "FCopy" OpHelp("reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)]"),
- /* 115 */ "Real" OpHelp("r[P2]=P4"),
- /* 116 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 117 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 118 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 119 */ "Delete" OpHelp(""),
- /* 120 */ "ResetCount" OpHelp(""),
- /* 121 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 122 */ "SorterData" OpHelp("r[P2]=data"),
- /* 123 */ "RowData" OpHelp("r[P2]=data"),
- /* 124 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 125 */ "NullRow" OpHelp(""),
- /* 126 */ "SorterInsert" OpHelp("key=r[P2]"),
- /* 127 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 128 */ "IdxDelete" OpHelp("key=r[P2 at P3]"),
- /* 129 */ "Seek" OpHelp("Move P3 to P1.rowid"),
- /* 130 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 131 */ "Destroy" OpHelp(""),
- /* 132 */ "Clear" OpHelp(""),
- /* 133 */ "ResetSorter" OpHelp(""),
- /* 134 */ "CreateIndex" OpHelp("r[P2]=root"),
- /* 135 */ "CreateTable" OpHelp("r[P2]=root"),
- /* 136 */ "ParseSchema2" OpHelp("rows=r[P1 at P2]"),
- /* 137 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"),
- /* 138 */ "RenameTable" OpHelp("P1 = root, P4 = name"),
- /* 139 */ "LoadAnalysis" OpHelp(""),
- /* 140 */ "DropTable" OpHelp(""),
- /* 141 */ "DropIndex" OpHelp(""),
- /* 142 */ "DropTrigger" OpHelp(""),
- /* 143 */ "IntegrityCk" OpHelp(""),
- /* 144 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 145 */ "Param" OpHelp(""),
- /* 146 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 147 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 148 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 149 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2 at P5])"),
- /* 150 */ "AggStep" OpHelp("accum=r[P3] step(r[P2 at P5])"),
- /* 151 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 152 */ "Expire" OpHelp(""),
- /* 153 */ "Pagecount" OpHelp(""),
- /* 154 */ "MaxPgcnt" OpHelp(""),
- /* 155 */ "CursorHint" OpHelp(""),
- /* 156 */ "IncMaxid" OpHelp(""),
- /* 157 */ "Noop" OpHelp(""),
- /* 158 */ "Explain" OpHelp(""),
+ /* 114 */ "NextIdEphemeral" OpHelp("r[P3]=get_max(space_index[P1]{Column[P2]})"),
+ /* 115 */ "FCopy" OpHelp("reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)]"),
+ /* 116 */ "Real" OpHelp("r[P2]=P4"),
+ /* 117 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 118 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 119 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
+ /* 120 */ "Delete" OpHelp(""),
+ /* 121 */ "ResetCount" OpHelp(""),
+ /* 122 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 123 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 124 */ "RowData" OpHelp("r[P2]=data"),
+ /* 125 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 126 */ "NullRow" OpHelp(""),
+ /* 127 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 128 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 129 */ "IdxDelete" OpHelp("key=r[P2 at P3]"),
+ /* 130 */ "Seek" OpHelp("Move P3 to P1.rowid"),
+ /* 131 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 132 */ "Destroy" OpHelp(""),
+ /* 133 */ "Clear" OpHelp(""),
+ /* 134 */ "ResetSorter" OpHelp(""),
+ /* 135 */ "CreateIndex" OpHelp("r[P2]=root"),
+ /* 136 */ "CreateTable" OpHelp("r[P2]=root"),
+ /* 137 */ "ParseSchema2" OpHelp("rows=r[P1 at P2]"),
+ /* 138 */ "ParseSchema3" OpHelp("name=r[P1] sql=r[P1+1]"),
+ /* 139 */ "RenameTable" OpHelp("P1 = root, P4 = name"),
+ /* 140 */ "LoadAnalysis" OpHelp(""),
+ /* 141 */ "DropTable" OpHelp(""),
+ /* 142 */ "DropIndex" OpHelp(""),
+ /* 143 */ "DropTrigger" OpHelp(""),
+ /* 144 */ "IntegrityCk" OpHelp(""),
+ /* 145 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 146 */ "Param" OpHelp(""),
+ /* 147 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 148 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 149 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+ /* 150 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2 at P5])"),
+ /* 151 */ "AggStep" OpHelp("accum=r[P3] step(r[P2 at P5])"),
+ /* 152 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 153 */ "Expire" OpHelp(""),
+ /* 154 */ "Pagecount" OpHelp(""),
+ /* 155 */ "MaxPgcnt" OpHelp(""),
+ /* 156 */ "CursorHint" OpHelp(""),
+ /* 157 */ "IncMaxid" OpHelp(""),
+ /* 158 */ "Noop" OpHelp(""),
+ /* 159 */ "Explain" OpHelp(""),
};
return azName[i];
}
diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h
index 28cf70b7a..7c331c788 100644
--- a/src/box/sql/opcodes.h
+++ b/src/box/sql/opcodes.h
@@ -114,51 +114,52 @@
#define OP_ColumnsUsed 111
#define OP_Sequence 112 /* synopsis: r[P2]=cursor[P1].ctr++ */
#define OP_NextId 113 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
-#define OP_FCopy 114 /* synopsis: reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)] */
-#define OP_Real 115 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_NewRowid 116 /* synopsis: r[P2]=rowid */
-#define OP_Insert 117 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_InsertInt 118 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 119
-#define OP_ResetCount 120
-#define OP_SorterCompare 121 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 122 /* synopsis: r[P2]=data */
-#define OP_RowData 123 /* synopsis: r[P2]=data */
-#define OP_Rowid 124 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 125
-#define OP_SorterInsert 126 /* synopsis: key=r[P2] */
-#define OP_IdxInsert 127 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 128 /* synopsis: key=r[P2 at P3] */
-#define OP_Seek 129 /* synopsis: Move P3 to P1.rowid */
-#define OP_IdxRowid 130 /* synopsis: r[P2]=rowid */
-#define OP_Destroy 131
-#define OP_Clear 132
-#define OP_ResetSorter 133
-#define OP_CreateIndex 134 /* synopsis: r[P2]=root */
-#define OP_CreateTable 135 /* synopsis: r[P2]=root */
-#define OP_ParseSchema2 136 /* synopsis: rows=r[P1 at P2] */
-#define OP_ParseSchema3 137 /* synopsis: name=r[P1] sql=r[P1+1] */
-#define OP_RenameTable 138 /* synopsis: P1 = root, P4 = name */
-#define OP_LoadAnalysis 139
-#define OP_DropTable 140
-#define OP_DropIndex 141
-#define OP_DropTrigger 142
-#define OP_IntegrityCk 143
-#define OP_RowSetAdd 144 /* synopsis: rowset(P1)=r[P2] */
-#define OP_Param 145
-#define OP_FkCounter 146 /* synopsis: fkctr[P1]+=P2 */
-#define OP_MemMax 147 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_OffsetLimit 148 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_AggStep0 149 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
-#define OP_AggStep 150 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
-#define OP_AggFinal 151 /* synopsis: accum=r[P1] N=P2 */
-#define OP_Expire 152
-#define OP_Pagecount 153
-#define OP_MaxPgcnt 154
-#define OP_CursorHint 155
-#define OP_IncMaxid 156
-#define OP_Noop 157
-#define OP_Explain 158
+#define OP_NextIdEphemeral 114 /* synopsis: r[P3]=get_max(space_index[P1]{Column[P2]}) */
+#define OP_FCopy 115 /* synopsis: reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)] */
+#define OP_Real 116 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
+#define OP_NewRowid 117 /* synopsis: r[P2]=rowid */
+#define OP_Insert 118 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_InsertInt 119 /* synopsis: intkey=P3 data=r[P2] */
+#define OP_Delete 120
+#define OP_ResetCount 121
+#define OP_SorterCompare 122 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 123 /* synopsis: r[P2]=data */
+#define OP_RowData 124 /* synopsis: r[P2]=data */
+#define OP_Rowid 125 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 126
+#define OP_SorterInsert 127 /* synopsis: key=r[P2] */
+#define OP_IdxInsert 128 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 129 /* synopsis: key=r[P2 at P3] */
+#define OP_Seek 130 /* synopsis: Move P3 to P1.rowid */
+#define OP_IdxRowid 131 /* synopsis: r[P2]=rowid */
+#define OP_Destroy 132
+#define OP_Clear 133
+#define OP_ResetSorter 134
+#define OP_CreateIndex 135 /* synopsis: r[P2]=root */
+#define OP_CreateTable 136 /* synopsis: r[P2]=root */
+#define OP_ParseSchema2 137 /* synopsis: rows=r[P1 at P2] */
+#define OP_ParseSchema3 138 /* synopsis: name=r[P1] sql=r[P1+1] */
+#define OP_RenameTable 139 /* synopsis: P1 = root, P4 = name */
+#define OP_LoadAnalysis 140
+#define OP_DropTable 141
+#define OP_DropIndex 142
+#define OP_DropTrigger 143
+#define OP_IntegrityCk 144
+#define OP_RowSetAdd 145 /* synopsis: rowset(P1)=r[P2] */
+#define OP_Param 146
+#define OP_FkCounter 147 /* synopsis: fkctr[P1]+=P2 */
+#define OP_MemMax 148 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_OffsetLimit 149 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggStep0 150 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
+#define OP_AggStep 151 /* synopsis: accum=r[P3] step(r[P2 at P5]) */
+#define OP_AggFinal 152 /* synopsis: accum=r[P1] N=P2 */
+#define OP_Expire 153
+#define OP_Pagecount 154
+#define OP_MaxPgcnt 155
+#define OP_CursorHint 156
+#define OP_IncMaxid 157
+#define OP_Noop 158
+#define OP_Explain 159
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -185,12 +186,13 @@
/* 88 */ 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 96 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 112 */ 0x10, 0x20, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04,\
-/* 128 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 144 */ 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,}
+/* 112 */ 0x10, 0x20, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04,\
+/* 128 */ 0x04, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\
+/* 136 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 144 */ 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00,\
+/* 152 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
+}
/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 18bc766c6..5c47ab020 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -2334,7 +2334,7 @@ generateWithRecursiveQuery(Parse * pParse, /* Parsing context */
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
if (pOrderBy) {
KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1);
- sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue,
+ sqlite3VdbeAddOp4(v, OP_OpenTEphemeral, iQueue,
pOrderBy->nExpr + 2, 0, (char *)pKeyInfo,
P4_KEYINFO);
destQueue.pOrderBy = pOrderBy;
@@ -2344,7 +2344,7 @@ generateWithRecursiveQuery(Parse * pParse, /* Parsing context */
VdbeComment((v, "Queue table"));
if (iDistinct) {
p->addrOpenEphm[0] =
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0);
+ sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, iDistinct, 0);
p->selFlags |= SF_UsesEphemeral;
}
@@ -2766,7 +2766,7 @@ multiSelect(Parse * pParse, /* Parsing context */
assert(p->pOrderBy == 0);
addr =
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1,
+ sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, tab1,
0);
assert(p->addrOpenEphm[0] == -1);
p->addrOpenEphm[0] = addr;
@@ -2787,7 +2787,7 @@ multiSelect(Parse * pParse, /* Parsing context */
/* Code the current SELECT into temporary table "tab2"
*/
addr =
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2,
+ sqlite3VdbeAddOp2(v, OP_OpenTEphemeral, tab2,
0);
assert(p->addrOpenEphm[1] == -1);
p->addrOpenEphm[1] = addr;
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index c4245b6d7..40785f261 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -92,8 +92,11 @@ int tarantoolSqlite3EphemeralDelete(BtCursor * pCur);
int tarantoolSqlite3EphemeralFirst(BtCursor * pCur, int * pRes);
int tarantoolSqlite3EphemeralNext(BtCursor * pCur, int * pRes);
int tarantoolSqlite3EphemeralLast(BtCursor * pCur, int * pRes);
+int tarantoolSqlite3EphemeralCount(BtCursor * pCur, i64 * pnEntry);
int tarantoolSqlite3EphemeralPrevious(BtCursor * pCur, int * pRes);
int tarantoolSqlite3EphemeralDrop(BtCursor * pCur);
+int tarantoolSqlite3EphemeralGetMaxId(BtCursor * pCur, uint32_t fieldno,
+ uint64_t * max_id);
/* Compare against the index key under a cursor -
* the key may span non-adjacent fields in a random order,
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 406819856..7cd8160c8 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4160,6 +4160,31 @@ case OP_NextId: { /* out3 */
break;
}
+/* Opcode: NextIdEphemeral P1 P2 P3 * *
+ * Synopsis: r[P3]=get_max(space_index[P1]{Column[P2]})
+ *
+ * This opcode works in the same way as OP_NextId does, except it is
+ * only applied for ephemeral tables. The difference is in the fact that
+ * all ephemeral tables don't have space_id (to be more precise it equals to zero).
+ */
+case OP_NextIdEphemeral: {
+ VdbeCursor *pC;
+ int p2;
+ pC = p->apCsr[pOp->p1];
+ p2 = pOp->p2;
+ pOut = &aMem[pOp->p3];
+
+ assert(pC->uc.pCursor->curFlags & BTCF_TEphemCursor);
+
+ rc = tarantoolSqlite3EphemeralGetMaxId(pC->uc.pCursor, p2,
+ (uint64_t *) &pOut->u.i);
+ if (rc) goto abort_due_to_error;
+
+ pOut->u.i += 1;
+ pOut->flags = MEM_Int;
+ break;
+}
+
/* Opcode: FCopy P1 P2 P3 * *
* Synopsis: reg[P2 at cur_frame]= reg[P1 at root_frame(OPFLAG_SAME_FRAME)]
*
diff --git a/test/sql-tap/insert1.test.lua b/test/sql-tap/insert1.test.lua
index 533241f5c..847b25ad2 100755
--- a/test/sql-tap/insert1.test.lua
+++ b/test/sql-tap/insert1.test.lua
@@ -315,7 +315,7 @@ test:do_execsql_test("insert-4.7", [[
x = test:execsql [[
EXPLAIN INSERT INTO t4 SELECT x+2 FROM t4;
]]
- return {test:lsearch(x, 'OpenEphemeral') > 0} -- X(264, "X!cmd", [=[["expr","[lsearch $x OpenEphemeral]>0"]]=])
+ return {test:lsearch(x, 'OpenTEphemeral') > 0} -- X(264, "X!cmd", [=[["expr","[lsearch $x OpenEphemeral]>0"]]=])
end, {
-- <insert-5.3>
1
--
2.15.1
More information about the Tarantool-patches
mailing list