[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