[tarantool-patches] [PATCH 3/4] sql: rework code generation for DDL routine

Nikita Pettik korablev at tarantool.org
Wed Mar 21 02:48:41 MSK 2018


As far as new opcodes to operate on system spaces have been introduced,
there is no more need to open cursors on such tables, when it comes to
insert/delete operations. In addition, it allows to get rid of system
spaces lookups from SQL data dictionary.  Moreover, previously DDL
relied on nested parse to make deletions from system space. But during
nested parse it is impossible to convert space id to space pointer (i.e.
emit OP_SIDtoPtr opcode) without any overhead or "hacks".  So, nested
parse has been replaced with hardcoded sequences of opcodes,
implementing the same logic.

Closes #3252
---
 src/box/sql/build.c          | 322 ++++++++++++++++++++++---------------------
 src/box/sql/sqliteInt.h      |   5 +
 src/box/sql/trigger.c        |  27 ++--
 test/sql/transition.result   |  11 +-
 test/sql/transition.test.lua |   8 +-
 5 files changed, 190 insertions(+), 183 deletions(-)

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 229c8b4d5..02d27dec6 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -1425,13 +1425,12 @@ convertToWithoutRowidTable(Parse * pParse, Table * pTab)
  * Return register storing the result.
  */
 static int
-getNewSpaceId(Parse * pParse, int iCursor)
+getNewSpaceId(Parse * pParse)
 {
 	Vdbe *v = sqlite3GetVdbe(pParse);
 	int iRes = ++pParse->nMem;
 
-	sqlite3VdbeAddOp1(v, OP_IncMaxid, iCursor);
-	sqlite3VdbeAddOp3(v, OP_Column, iCursor, 1, iRes);
+	sqlite3VdbeAddOp1(v, OP_IncMaxid, iRes);
 	return iRes;
 }
 
@@ -1441,10 +1440,8 @@ getNewSpaceId(Parse * pParse, int iCursor)
  * space id or designates a register storing the id.
  */
 static void
-createIndex(Parse * pParse,
-	    Index * pIndex,
-	    int iSpaceId,
-	    int iIndexId, const char *zSql, Table * pSysIndex, int iCursor)
+createIndex(Parse * pParse, Index * pIndex, int iSpaceId, int iIndexId,
+	    const char *zSql)
 {
 	Vdbe *v = sqlite3GetVdbe(pParse);
 	int iFirstCol = ++pParse->nMem;
@@ -1509,7 +1506,7 @@ createIndex(Parse * pParse,
 	sqlite3VdbeAddOp4(v, OP_Blob, zPartsSz, iFirstCol + 5, MSGPACK_SUBTYPE,
 			  zParts, P4_STATIC);
 	sqlite3VdbeAddOp3(v, OP_MakeRecord, iFirstCol, 6, iRecord);
-	sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCursor, iRecord, iFirstCol, 6);
+	sqlite3VdbeAddOp2(v, OP_SInsert, BOX_INDEX_ID, iRecord);
 	/* Do not account nested operations: the count of such
 	 * operations depends on Tarantool data dictionary internals,
 	 * such as data layout in system spaces. Also do not account
@@ -1518,7 +1515,6 @@ createIndex(Parse * pParse,
 	 */
 	if (!pParse->nested && pIndex->idxType == SQLITE_IDXTYPE_APPDEF)
 		sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
-	sqlite3TableAffinity(v, pSysIndex, 0);
 }
 
 /*
@@ -1571,8 +1567,7 @@ makeIndexSchemaRecord(Parse * pParse,
  * iCursor is a cursor to access _space.
  */
 static void
-createSpace(Parse * pParse,
-	    int iSpaceId, char *zStmt, int iCursor, Table * pSysSpace)
+createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 {
 	Table *p = pParse->pNewTable;
 	Vdbe *v = sqlite3GetVdbe(pParse);
@@ -1615,14 +1610,13 @@ createSpace(Parse * pParse,
 	sqlite3VdbeAddOp4(v, OP_Blob, zFormatSz, iFirstCol + 6, MSGPACK_SUBTYPE,
 			  zFormat, P4_STATIC);
 	sqlite3VdbeAddOp3(v, OP_MakeRecord, iFirstCol, 7, iRecord);
-	sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCursor, iRecord, iFirstCol, 7);
+	sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SPACE_ID, iRecord);
 	/* Do not account nested operations: the count of such
 	 * operations depends on Tarantool data dictionary internals,
 	 * such as data layout in system spaces.
 	 */
 	if (!pParse->nested)
 		sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
