diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index 054c0856c583e97e715528811ed1b0a8d7afc6fc..129ef823c65073fcffeb4355ce2f65b18678a9c8 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -84,10 +84,9 @@ sqlite3AlterRenameTable(Parse * pParse,	/* Parser context. */
 		goto exit_rename_table;
 	assert(pSrc->nSrc == 1);
 
-	pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
-	if (!pTab)
+	pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName);
+	if (pTab == NULL)
 		goto exit_rename_table;
-	assert(sqlite3SchemaToIndex(pParse->db, pTab->pSchema) == 0);
 
 	user_session->sql_flags |= SQLITE_PreferBuiltin;
 
@@ -99,7 +98,7 @@ sqlite3AlterRenameTable(Parse * pParse,	/* Parser context. */
 	/* Check that a table named 'zName' does not already exist
 	 * in database. If so, this is an error.
 	 */
-	if (sqlite3FindTable(db, zName)) {
+	if (sqlite3HashFind(&db->pSchema->tblHash, zName) != NULL) {
 		sqlite3ErrorMsg(pParse,
 				"there is already another table or index with this name: %s",
 				zName);
@@ -122,7 +121,7 @@ sqlite3AlterRenameTable(Parse * pParse,	/* Parser context. */
 	if (v == 0) {
 		goto exit_rename_table;
 	}
-	sqlite3BeginWriteOperation(pParse, false);
+	sql_set_multi_write(pParse, false);
 
 	/* Drop and reload the internal table schema. */
 	reloadTableSchema(pParse, pTab, zName);
@@ -163,7 +162,7 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 	zTab = &pNew->zName[16];	/* Skip the "sqlite_altertab_" prefix on the name */
 	pCol = &pNew->aCol[pNew->nCol - 1];
 	pDflt = pCol->pDflt;
-	pTab = sqlite3FindTable(db, zTab);
+	pTab = sqlite3HashFind(&db->pSchema->tblHash, zTab);;
 	assert(pTab);
 
 	/* If the default value for the new column was specified with a
@@ -257,8 +256,8 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 	assert(pParse->pNewTable == 0);
 	if (db->mallocFailed)
 		goto exit_begin_add_column;
-	pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
-	if (!pTab)
+	pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName);
+	if (pTab == NULL)
 		goto exit_begin_add_column;
 
 	/* Make sure this is not an attempt to ALTER a view. */
@@ -305,7 +304,7 @@ sqlite3AlterBeginAddColumn(Parse * pParse, SrcList * pSrc)
 	pNew->nTabRef = 1;
 
 	/* Begin a transaction and increment the schema cookie.  */
-	sqlite3BeginWriteOperation(pParse, 0);
+	sql_set_multi_write(pParse, false);
 	v = sqlite3GetVdbe(pParse);
 	if (!v)
 		goto exit_begin_add_column;
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 4eae896abfc4fd02f083bc526f18dfdaffe4c3ed..665bfbcb59a913559c655ea480511e921660e8fa 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -156,7 +156,8 @@ openStatTable(Parse * pParse,	/* Parsing context */
 		const char *zTab = aTable[i];
 		Table *pStat;
 		/* The table already exists, because it is a system space */
-		pStat = sqlite3FindTable(db, zTab);
+		pStat = sqlite3HashFind(&db->pSchema->tblHash, zTab);
+		assert(pStat != NULL);
 		aRoot[i] = pStat->tnum;
 		aCreateTbl[i] = 0;
 		if (zWhere) {
@@ -831,7 +832,6 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 		/* Do not gather statistics on system tables */
 		return;
 	}
-	assert(sqlite3SchemaToIndex(db, pTab->pSchema) == 0);
 
 	/* Establish a read-lock on the table at the shared-cache level.
 	 * Open a read-only cursor on the table. Also allocate a cursor number
@@ -907,7 +907,6 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 		pParse->nMem = MAX(pParse->nMem, regPrev + nColTest);
 
 		/* Open a read-only cursor on the index being analyzed. */
-		assert(sqlite3SchemaToIndex(db, pIdx->pSchema) == 0);
 		struct space *space =
 			space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
 		assert(space != NULL);
@@ -1028,7 +1027,7 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 		int nPkColumn = (int)index_column_count(pPk);
 		regKeyStat = sqlite3GetTempRange(pParse, nPkColumn);
 		for (j = 0; j < nPkColumn; j++) {
-			k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+			k = pPk->aiColumn[j];
 			assert(k >= 0 && k < pTab->nCol);
 			sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKeyStat + j);
 			VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
@@ -1121,7 +1120,7 @@ analyzeDatabase(Parse * pParse)
 	int iMem;
 	int iTab;
 
-	sqlite3BeginWriteOperation(pParse, 0);
+	sql_set_multi_write(pParse, false);
 	iStatCur = pParse->nTab;
 	pParse->nTab += 3;
 	openStatTable(pParse, iStatCur, 0, 0);
@@ -1145,8 +1144,7 @@ analyzeTable(Parse * pParse, Table * pTab, Index * pOnlyIdx)
 	int iStatCur;
 
 	assert(pTab != 0);
-	assert(sqlite3SchemaToIndex(pParse->db, pTab->pSchema) == 0);
-	sqlite3BeginWriteOperation(pParse, 0);
+	sql_set_multi_write(pParse, false);
 	iStatCur = pParse->nTab;
 	pParse->nTab += 3;
 	if (pOnlyIdx) {
@@ -1293,16 +1291,15 @@ analysisLoader(void *pData, int argc, char **argv, char **NotUsed)
 	if (argv == 0 || argv[0] == 0 || argv[2] == 0) {
 		return 0;
 	}
-	pTable = sqlite3FindTable(pInfo->db, argv[0]);
-	if (pTable == 0) {
+	pTable = sqlite3HashFind(&pInfo->db->pSchema->tblHash, argv[0]);
+	if (pTable == NULL)
 		return 0;
-	}
 	if (argv[1] == 0) {
 		pIndex = 0;
 	} else if (sqlite3_stricmp(argv[0], argv[1]) == 0) {
 		pIndex = sqlite3PrimaryKeyIndex(pTable);
 	} else {
-		pIndex = sqlite3FindIndex(pInfo->db, argv[1], pTable);
+		pIndex = sqlite3HashFind(&pTable->idxHash, argv[1]);
 	}
 	z = argv[2];
 
@@ -1631,19 +1628,17 @@ loadStatTbl(sqlite3 * db,	/* Database handle */
 static int
 loadStat4(sqlite3 * db)
 {
-	int rc = SQLITE_OK;	/* Result codes from subroutines */
 	Table *pTab = 0;	/* Pointer to stat table */
 
 	assert(db->lookaside.bDisable);
-	pTab = sqlite3FindTable(db, "_sql_stat4");
-	if (pTab) {
-		rc = loadStatTbl(db,
-				 pTab,
-				 "SELECT \"tbl\",\"idx\",count(*) FROM \"_sql_stat4\" GROUP BY \"tbl\",\"idx\"",
-				 "SELECT \"tbl\",\"idx\",\"neq\",\"nlt\",\"ndlt\",\"sample\" FROM \"_sql_stat4\"");
-	}
-	
-	return rc;
+	pTab = sqlite3HashFind(&db->pSchema->tblHash, "_sql_stat4");
+	/* _slq_stat4 is a system space, so it always exists. */
+	assert(pTab != NULL);
+	return loadStatTbl(db, pTab,
+			   "SELECT \"tbl\",\"idx\",count(*) FROM \"_sql_stat4\""
+			   " GROUP BY \"tbl\",\"idx\"",
+			   "SELECT \"tbl\",\"idx\",\"neq\",\"nlt\",\"ndlt\","
+			   "\"sample\" FROM \"_sql_stat4\"");
 }
 
 /*
@@ -1687,10 +1682,8 @@ sqlite3AnalysisLoad(sqlite3 * db)
 
 	/* Load new statistics out of the _sql_stat1 table */
 	sInfo.db = db;
-	if (sqlite3FindTable(db, "_sql_stat1") != 0) {
-		zSql = "SELECT \"tbl\",\"idx\",\"stat\" FROM \"_sql_stat1\"";
-		rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
-	}
+	zSql = "SELECT \"tbl\",\"idx\",\"stat\" FROM \"_sql_stat1\"";
+	rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
 
 	/* Set appropriate defaults on all indexes not in the _sql_stat1 table */
 	for (j = sqliteHashFirst(&db->pSchema->tblHash); j;
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 15b1d15d8647d6b9e383b7256a553e2681f18591..252474197852f6974e5837dd13fcf19f075e939b 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -86,26 +86,14 @@ sqlite3FinishCoding(Parse * pParse)
 	       || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
 	if (v) {
 		sqlite3VdbeAddOp0(v, OP_Halt);
-
-		/* The cookie mask contains one bit for each database file open.
-		 * (Bit 0 is for main, bit 1 is for temp, and so forth.)  Bits are
-		 * set for each database that is used.  Generate code to start a
-		 * transaction on each used database and to verify the schema cookie
-		 * on each used database.
-		 */
-		if (db->mallocFailed == 0
-		    && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
-		    ) {
+		if (db->mallocFailed == 0 || pParse->pConstExpr) {
 			int i;
 			assert(sqlite3VdbeGetOp(v, 0)->opcode == OP_Init);
 			sqlite3VdbeJumpHere(v, 0);
-			if (DbMaskTest(pParse->cookieMask, 0) != 0) {
-				if (pParse->initiateTTrans)
-					sqlite3VdbeAddOp0(v, OP_TTransaction);
-
-				if (db->init.busy == 0)
-					sqlite3VdbeChangeP5(v, 1);
-			}
+			if (pParse->initiateTTrans)
+				sqlite3VdbeAddOp0(v, OP_TTransaction);
+			if (db->init.busy == 0)
+				sqlite3VdbeChangeP5(v, 1);
 
 			/* Code constant expressions that where factored out of inner loops */
 			if (pParse->pConstExpr) {
@@ -179,32 +167,10 @@ sqlite3NestedParse(Parse * pParse, const char *zFormat, ...)
 	pParse->nested--;
 }
 
-/*
- * Locate the in-memory structure that describes a particular database
- * table given the name of that table and (optionally) the name of the
- * database containing the table.  Return NULL if not found.
- *
- * If zDatabase is 0, all databases are searched for the table and the
- * first matching table is returned.  (No checking for duplicate table
- * names is done.)  The search order is TEMP first, then MAIN, then any
- * auxiliary databases added using the ATTACH command.
- *
- * See also sqlite3LocateTable().
- */
-Table *
-sqlite3FindTable(sqlite3 * db, const char *zName)
-{
-	return sqlite3HashFind(&db->pSchema->tblHash, zName);
-}
-
 /*
  * Locate the in-memory structure that describes a particular database
  * table given the name of that table. Return NULL if not found.
  * Also leave an error message in pParse->zErrMsg.
- *
- * The difference between this routine and sqlite3FindTable() is that this
- * routine leaves an error message in pParse->zErrMsg where
- * sqlite3FindTable() does not.
  */
 Table *
 sqlite3LocateTable(Parse * pParse,	/* context in which to report errors */
@@ -216,8 +182,8 @@ sqlite3LocateTable(Parse * pParse,	/* context in which to report errors */
 
 	assert(pParse->db->pSchema != NULL);
 
-	p = sqlite3FindTable(pParse->db, zName);
-	if (p == 0) {
+	p = sqlite3HashFind(&pParse->db->pSchema->tblHash, zName);
+	if (p == NULL) {
 		const char *zMsg =
 		    flags & LOCATE_VIEW ? "no such view" : "no such table";
 		if ((flags & LOCATE_NOERR) == 0) {
@@ -229,48 +195,18 @@ sqlite3LocateTable(Parse * pParse,	/* context in which to report errors */
 	return p;
 }
 
-/*
- * Locate the table identified by *p.
- *
- * This is a wrapper around sqlite3LocateTable(). The difference between
- * sqlite3LocateTable() and this function is that this function restricts
- * the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
- * non-NULL if it is part of a view or trigger program definition. See
- * sqlite3FixSrcList() for details.
- */
-Table *
-sqlite3LocateTableItem(Parse * pParse, u32 flags, struct SrcList_item * p)
-{
-	return sqlite3LocateTable(pParse, flags, p->zName);
-}
-
-/*
- * Locate the in-memory structure that describes
- * a particular index given the name of that index
- * and the name of the database that contains the index.
- * Return NULL if not found.
- */
-Index *
-sqlite3FindIndex(MAYBE_UNUSED sqlite3 * db, const char *zName, Table * pTab)
-{
-	assert(pTab);
-
-	return sqlite3HashFind(&pTab->idxHash, zName);
-}
-
 Index *
 sqlite3LocateIndex(sqlite3 * db, const char *zName, const char *zTable)
 {
 	assert(zName);
 	assert(zTable);
 
-	Table *pTab = sqlite3FindTable(db, zTable);
+	Table *pTab = sqlite3HashFind(&db->pSchema->tblHash, zTable);
 
-	if (pTab == 0) {
-		return 0;
-	}
+	if (pTab == NULL)
+		return NULL;
 
-	return sqlite3FindIndex(db, zName, pTab);
+	return sqlite3HashFind(&pTab->idxHash, zName);
 }
 
 /*
@@ -553,18 +489,6 @@ sqlite3PrimaryKeyIndex(Table * pTab)
 	return p;
 }
 
-/*
- * Return the column of index pIdx that corresponds to table
- * column iCol.  Return -1 if not found.
- */
-i16
-sqlite3ColumnOfIndex(Index * pIdx, i16 iCol)
-{
-	/* TARANTOOL: Data layout is the same in every index.  */
-	(void) pIdx;
-	return iCol;
-}
-
 /*
  * Begin constructing a new table representation in memory.  This is
  * the first of several action routines that get called in response
@@ -610,15 +534,14 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 		return;
 
 	assert(db->pSchema != NULL);
-	pTable = sqlite3FindTable(db, zName);
-	if (pTable) {
+	pTable = sqlite3HashFind(&db->pSchema->tblHash, zName);
+	if (pTable != NULL) {
 		if (!noErr) {
 			sqlite3ErrorMsg(pParse,
 					"table %s already exists",
 					zName);
 		} else {
 			assert(!db->init.busy || CORRUPT_DB);
-			sqlite3CodeVerifySchema(pParse);
 		}
 		goto begin_table_error;
 	}
@@ -650,7 +573,7 @@ sqlite3StartTable(Parse *pParse, Token *pName, int noErr)
 	 * now.
 	 */
 	if (!db->init.busy && (v = sqlite3GetVdbe(pParse)) != 0)
-		sqlite3BeginWriteOperation(pParse, 1);
+		sql_set_multi_write(pParse, true);
 
 	/* Normal (non-error) return. */
 	return;
@@ -2035,7 +1958,6 @@ sqlite3CreateView(Parse * pParse,	/* The parsing context */
 	p = pParse->pNewTable;
 	if (p == 0 || pParse->nErr)
 		goto create_view_fail;
-	sqlite3SchemaToIndex(db, p->pSchema);
 	sqlite3FixInit(&sFix, pParse, "view", pName);
 	if (sqlite3FixSelect(&sFix, pSelect))
 		goto create_view_fail;
@@ -2202,26 +2124,22 @@ sqliteViewResetAll(sqlite3 * db)
 #define sqliteViewResetAll(A,B)
 #endif				/* SQLITE_OMIT_VIEW */
 
-/*
- * Remove entries from the sqlite_statN tables (for N in (1,2,3))
- * after a DROP INDEX or DROP TABLE command.
+/**
+ * Remove entries from the _sql_stat1 and _sql_stat4
+ * system spaces after a DROP INDEX or DROP TABLE command.
+ *
+ * @param pParse Parsing context.
+ * @param zType Type of entry to be deleted:
+ * 		'idx' or 'tbl' string literal.
+ * @param zName Name of index or table.
  */
 static void
-sqlite3ClearStatTables(Parse * pParse,	/* The parsing context */
-		       const char *zType,	/* "idx" or "tbl" */
-		       const char *zName	/* Name of index or table */
-    )
+sql_clear_stat_spaces(Parse * pParse, const char *zType, const char *zName)
 {
-	int i;
-	for (i = 1; i <= 4; i++) {
-		char zTab[24];
-		sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i);
-		if (sqlite3FindTable(pParse->db, zTab)) {
-			sqlite3NestedParse(pParse,
-					   "DELETE FROM \"%s\" WHERE \"%s\"=%Q",
-					   zTab, zType, zName);
-		}
-	}
+	sqlite3NestedParse(pParse, "DELETE FROM \"_sql_stat1\" WHERE \"%s\"=%Q",
+			   zType, zName);
+	sqlite3NestedParse(pParse, "DELETE FROM \"_sql_stat4\" WHERE \"%s\"=%Q",
+			   zType, zName);
 }
 
 /*
@@ -2236,7 +2154,6 @@ 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
@@ -2372,15 +2289,12 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr)
 	if (noErr)
 		db->suppressErr++;
 	assert(isView == 0 || isView == LOCATE_VIEW);
-	pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
+	pTab = sqlite3LocateTable(pParse, isView, pName->a[0].zName);
 	if (noErr)
 		db->suppressErr--;
 
-	if (pTab == 0) {
-		if (noErr)
-			sqlite3CodeVerifySchema(pParse);
+	if (pTab == NULL)
 		goto exit_drop_table;
-	}
 #ifndef SQLITE_OMIT_VIEW
 	/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
 	 * on a table.
@@ -2410,8 +2324,7 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr)
 	 *    space_id from _space.
 	 */
 
-	sqlite3BeginWriteOperation(pParse, 1);
-	sqlite3ClearStatTables(pParse, "tbl", pTab->zName);
+	sql_clear_stat_spaces(pParse, "tbl", pTab->zName);
 	sqlite3FkDropTable(pParse, pName, pTab);
 	sqlite3CodeDropTable(pParse, pTab, isView);
 
@@ -2876,7 +2789,7 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 			 */
 			assert(0);
 		}
-		pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
+		pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName);
 		assert(db->mallocFailed == 0 || pTab == 0);
 		if (pTab == 0)
 			goto exit_create_index;
@@ -2916,21 +2829,21 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 			goto exit_create_index;
 		assert(pName->z != 0);
 		if (!db->init.busy) {
-			if (sqlite3FindTable(db, zName) != 0) {
+			if (sqlite3HashFind(&db->pSchema->tblHash, zName) !=
+			    NULL) {
 				sqlite3ErrorMsg(pParse,
 						"there is already a table named %s",
 						zName);
 				goto exit_create_index;
 			}
 		}
-		if (sqlite3FindIndex(db, zName, pTab) != 0) {
+		if (sqlite3HashFind(&pTab->idxHash, zName) != NULL) {
 			if (!ifNotExist) {
 				sqlite3ErrorMsg(pParse,
 						"index %s.%s already exists",
 						pTab->zName, zName);
 			} else {
 				assert(!db->init.busy);
-				sqlite3CodeVerifySchema(pParse);
 			}
 			goto exit_create_index;
 		}
@@ -3075,9 +2988,6 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 	if (pParse->pNewTable == 0)
 		estimateIndexWidth(pIndex);
 
-	assert(pTab->iPKey < 0
-	       || sqlite3ColumnOfIndex(pIndex, pTab->iPKey) >= 0);
-
 	if (pTab == pParse->pNewTable) {
 		/* This routine has been called to create an automatic index as a
 		 * result of a PRIMARY KEY or UNIQUE clause on a column definition, or
@@ -3186,7 +3096,7 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 		if (v == 0)
 			goto exit_create_index;
 
-		sqlite3BeginWriteOperation(pParse, 1);
+		sql_set_multi_write(pParse, true);
 
 
 		sqlite3VdbeAddOp2(v, OP_SIDtoPtr, BOX_INDEX_ID,
@@ -3382,8 +3292,6 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName, Token * pName2, int ifExists)
 		if (!ifExists) {
 			sqlite3ErrorMsg(pParse, "no such index: %s.%S",
 					zTableName, pName, 0);
-		} else {
-			sqlite3CodeVerifySchema(pParse);
 		}
 		pParse->checkSchema = 1;
 		goto exit_drop_index;
@@ -3412,7 +3320,7 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName, Token * pName2, int ifExists)
 	 * But firstly, delete statistics since schema
 	 * changes after DDL.
 	 */
-	sqlite3ClearStatTables(pParse, "idx", pIndex->zName);
+	sql_clear_stat_spaces(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),
@@ -3929,56 +3837,15 @@ sqlite3Savepoint(Parse * pParse, int op, Token * pName)
 	}
 }
 
-/*
- * Record the fact that the schema cookie will need to be verified
- * for database.  The code to actually verify the schema cookie
- * will occur at the end of the top-level VDBE and will be generated
- * later, by sqlite3FinishCoding().
- */
-void
-sqlite3CodeVerifySchema(Parse * pParse)
-{
-	Parse *pToplevel = sqlite3ParseToplevel(pParse);
-
-	if (DbMaskTest(pToplevel->cookieMask, 0) == 0) {
-		DbMaskSet(pToplevel->cookieMask, 0);
-	}
-}
-
-/*
- * Generate VDBE code that prepares for doing an operation that
- * might change the database.
- *
- * This routine starts a new transaction if we are not already within
- * a transaction.  If we are already within a transaction, then a checkpoint
- * is set if the setStatement parameter is true.  A checkpoint should
- * be set for operations that might fail (due to a constraint) part of
- * the way through and which will need to undo some writes without having to
- * rollback the whole transaction.  For operations where all constraints
- * can be checked before any changes are made to the database, it is never
- * necessary to undo a write and the checkpoint should not be set.
- */
-void
-sqlite3BeginWriteOperation(Parse * pParse, int setStatement)
-{
-	Parse *pToplevel = sqlite3ParseToplevel(pParse);
-	sqlite3CodeVerifySchema(pParse);
-	DbMaskSet(pToplevel->writeMask, 0);
-	pToplevel->isMultiWrite |= setStatement;
-}
-
-/*
- * Indicate that the statement currently under construction might write
- * more than one entry (example: deleting one row then inserting another,
- * inserting multiple rows in a table, or inserting a row and index entries.)
- * If an abort occurs after some of these writes have completed, then it will
- * be necessary to undo the completed writes.
+/**
+ * Set flag in parse context, which indicates that during query
+ * execution multiple insertion/updates may occur.
  */
 void
-sqlite3MultiWrite(Parse * pParse)
+sql_set_multi_write(struct Parse *parse_context, bool is_set)
 {
-	Parse *pToplevel = sqlite3ParseToplevel(pParse);
-	pToplevel->isMultiWrite = 1;
+	Parse *pToplevel = sqlite3ParseToplevel(parse_context);
+	pToplevel->isMultiWrite |= is_set;
 }
 
 /*
@@ -4095,7 +3962,7 @@ reindexTable(Parse * pParse, Table * pTab, char const *zColl)
 
 	for (pIndex = pTab->pIndex; pIndex; pIndex = pIndex->pNext) {
 		if (zColl == 0 || collationMatch(zColl, pIndex)) {
-			sqlite3BeginWriteOperation(pParse, 0);
+			sql_set_multi_write(pParse, false);
 			sqlite3RefillIndex(pParse, pIndex, -1);
 		}
 	}
@@ -4170,8 +4037,8 @@ sqlite3Reindex(Parse * pParse, Token * pName1, Token * pName2)
 	z = sqlite3NameFromToken(db, pName1);
 	if (z == 0)
 		return;
-	pTab = sqlite3FindTable(db, z);
-	if (pTab) {
+	pTab = sqlite3HashFind(&db->pSchema->tblHash, z);
+	if (pTab != NULL) {
 		reindexTable(pParse, pTab, 0);
 		sqlite3DbFree(db, z);
 		return;
@@ -4180,16 +4047,15 @@ sqlite3Reindex(Parse * pParse, Token * pName1, Token * pName2)
 		zTable = sqlite3NameFromToken(db, pName2);
 	}
 
-	pTab = sqlite3FindTable(db, zTable);
+	pTab = sqlite3HashFind(&db->pSchema->tblHash, zTable);
 	if (pTab == 0) {
 		sqlite3ErrorMsg(pParse, "no such table: %s", zTable);
 		goto exit_reindex;
 	}
 
-	pIndex = sqlite3FindIndex(db, z, pTab);
-
-	if (pIndex) {
-		sqlite3BeginWriteOperation(pParse, 0);
+	pIndex = sqlite3HashFind(&pTab->idxHash, z);
+	if (pIndex != NULL) {
+		sql_set_multi_write(pParse, false);
 		sqlite3RefillIndex(pParse, pIndex, -1);
 		return;
 	}
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index ab8dd0bc3f8f936a4bfcf59f13a878c1f5f10630..bb4338f4777b273338b4f8c80b9fbc3c6c1b420c 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -56,15 +56,13 @@ sqlite3SrcListLookup(Parse * pParse, SrcList * pSrc)
 	struct SrcList_item *pItem = pSrc->a;
 	Table *pTab;
 	assert(pItem && pSrc->nSrc == 1);
-	pTab = sqlite3LocateTableItem(pParse, 0, pItem);
+	pTab = sqlite3LocateTable(pParse, 0, pItem->zName);
 	sqlite3DeleteTable(pParse->db, pItem->pTab);
 	pItem->pTab = pTab;
-	if (pTab) {
+	if (pTab != NULL)
 		pTab->nTabRef++;
-	}
-	if (sqlite3IndexedByLookup(pParse, pItem)) {
-		pTab = 0;
-	}
+	if (sqlite3IndexedByLookup(pParse, pItem))
+		pTab = NULL;
 	return pTab;
 }
 
@@ -113,7 +111,6 @@ sqlite3MaterializeView(Parse * pParse,	/* Parsing context */
 	Select *pSel;
 	SrcList *pFrom;
 	sqlite3 *db = pParse->db;
-	assert(sqlite3SchemaToIndex(db, pView->pSchema) == 0);
 	pWhere = sqlite3ExprDup(db, pWhere, 0);
 	pFrom = sqlite3SrcListAppend(db, 0, 0);
 	if (pFrom) {
@@ -325,7 +322,7 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 	}
 	if (pParse->nested == 0)
 		sqlite3VdbeCountChanges(v);
-	sqlite3BeginWriteOperation(pParse, 1);
+	sql_set_multi_write(pParse, true);
 
 	/* If we are trying to delete from a view, realize that view into
 	 * an ephemeral table.
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 78ebc91a591ef269f9097fa7e285c06f5b782177..8071314670efbe83a691a1e17d681b3a7b437385 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2455,9 +2455,6 @@ sqlite3FindInIndex(Parse * pParse,	/* Parsing context */
 		assert(p->pEList->a[0].pExpr != 0);	/* Because of isCandidateForInOpt(p) */
 		assert(p->pSrc != 0);	/* Because of isCandidateForInOpt(p) */
 		pTab = p->pSrc->a[0].pTab;
-
-		sqlite3CodeVerifySchema(pParse);
-
 		assert(v);	/* sqlite3GetVdbe() has always been previously called */
 
 		Index *pIdx;	/* Iterator variable */
@@ -3584,8 +3581,7 @@ sqlite3ExprCodeGetColumnOfTable(Vdbe * v,	/* The VDBE under construction */
 				int regOut	/* Extract the value into this register */
     )
 {
-	int x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
-	sqlite3VdbeAddOp3(v, OP_Column, iTabCur, x, regOut);
+	sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
 	if (iCol >= 0) {
 		sqlite3ColumnDefault(v, pTab, iCol, regOut);
 	}
@@ -5314,8 +5310,7 @@ exprIdxCover(Walker * pWalker, Expr * pExpr)
 {
 	if (pExpr->op == TK_COLUMN
 	    && pExpr->iTable == pWalker->u.pIdxCover->iCur
-	    && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx,
-				    pExpr->iColumn) < 0) {
+	    && pExpr->iColumn < 0) {
 		pWalker->eCode = 1;
 		return WRC_Abort;
 	}
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index f4a6b2707e023a1afab8c8fe56c7816962fe845b..f56b6d9cde759d031560731fd665ff5534b84cd2 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -961,7 +961,8 @@ sqlite3FkCheck(Parse * pParse,	/* Parse context */
 		 * early.
 		 */
 		if (pParse->disableTriggers) {
-			pTo = sqlite3FindTable(db, pFKey->zTo);
+			pTo = sqlite3HashFind(&db->pSchema->tblHash,
+					      pFKey->zTo);
 		} else {
 			pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo);
 		}
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index c76910e5b07085b7680fea30dee52f154ab74d8c..b24d55b070c0cb7deefad5a4c07790e66196cb8c 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -422,7 +422,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 		goto insert_cleanup;
 	if (pParse->nested == 0)
 		sqlite3VdbeCountChanges(v);
-	sqlite3BeginWriteOperation(pParse, pSelect || pTrigger);
+	sql_set_multi_write(pParse, pSelect || pTrigger);
 
 #ifndef SQLITE_OMIT_XFER_OPT
 	/* If the statement is of the form
@@ -1382,8 +1382,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			if (pIdx != pPk) {
 				for (i = 0; i < nPkCol; i++) {
 					assert(pPk->aiColumn[i] >= 0);
-					x = sqlite3ColumnOfIndex(pIdx,
-								 pPk->aiColumn[i]);
+					x = pPk->aiColumn[i];
 					sqlite3VdbeAddOp3(v, OP_Column,
 							  iThisCur, x, regR + i);
 					VdbeComment((v, "%s.%s", pTab->zName,
@@ -1446,7 +1445,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 		default: {
 				Trigger *pTrigger = 0;
 				assert(onError == ON_CONFLICT_ACTION_REPLACE);
-				sqlite3MultiWrite(pParse);
+				sql_set_multi_write(pParse, true);
 				if (user_session->
 				    sql_flags & SQLITE_RecTriggers) {
 					pTrigger =
@@ -1708,9 +1707,8 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	int regData, regTupleid;	/* Registers holding data and tupleid */
 	struct session *user_session = current_session();
 
-	if (pSelect == 0) {
+	if (pSelect == NULL)
 		return 0;	/* Must be of the form  INSERT INTO ... SELECT ... */
-	}
 	if (pParse->pWith || pSelect->pWith) {
 		/* Do not attempt to process this query if there are an WITH clauses
 		 * attached to it. Proceeding may generate a false "no such table: xxx"
@@ -1771,8 +1769,8 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	 * we have to check the semantics.
 	 */
 	pItem = pSelect->pSrc->a;
-	pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
-	if (pSrc == 0) {
+	pSrc = sqlite3LocateTable(pParse, 0, pItem->zName);
+	if (pSrc == NULL) {
 		return 0;	/* FROM clause does not contain a real table */
 	}
 	if (pSrc == pDest) {
@@ -1857,7 +1855,6 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	sqlite3_xferopt_count++;
 #endif
 	v = sqlite3GetVdbe(pParse);
-	sqlite3CodeVerifySchema(pParse);
 	iSrc = pParse->nTab++;
 	iDest = pParse->nTab++;
 	regData = sqlite3GetTempReg(pParse);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 2804cc777eea86cbd8cd25b150ddb0b318701385..b724c9845d38a41201351c0fc4e9a806ec08f82a 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -356,7 +356,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				Column *pCol;
 				Index *pPk = sqlite3PrimaryKeyIndex(pTab);
 				pParse->nMem = 6;
-				sqlite3CodeVerifySchema(pParse);
 				sqlite3ViewGetColumnNames(pParse, pTab);
 				for (i = 0, pCol = pTab->aCol; i < pTab->nCol;
 				     i++, pCol++) {
@@ -395,7 +394,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			Index *pIdx;
 			HashElem *i;
 			pParse->nMem = 4;
-			sqlite3CodeVerifySchema(pParse);
 			for (i = sqliteHashFirst(&db->pSchema->tblHash); i;
 			     i = sqliteHashNext(i)) {
 				Table *pTab = sqliteHashData(i);
@@ -439,7 +437,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 						pParse->nMem = 3;
 					}
 					mx = index_column_count(pIdx);
-					sqlite3CodeVerifySchema(pParse);
 					assert(pParse->nMem <=
 					       pPragma->nPragCName);
 					for (i = 0; i < mx; i++) {
@@ -479,10 +476,10 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				Index *pIdx;
 				Table *pTab;
 				int i;
-				pTab = sqlite3FindTable(db, zRight);
-				if (pTab) {
+				pTab = sqlite3HashFind(&db->pSchema->tblHash,
+						       zRight);
+				if (pTab != NULL) {
 					pParse->nMem = 5;
-					sqlite3CodeVerifySchema(pParse);
 					for (pIdx = pTab->pIndex, i = 0; pIdx;
 					     pIdx = pIdx->pNext, i++) {
 						const char *azOrigin[] =
@@ -539,13 +536,13 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			if (zRight) {
 				FKey *pFK;
 				Table *pTab;
-				pTab = sqlite3FindTable(db, zRight);
-				if (pTab) {
+				pTab = sqlite3HashFind(&db->pSchema->tblHash,
+						       zRight);
+				if (pTab != NULL) {
 					pFK = pTab->pFKey;
 					if (pFK) {
 						int i = 0;
 						pParse->nMem = 8;
-						sqlite3CodeVerifySchema(pParse);
 						while (pFK) {
 							int j;
 							for (j = 0;
@@ -595,7 +592,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			pParse->nMem += 4;
 			regKey = ++pParse->nMem;
 			regRow = ++pParse->nMem;
-			sqlite3CodeVerifySchema(pParse);
 			k = sqliteHashFirst(&db->pSchema->tblHash);
 			while (k) {
 				if (zRight) {
@@ -617,8 +613,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				for (i = 1, pFK = pTab->pFKey; pFK;
 				     i++, pFK = pFK->pNextFrom) {
 					pParent =
-					    sqlite3FindTable(db, pFK->zTo);
-					if (pParent == 0)
+						sqlite3HashFind(&db->pSchema->tblHash,
+								pFK->zTo);
+					if (pParent == NULL)
 						continue;
 					pIdx = 0;
 					x = sqlite3FkLocateIndex(pParse,
@@ -655,7 +652,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				for (i = 1, pFK = pTab->pFKey; pFK;
 				     i++, pFK = pFK->pNextFrom) {
 					pParent =
-					    sqlite3FindTable(db, pFK->zTo);
+						sqlite3HashFind(&db->pSchema->tblHash,
+								pFK->zTo);
 					pIdx = 0;
 					aiCols = 0;
 					if (pParent) {
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index 0ea181d444a21746229c5c8fa5764a8e446956d5..7a16074dc7391454e73f3bb0342618a5fdaeda9e 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -204,35 +204,6 @@ sqlite3InitDatabase(sqlite3 * db)
 	return rc;
 }
 
-/*
- * Convert a schema pointer into the 0 index that indicates
- * that schema refers to a single database.
- * This method is inherited from SQLite, which has several dbs.
- * But we have only one, so it is used only in assertions.
- */
-int
-sqlite3SchemaToIndex(sqlite3 * db, Schema * pSchema)
-{
-	int i = -1000000;
-
-	/* If pSchema is NULL, then return -1000000. This happens when code in
-	 * expr.c is trying to resolve a reference to a transient table (i.e. one
-	 * created by a sub-select). In this case the return value of this
-	 * function should never be used.
-	 *
-	 * We return -1000000 instead of the more usual -1 simply because using
-	 * -1000000 as the incorrect index into db->aDb[] is much
-	 * more likely to cause a segfault than -1 (of course there are assert()
-	 * statements too, but it never hurts to play the odds).
-	 */
-	if (pSchema) {
-		if (db->pSchema == pSchema) {
-			i = 0;
-		}
-		assert(i == 0);
-	}
-	return i;
-}
 
 /*
  * Free all memory allocations in the pParse object
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 9e64b434e4c32555964b1f33b946145e5fc96401..d97e466b5dcaa73f336954affb339712516ff68d 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -4737,8 +4737,8 @@ selectExpander(Walker * pWalker, Select * p)
 			/* An ordinary table or view name in the FROM clause */
 			assert(pFrom->pTab == 0);
 			pFrom->pTab = pTab =
-			    sqlite3LocateTableItem(pParse, 0, pFrom);
-			if (pTab == 0)
+			    sqlite3LocateTable(pParse, 0, pFrom->zName);
+			if (pTab == NULL)
 				return WRC_Abort;
 			if (pTab->nTabRef >= 0xffff) {
 				sqlite3ErrorMsg(pParse,
@@ -6147,8 +6147,6 @@ sqlite3Select(Parse * pParse,		/* The parser context */
 				Index *pBest;	/* Best index found so far */
 				int iRoot = pTab->tnum;	/* Root page of scanned b-tree */
 
-				sqlite3CodeVerifySchema(pParse);
-
 				/* Search for the index that has the lowest scan cost.
 				 *
 				 * (2011-04-15) Do not do a full scan of an unordered index.
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index e26239fd4fed84f21d6d1bfd816dc503ccf5dcf3..d4e1f9201be70e0b0c8849fc4e545b15c8e1f0e8 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -2901,25 +2901,6 @@ struct TriggerPrg {
 	u32 aColmask[2];	/* Masks of old.*, new.* columns accessed */
 };
 
-/*
- * The yDbMask datatype for the bitmask of all attached databases.
- */
-#if SQLITE_MAX_ATTACHED>30
-typedef unsigned char yDbMask[(SQLITE_MAX_ATTACHED + 9) / 8];
-#define DbMaskTest(M,I)    (((M)[(I)/8]&(1<<((I)&7)))!=0)
-#define DbMaskZero(M)      memset((M),0,sizeof(M))
-#define DbMaskSet(M,I)     (M)[(I)/8]|=(1<<((I)&7))
-#define DbMaskAllZero(M)   sqlite3DbMaskAllZero(M)
-#define DbMaskNonZero(M)   (sqlite3DbMaskAllZero(M)==0)
-#else
-typedef unsigned int yDbMask;
-#define DbMaskTest(M,I)    (((M)&(((yDbMask)1)<<(I)))!=0)
-#define DbMaskZero(M)      (M)=0
-#define DbMaskSet(M,I)     (M)|=(((yDbMask)1)<<(I))
-#define DbMaskAllZero(M)   (M)==0
-#define DbMaskNonZero(M)   (M)!=0
-#endif
-
 /*
  * An SQL parser context.  A copy of this structure is passed through
  * the parser and down into all the parser action routine in order to
@@ -2960,8 +2941,6 @@ struct Parse {
 	int *aLabel;		/* Space to hold the labels */
 	ExprList *pConstExpr;	/* Constant expressions */
 	Token constraintName;	/* Name of the constraint currently being parsed */
-	yDbMask writeMask;	/* Start a write transaction on these databases */
-	yDbMask cookieMask;	/* Bitmask of schema verified databases */
 	int regRoot;		/* Register holding root page number for new objects */
 	int nMaxArg;		/* Max args passed to user function by sub-program */
 #ifdef SELECTTRACE_ENABLED
@@ -3562,7 +3541,6 @@ int sqlite3ColumnsFromExprList(Parse *, ExprList *, i16 *, Column **);
 void sqlite3SelectAddColumnTypeAndCollation(Parse *, Table *, Select *);
 Table *sqlite3ResultSetOfSelect(Parse *, Select *);
 Index *sqlite3PrimaryKeyIndex(Table *);
-i16 sqlite3ColumnOfIndex(Index *, i16);
 void sqlite3StartTable(Parse *, Token *, int);
 void sqlite3AddColumn(Parse *, Token *, Token *);
 void sqlite3AddNotNull(Parse *, int);
@@ -3599,9 +3577,6 @@ int sqlite3ViewGetColumnNames(Parse *, Table *);
 #define sqlite3ViewGetColumnNames(A,B) 0
 #endif
 
-#if SQLITE_MAX_ATTACHED>30
-int sqlite3DbMaskAllZero(yDbMask);
-#endif
 void sqlite3DropTable(Parse *, SrcList *, int, int);
 void sqlite3DeleteTable(sqlite3 *, Table *);
 void sqlite3Insert(Parse *, SrcList *, Select *, IdList *, int);
@@ -3681,12 +3656,9 @@ int sqlite3ExprCodeExprList(Parse *, ExprList *, int, int, u8);
 void sqlite3ExprIfTrue(Parse *, Expr *, int, int);
 void sqlite3ExprIfFalse(Parse *, Expr *, int, int);
 void sqlite3ExprIfFalseDup(Parse *, Expr *, int, int);
-Table *sqlite3FindTable(sqlite3 *, const char *);
 #define LOCATE_VIEW    0x01
 #define LOCATE_NOERR   0x02
 Table *sqlite3LocateTable(Parse *, u32 flags, const char *);
-Table *sqlite3LocateTableItem(Parse *, u32 flags, struct SrcList_item *);
-Index *sqlite3FindIndex(sqlite3 *, const char *, Table *);
 Index *sqlite3LocateIndex(sqlite3 *, const char *, const char *);
 void sqlite3UnlinkAndDeleteTable(sqlite3 *, const char *);
 void sqlite3UnlinkAndDeleteIndex(sqlite3 *, Index *);
@@ -3704,7 +3676,6 @@ void sqlite3PrngSaveState(void);
 void sqlite3PrngRestoreState(void);
 #endif
 void sqlite3RollbackAll(Vdbe *, int);
-void sqlite3CodeVerifySchema(Parse *);
 void sqlite3BeginTransaction(Parse *, int);
 void sqlite3CommitTransaction(Parse *);
 void sqlite3RollbackTransaction(Parse *);
@@ -3742,8 +3713,8 @@ vdbe_emit_insertion_completion(Vdbe *v, int cursor_id, int tuple_id,
 
 int sqlite3OpenTableAndIndices(Parse *, Table *, int, u8, int, u8 *, int *,
 			       int *, u8, u8);
-void sqlite3BeginWriteOperation(Parse *, int);
-void sqlite3MultiWrite(Parse *);
+void
+sql_set_multi_write(Parse *, bool);
 void sqlite3MayAbort(Parse *);
 void sqlite3HaltConstraint(Parse *, int, int, char *, i8, u8);
 void sqlite3UniqueConstraint(Parse *, int, Index *);
@@ -3936,8 +3907,6 @@ struct coll *sqlite3GetCollSeq(Parse *, struct coll *, const char *);
 char sqlite3AffinityType(const char *, u8 *);
 void sqlite3Analyze(Parse *, Token *);
 int sqlite3InvokeBusyHandler(BusyHandler *);
-int sqlite3FindDb(sqlite3 *, Token *);
-int sqlite3FindDbName(const char *);
 int sqlite3AnalysisLoad(sqlite3 *);
 void sqlite3DeleteIndexSamples(sqlite3 *, Index *);
 void sqlite3DefaultRowEst(Index *);
@@ -3949,7 +3918,6 @@ void sqlite3RegisterLikeFunctions(sqlite3 *, int);
 int sqlite3IsLikeFunction(sqlite3 *, Expr *, int *, char *);
 void sqlite3SchemaClear(sqlite3 *);
 Schema *sqlite3SchemaCreate(sqlite3 *);
-int sqlite3SchemaToIndex(sqlite3 * db, Schema *);
 KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *, int, int);
 void sqlite3KeyInfoUnref(KeyInfo *);
 KeyInfo *sqlite3KeyInfoRef(KeyInfo *);
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index eaa08eb4c60ab406960d810728f55207c091aded..ed7b948aba8173bb3fd56f4621919fffda5b4d18 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -129,7 +129,6 @@ sqlite3BeginTrigger(Parse * pParse,	/* The parse context of the CREATE TRIGGER s
 					zName);
 		} else {
 			assert(!db->init.busy);
-			sqlite3CodeVerifySchema(pParse);
 		}
 		goto trigger_cleanup;
 	}
@@ -215,7 +214,6 @@ sqlite3FinishTrigger(Parse * pParse,	/* Parser context */
 	if (NEVER(pParse->nErr) || !pTrig)
 		goto triggerfinish_cleanup;
 	zName = pTrig->zName;
-	assert(sqlite3SchemaToIndex(pParse->db, pTrig->pSchema) == 0);
 	pTrig->step_list = pStepList;
 	while (pStepList) {
 		pStepList->pTrig = pTrig;
@@ -294,7 +292,7 @@ sqlite3FinishTrigger(Parse * pParse,	/* Parser context */
 		iFirstCol = pParse->nMem + 1;
 		pParse->nMem += 2;
 
-		sqlite3BeginWriteOperation(pParse, 0);
+		sql_set_multi_write(pParse, false);
 		sqlite3VdbeAddOp4(v,
 				  OP_String8, 0, iFirstCol, 0,
 				  zName, P4_STATIC);
@@ -527,8 +525,6 @@ sqlite3DropTrigger(Parse * pParse, SrcList * pName, int noErr)
 		if (!noErr) {
 			sqlite3ErrorMsg(pParse, "no such trigger: %S", pName,
 					0);
-		} else {
-			sqlite3CodeVerifySchema(pParse);
 		}
 		pParse->checkSchema = 1;
 		goto drop_trigger_cleanup;
@@ -673,7 +669,6 @@ targetSrcList(Parse * pParse,	/* The parsing context */
 		assert(pSrc->nSrc > 0);
 		pSrc->a[pSrc->nSrc - 1].zName =
 		    sqlite3DbStrDup(db, pStep->zTarget);
-		assert(sqlite3SchemaToIndex(db, pStep->pTrig->pSchema) == 0);
 	}
 	return pSrc;
 }
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 98e696ddfd0f3675a5b76c62619b599a57cf2289..83c05ab489df4c03b8b4e55323c30b78bfdc783a 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -288,7 +288,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 		goto update_cleanup;
 	if (pParse->nested == 0)
 		sqlite3VdbeCountChanges(v);
-	sqlite3BeginWriteOperation(pParse, 1);
+	sql_set_multi_write(pParse, true);
 
 	/* Allocate required registers. */
 	regOldPk = regNewPk = ++pParse->nMem;
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index c51bd7455b30f83ab618fa5d5c00095aa8371766..2a2630281a6bb00fbae2e3259b87621b857f90dc 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -4615,7 +4615,6 @@ sqlite3WhereBegin(Parse * pParse,	/* The parser context */
 #endif				/* SQLITE_ENABLE_COLUMN_USED_MASK */
 			}
 		}
-		sqlite3CodeVerifySchema(pParse);
 	}
 	pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
 	if (db->mallocFailed)
@@ -4813,7 +4812,6 @@ sqlite3WhereEnd(WhereInfo * pWInfo)
 				if (pOp->opcode == OP_Column) {
 					int x = pOp->p2;
 					assert(pIdx->pTable == pTab);
-					x = sqlite3ColumnOfIndex(pIdx, x);
 					if (x >= 0) {
 						pOp->p2 = x;
 						pOp->p1 = pLevel->iIdxCur;
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index aaffa7c1c6827ceb19f1ede6e143819e92e251ea..6aec4ae795b8526dcfb20cad402f4be71b5ef38d 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -847,7 +847,7 @@ codeCursorHintCheckExpr(Walker * pWalker, Expr * pExpr)
 	assert(pHint->pIdx != 0);
 	if (pExpr->op == TK_COLUMN
 	    && pExpr->iTable == pHint->iTabCur
-	    && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn) < 0) {
+	    && (pExpr->iColumn < 0)) {
 		pWalker->eCode = 1;
 	}
 	return WRC_Continue;
@@ -921,8 +921,6 @@ codeCursorHintFixExpr(Walker * pWalker, Expr * pExpr)
 			pExpr->iTable = reg;
 		} else if (pHint->pIdx != 0) {
 			pExpr->iTable = pHint->iIdxCur;
-			pExpr->iColumn =
-			    sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
 			assert(pExpr->iColumn >= 0);
 		}
 	} else if (pExpr->op == TK_AGG_FUNCTION) {
@@ -1517,8 +1515,7 @@ sqlite3WhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about t
 			int nPkCol = index_column_count(pPk);
 			int iKeyReg = sqlite3GetTempRange(pParse, nPkCol);
 			for (j = 0; j < nPkCol; j++) {
-				k = sqlite3ColumnOfIndex(pIdx,
-							 pPk->aiColumn[j]);
+				k = pPk->aiColumn[j];
 				sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k,
 						  iKeyReg + j);
 			}