-	sqlite3TableAffinity(v, pSysSpace, 0);
 }
 
 /*
@@ -1631,8 +1625,7 @@ createSpace(Parse * pParse,
  * iCursor is a cursor to access _index.
  */
 static void
-createImplicitIndices(Parse * pParse,
-		      int iSpaceId, int iCursor, Table * pSysIndex)
+createImplicitIndices(Parse * pParse, int iSpaceId)
 {
 	Table *p = pParse->pNewTable;
 	Index *pIdx, *pPrimaryIdx = sqlite3PrimaryKeyIndex(p);
@@ -1640,22 +1633,21 @@ createImplicitIndices(Parse * pParse,
 
 	if (pPrimaryIdx) {
 		/* Tarantool quirk: primary index is created first */
-		createIndex(pParse, pPrimaryIdx, iSpaceId, 0, NULL, pSysIndex,
-			    iCursor);
+		createIndex(pParse, pPrimaryIdx, iSpaceId, 0, NULL);
 	} else {
 		/*
 		 * This branch should not be taken.
 		 * If it is, then the current CREATE TABLE statement fails to
 		 * specify the PRIMARY KEY. The error is reported elsewhere.
 		 */
+		unreachable();
 	}
 
 	/* (pIdx->i) mapping must be consistent with parseTableSchemaRecord */
 	for (pIdx = p->pIndex, i = 0; pIdx; pIdx = pIdx->pNext) {
 		if (pIdx == pPrimaryIdx)
 			continue;
-		createIndex(pParse, pIdx, iSpaceId, ++i, NULL, pSysIndex,
-			    iCursor);
+		createIndex(pParse, pIdx, iSpaceId, ++i, NULL);
 	}
 }
 
@@ -1849,29 +1841,12 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 		Vdbe *v;
 		char *zType;	/* "VIEW" or "TABLE" */
 		char *zStmt;	/* Text of the CREATE TABLE or CREATE VIEW statement */
-		Table *pSysSchema, *pSysSpace, *pSysIndex;
-		int iCursor = pParse->nTab++;
 		int iSpaceId;
 
 		v = sqlite3GetVdbe(pParse);
 		if (NEVER(v == 0))
 			return;
 
-		pSysSchema = sqlite3HashFind(&pParse->db->pSchema->tblHash,
-					     TARANTOOL_SYS_SCHEMA_NAME);
-		if (NEVER(!pSysSchema))
-			return;
-
-		pSysSpace = sqlite3HashFind(&pParse->db->pSchema->tblHash,
-					    TARANTOOL_SYS_SPACE_NAME);
-		if (NEVER(!pSysSpace))
-			return;
-
-		pSysIndex = sqlite3HashFind(&pParse->db->pSchema->tblHash,
-					    TARANTOOL_SYS_INDEX_NAME);
-		if (NEVER(!pSysIndex))
-			return;
-
 		/*
 		 * Initialize zType for the new view or table.
 		 */
@@ -1913,66 +1888,35 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 					       pParse->sNameToken.z);
 		}
 
-		sqlite3OpenTable(pParse, iCursor, pSysSchema, OP_OpenRead);
-		sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
-		iSpaceId = getNewSpaceId(pParse, iCursor);
-		sqlite3OpenTable(pParse, iCursor, pSysSpace, OP_OpenWrite);
-		createSpace(pParse, iSpaceId, zStmt, iCursor, pSysSpace);
-		sqlite3OpenTable(pParse, iCursor, pSysIndex, OP_OpenWrite);
-		createImplicitIndices(pParse, iSpaceId, iCursor, pSysIndex);
-		sqlite3VdbeAddOp1(v, OP_Close, iCursor);
+		iSpaceId = getNewSpaceId(pParse);
+		createSpace(pParse, iSpaceId, zStmt);
+		/* Indexes aren't required for VIEW's. */
+		if (p->pSelect == NULL) {
+			createImplicitIndices(pParse, iSpaceId);
+		}
 
 		/* Check to see if we need to create an _sequence table for
 		 * keeping track of autoincrement keys.
 		 */
 		if ((p->tabFlags & TF_Autoincrement) != 0) {
-			Table *sys_sequence, *sys_space_sequence;
 			int reg_seq_id;
 			int reg_seq_record, reg_space_seq_record;
 			assert(iSpaceId);
-
-			/* Do an insertion into _sequence  */
-			sys_sequence = sqlite3HashFind(
-				&pParse->db->pSchema->tblHash,
-				TARANTOOL_SYS_SEQUENCE_NAME);
-			if (NEVER(!sys_sequence))
-				return;
-
-			sqlite3OpenTable(pParse, iCursor, sys_sequence,
-					 OP_OpenWrite);
+			/* Do an insertion into _sequence. */
 			reg_seq_id = ++pParse->nMem;
-			sqlite3VdbeAddOp3(v, OP_NextId, iCursor, 0, reg_seq_id);
-
+			sqlite3VdbeAddOp2(v, OP_NextId, BOX_SEQUENCE_ID,
+					  reg_seq_id);
 			reg_seq_record = emitNewSysSequenceRecord(pParse,
 								  reg_seq_id,
 								  p->zName);
-			if (reg_seq_record < 0)
-				return;
-			sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCursor,
-					     reg_seq_record,
-					     reg_seq_record + 1, 9);
-			sqlite3VdbeAddOp1(v, OP_Close, iCursor);
-
-			/* Do an insertion into _space_sequence  */
-			sys_space_sequence = sqlite3HashFind(
-				&pParse->db->pSchema->tblHash,
-				TARANTOOL_SYS_SPACE_SEQUENCE_NAME);
-			if (NEVER(!sys_space_sequence))
-				return;
-
-			sqlite3OpenTable(pParse, iCursor, sys_space_sequence,
-					 OP_OpenWrite);
-			
-			reg_space_seq_record = emitNewSysSpaceSequenceRecord(
-				pParse,
-				iSpaceId,
-				reg_seq_id);
-
-			sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCursor,
-					     reg_space_seq_record,
-					     reg_space_seq_record + 1, 3);
-
-			sqlite3VdbeAddOp1(v, OP_Close, iCursor);
+			sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SEQUENCE_ID,
+					  reg_seq_record);
+			/* Do an insertion into _space_sequence. */
+			reg_space_seq_record =
+				emitNewSysSpaceSequenceRecord(pParse, iSpaceId,
+							      reg_seq_id);
+			sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SPACE_SEQUENCE_ID,
+					  reg_space_seq_record);
 		}
 
 		/* Reparse everything to update our internal data structures */
@@ -2238,9 +2182,11 @@ sqlite3CodeDropTable(Parse * pParse, Table * pTab, int isView)
 	v = sqlite3GetVdbe(pParse);
 	assert(v != 0);
 	sqlite3BeginWriteOperation(pParse, 1);
-
-	/* Drop all triggers associated with the table being dropped. Code
-	 * is generated to remove entries from _trigger space.
+	/*
+	 * Drop all triggers associated with the table being
+	 * dropped. Code is generated to remove entries from
+	 * _trigger. OP_DropTrigger will remove it from internal
+	 * SQL structures.
 	 */
 	pTrigger = pTab->pTrigger;
 	/* Do not account triggers deletion - they will be accounted
@@ -2254,58 +2200,115 @@ sqlite3CodeDropTable(Parse * pParse, Table * pTab, int isView)
 		pTrigger = pTrigger->pNext;
 	}
 	pParse->nested--;
-
-	/* Remove any entries of the _sequence table associated with
-	 * the table being dropped. This is done before the table is dropped
-	 * at the btree level, in case the _sequence table needs to
-	 * move as a result of the drop.
+	/*
+	 * Remove any entries of the _sequence and _space_sequence
+	 * space associated with the table being dropped. This is
+	 * done before the table is dropped from internal schema.
 	 */
+	int idx_rec_reg = ++pParse->nMem;
+	int space_id_reg = ++pParse->nMem;
+	int space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
+	sqlite3VdbeAddOp2(v, OP_Integer, space_id, space_id_reg);
 	if (pTab->tabFlags & TF_Autoincrement) {
-		sqlite3NestedParse(pParse,
-				   "DELETE FROM \"%s\" WHERE \"space_id\"=%d",
-				   TARANTOOL_SYS_SPACE_SEQUENCE_NAME,
-				   SQLITE_PAGENO_TO_SPACEID(pTab->tnum));
-		sqlite3NestedParse(pParse,
-				   "DELETE FROM \"%s\" WHERE \"name\"=%Q",
-				   TARANTOOL_SYS_SEQUENCE_NAME,
-				   pTab->zName);
-	}
-
-	/* Drop all _space and _index entries that refer to the
-	 * table. The program loops through the _index & _space tables and deletes
-	 * every row that refers to a table.
-	 * Triggers are handled separately because a trigger can be
-	 * created in the temp database that refers to a table in another
-	 * database.
+		/* Delete entry by from _space_sequence. */
+		sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_reg, 1,
+				  idx_rec_reg);
+		sqlite3VdbeAddOp2(v, OP_SDelete, BOX_SPACE_SEQUENCE_ID,
+				  idx_rec_reg);
+		VdbeComment((v, "Delete entry from _space_sequence"));
+		/*
+		 * Program below implement analogue of SQL statement:
+		 * "DELETE FROM BOX_SEQUENCE WHERE name = zName;"
+		 * However, we can't use nested parse for DDL,
+		 * since pointers to spaces will expire.
+		 */
+		/* Name to be found in _sequence. */
+		int space_ref_name = ++pParse->nMem;
+		/* Pointer to _sequence to be passe to OpenWrite. */
+		int space_ptr = ++pParse->nMem;
+		/* Cursor to _sequence which will generate OpenWrite. */
+		int cursor_to_seq = pParse->nTab++;
+		/* Name of space fetched from _sequence. */
+		int space_name = ++pParse->nMem;
+		/* Space id fetched from _sequence. */
+		int space_id_seq = ++pParse->nMem;
+		int record_to_delete = ++pParse->nMem;
+		/* Save name to be found in register. */
+		sqlite3VdbeAddOp4(v, OP_String8, 0, space_ref_name, 0,
+				  pTab->zName, P4_STATIC);
+		/* Convert space id to space pointer and open cursor. */
+		sqlite3VdbeAddOp2(v, OP_SIDtoPtr, BOX_SEQUENCE_ID, space_ptr);
+		sqlite3VdbeAddOp4Int(v, OP_OpenWrite, cursor_to_seq, 0,
+				     space_ptr,
+				     9 /* Number of fields in _sequence. */);
+		int loop_exit = sqlite3VdbeAddOp1(v, OP_Rewind, cursor_to_seq);
+		/* Fetch space name from tuple and save to space_name reg. */
+		int loop_start = sqlite3VdbeAddOp3(v, OP_Column, cursor_to_seq,
+						   2, space_name);
+		/* Compare it with the name of space we want to delete. */
+		int loop_end = sqlite3VdbeAddOp3(v, OP_Ne, space_ref_name, 0,
+						  space_name);
+		/* Store _sequence.id to space_id_seq register. */
+		sqlite3VdbeAddOp3(v, OP_Column, cursor_to_seq, 0, space_id_seq);
+		/* Prepare record to be deleted. Key is in space_id_seq. */
+		sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_seq, 1,
+				  record_to_delete);
+		sqlite3VdbeAddOp2(v, OP_SDelete, BOX_SEQUENCE_ID,
+				  record_to_delete);
+		VdbeComment((v, "Delete entry from _sequence"));
+		sqlite3VdbeJumpHere(v, loop_end);
+		sqlite3VdbeAddOp2(v, OP_Next, cursor_to_seq, loop_start);
+		sqlite3VdbeJumpHere(v, loop_exit);
+	}
+	/*
+	 * Drop all _space and _index entries that refer to the
+	 * table.
 	 */
-	int space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
 	if (!isView) {
-		if (pTab->pIndex && pTab->pIndex->pNext) {
-			/*  Remove all indexes, except for primary.
-			   Tarantool won't allow remove primary when secondary exist. */
-			sqlite3NestedParse(pParse,
-					   "DELETE FROM \"%s\" WHERE \"id\"=%d AND \"iid\">0",
-					   TARANTOOL_SYS_INDEX_NAME, space_id);
+		struct space *space = space_by_id(space_id);
+		assert(space != NULL);
+		uint32_t index_count = space->index_count;
+		if (index_count > 1) {
+			/*
+			 * Remove all indexes, except for primary.
+			 * Tarantool won't allow remove primary when
+			 * secondary exist.
+			 */
+			uint32_t *iids =
+				(uint32_t *) sqlite3Malloc(sizeof(uint32_t) *
+							   (index_count - 1));
+			/* Save index ids to be deleted except for PK. */
+			for (uint32_t i = 1; i < index_count; ++i) {
+				iids[i - 1] = space->index[i]->def->iid;
+			}
+			for (uint32_t i = 0; i < index_count - 1; ++i) {
+				sqlite3VdbeAddOp2(v, OP_Integer, iids[i],
+						  space_id_reg + 1);
+				sqlite3VdbeAddOp3(v, OP_MakeRecord,
+						  space_id_reg, 2, idx_rec_reg);
+				sqlite3VdbeAddOp2(v, OP_SDelete, BOX_INDEX_ID,
+						  idx_rec_reg);
+				VdbeComment((v,
+					     "Remove secondary index iid = %u",
+					     iids[i]));
+			}
+			sqlite3_free(iids);
 		}
-
-		/*  Remove primary index. */
-		sqlite3NestedParse(pParse,
-				   "DELETE FROM \"%s\" WHERE \"id\"=%d AND \"iid\"=0",
-				   TARANTOOL_SYS_INDEX_NAME, space_id);
+		sqlite3VdbeAddOp2(v, OP_Integer, 0, space_id_reg + 1);
+		sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_reg, 2,
+				  idx_rec_reg);
+		sqlite3VdbeAddOp2(v, OP_SDelete, BOX_INDEX_ID, idx_rec_reg);
+		VdbeComment((v, "Remove primary index"));
 	}
 	/* Delete records about the space from the _truncate. */
-	sqlite3NestedParse(pParse, "DELETE FROM \""
-			   TARANTOOL_SYS_TRUNCATE_NAME "\" WHERE \"id\" = %d",
-			   space_id);
-
-	Expr *id_value = sqlite3ExprInteger(db, space_id);
-	const char *column = "id";
-	/* Execute not nested DELETE of a space to account DROP TABLE
-	 * changes.
-	 */
-	sqlite3DeleteByKey(pParse, TARANTOOL_SYS_SPACE_NAME,
-			   &column, &id_value, 1);
-
+	sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_reg, 1, idx_rec_reg);
+	sqlite3VdbeAddOp2(v, OP_SDelete, BOX_TRUNCATE_ID, idx_rec_reg);
+	VdbeComment((v, "Delete entry from _truncate"));
+	/* Eventually delete entry from _space. */
+	sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_reg, 1, idx_rec_reg);
+	sqlite3VdbeAddOp2(v, OP_SDelete, BOX_SPACE_ID, idx_rec_reg);
+	sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
+	VdbeComment((v, "Delete entry from _space"));
 	/* Remove the table entry from SQLite's internal schema and modify
 	 * the schema cookie.
 	 */
@@ -2603,16 +2606,18 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
 	sqlite3VdbeJumpHere(v, addr1);
 	if (memRootPage < 0)
 		sqlite3VdbeAddOp2(v, OP_Clear, tnum, 0);
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(tnum));
-	assert(space != NULL);
 	int space_ptr_reg = ++pParse->nMem;
-	sqlite3VdbeAddOp4Int64(v, OP_Int64, 0, space_ptr_reg, 0,
-			       ((int64_t) space));
+	/*
+	 * OP_Clear can use truncate optimization
+	 * (i.e. insert record into _truncate) and schema
+	 * may change. Thus, use dynamic conversion from
+	 * space id to ptr.
+	 */
+	sqlite3VdbeAddOp2(v, OP_SIDtoPtr, SQLITE_PAGENO_TO_SPACEID(tnum),
+			  space_ptr_reg);
 	sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, space_ptr_reg,
 			  (char *)pKey, P4_KEYINFO);
-	sqlite3VdbeChangeP5(v,
-			    OPFLAG_BULKCSR | ((memRootPage >= 0) ?
-					      OPFLAG_P2ISREG : 0));
+	sqlite3VdbeChangeP5(v, OPFLAG_FRESH_PTR);
 
 	addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
 	VdbeCoverage(v);
@@ -3138,8 +3143,8 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 	else if (pTblName) {
 		Vdbe *v;
 		char *zStmt;
-		Table *pSysIndex;
 		int iCursor = pParse->nTab++;
+		int index_space_ptr_reg = pParse->nTab++;
 		int iSpaceId, iIndexId, iFirstSchemaCol;
 
 		v = sqlite3GetVdbe(pParse);
@@ -3148,13 +3153,11 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 
 		sqlite3BeginWriteOperation(pParse, 1);
 
-		pSysIndex =
-		    sqlite3HashFind(&pParse->db->pSchema->tblHash,
-				    TARANTOOL_SYS_INDEX_NAME);
-		if (NEVER(!pSysIndex))
-			return;
 
-		sqlite3OpenTable(pParse, iCursor, pSysIndex, OP_OpenWrite);
+		sqlite3VdbeAddOp2(v, OP_SIDtoPtr, BOX_INDEX_ID,
+				  index_space_ptr_reg);
+		sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iCursor, 0,
+				     index_space_ptr_reg, 6);
 		sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
 
 		/* Gather the complete text of the CREATE INDEX statement into
@@ -3176,9 +3179,8 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 
 		iSpaceId = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
 		iIndexId = getNewIid(pParse, iSpaceId, iCursor);
-		createIndex(pParse, pIndex, iSpaceId, iIndexId, zStmt,
-			    pSysIndex, iCursor);
 		sqlite3VdbeAddOp1(v, OP_Close, iCursor);
+		createIndex(pParse, pIndex, iSpaceId, iIndexId, zStmt);
 
 		/* consumes zStmt */
 		iFirstSchemaCol =
@@ -3322,17 +3324,21 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName, Token * pName2, int ifExists)
 		goto exit_drop_index;
 	}
 
-	/* Generate code to remove the index and from the master table */
-	sqlite3BeginWriteOperation(pParse, 1);
-	const char *columns[2] = { "id", "iid" };
-	Expr *values[2];
-	values[0] =
-	    sqlite3ExprInteger(db, SQLITE_PAGENO_TO_SPACEID(pIndex->tnum));
-	values[1] =
-	    sqlite3ExprInteger(db, SQLITE_PAGENO_TO_INDEXID(pIndex->tnum));
-	sqlite3DeleteByKey(pParse, TARANTOOL_SYS_INDEX_NAME,
-			   columns, values, 2);
+	/*
+	 * Generate code to remove entry from _index space
+	 * But firstly, delete statistics since schema
+	 * changes after DDL.
+	 */
 	sqlite3ClearStatTables(pParse, "idx", pIndex->zName);
+	int record_reg = ++pParse->nMem;
+	int space_id_reg = ++pParse->nMem;
+	sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_PAGENO_TO_SPACEID(pIndex->tnum),
+			  space_id_reg);
+	sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_PAGENO_TO_INDEXID(pIndex->tnum),
+			  space_id_reg + 1);
+	sqlite3VdbeAddOp3(v, OP_MakeRecord, space_id_reg, 2, record_reg);
+	sqlite3VdbeAddOp2(v, OP_SDelete, BOX_INDEX_ID, record_reg);
+	sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
 	sqlite3ChangeCookie(pParse);
 
 	sqlite3VdbeAddOp3(v, OP_DropIndex, 0, 0, 0);
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 190a33cf2..95bad3773 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -2455,6 +2455,11 @@ struct Parse {
 #define OPFLAG_NOOP_IF_NULL  0x02	/* OP_FCopy: if source register is NULL
 					 * then do nothing
 					 */
+#define OPFLAG_FRESH_PTR     0x20	/* OP_Open**: set if space pointer
+					 * comes from OP_SIDtoPtr, i.e. it
+					 * is fresh, even in case schema
+					 * changes previously.
+					 */
 
 /*
  * Each trigger present in the database schema is stored as an instance of
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index a2827c882..eca6ce6b3 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -557,23 +557,22 @@ tableOfTrigger(Trigger * pTrigger)
 void
 sqlite3DropTriggerPtr(Parse * pParse, Trigger * pTrigger)
 {
-	Table *pTable MAYBE_UNUSED;
 	Vdbe *v;
-	sqlite3 *db = pParse->db;
-
-	assert(sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema) == 0);
-	pTable = tableOfTrigger(pTrigger);
-	assert(pTable);
-	assert(pTable->pSchema == pTrigger->pSchema);
-
-	/* Generate code to destroy the database record of the trigger.
+	/* Generate code to delete entry from _trigger and
+	 * internal SQL structures.
 	 */
-	assert(pTable != 0);
 	if ((v = sqlite3GetVdbe(pParse)) != 0) {
-		const char *column = "name";
-		Expr *value = sqlite3Expr(db, TK_STRING, pTrigger->zName);
-		sqlite3DeleteByKey(pParse, TARANTOOL_SYS_TRIGGER_NAME,
-				   &column, &value, 1);
+		int trig_name_reg = ++pParse->nMem;
+		int record_to_delete = ++pParse->nMem;
+		sqlite3VdbeAddOp4(v, OP_String8, 0, trig_name_reg, 0,
+				  pTrigger->zName, P4_STATIC);
+		sqlite3VdbeAddOp3(v, OP_MakeRecord, trig_name_reg, 1,
+				  record_to_delete);
+		sqlite3VdbeAddOp2(v, OP_SDelete, BOX_TRIGGER_ID,
+				  record_to_delete);
+		if (!pParse->nested)
+			sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
+
 		sqlite3ChangeCookie(pParse);
 		sqlite3VdbeAddOp4(v, OP_DropTrigger, 0, 0, 0, pTrigger->zName,
 				  0);
diff --git a/test/sql/transition.result b/test/sql/transition.result
index 500fe85c6..202ad2ac8 100644
--- a/test/sql/transition.result
+++ b/test/sql/transition.result
@@ -112,10 +112,6 @@ box.sql.execute("SELECT COUNT(*) FROM foobar WHERE bar='cacodaemon'")
 ---
 - - [0]
 ...
--- cleanup
-box.space.FOOBAR:drop()
----
-...
 -- multi-index
 -- create space
 box.sql.execute("CREATE TABLE barfoo (bar, foo NUM PRIMARY KEY)")
@@ -191,6 +187,7 @@ box.sql.execute("CREATE TABLE implicit_indices(a PRIMARY KEY,b,c,d UNIQUE)")
 box.space.IMPLICIT_INDICES:drop()
 ---
 ...
-box.sql.execute("DROP TABLE implicit_indices")
----
-...
+-- Commented until SQL and Tarantool data-dictionaries are integrated.
+-- It is incorrect, since after space dropping via Lua interface,
+-- it still remain in SQL internal structures.
+-- box.sql.execute("DROP TABLE implicit_indices")
diff --git a/test/sql/transition.test.lua b/test/sql/transition.test.lua
index 996e634ec..885993bb8 100644
--- a/test/sql/transition.test.lua
+++ b/test/sql/transition.test.lua
@@ -33,9 +33,6 @@ box.sql.execute("SELECT COUNT(*) FROM foobar WHERE bar='cacodaemon'")
 box.sql.execute("DELETE FROM foobar WHERE bar='cacodaemon'")
 box.sql.execute("SELECT COUNT(*) FROM foobar WHERE bar='cacodaemon'")
 
--- cleanup
-box.space.FOOBAR:drop()
-
 -- multi-index
 
 -- create space
@@ -70,4 +67,7 @@ box.sql.execute("CREATE TABLE rowid(x)")
 -- create a table with implicit indices (used to SEGFAULT)
 box.sql.execute("CREATE TABLE implicit_indices(a PRIMARY KEY,b,c,d UNIQUE)")
 box.space.IMPLICIT_INDICES:drop()
-box.sql.execute("DROP TABLE implicit_indices")
+-- Commented until SQL and Tarantool data-dictionaries are integrated.
+-- It is incorrect, since after space dropping via Lua interface,
+-- it still remain in SQL internal structures.
+-- box.sql.execute("DROP TABLE implicit_indices")
-- 
2.15.1





More information about the Tarantool-patches mailing list