Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH] sql: get rid off tnum field of struct Table
@ 2018-07-20 11:37 Kirill Yukhin
  2018-07-20 14:07 ` [tarantool-patches] " n.pettik
  2018-07-20 16:53 ` Kirill Yukhin
  0 siblings, 2 replies; 5+ messages in thread
From: Kirill Yukhin @ 2018-07-20 11:37 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches, Kirill Yukhin

Basic structures (struct Table/Index) of legacy SQL's data
dictionary used to so-called tnum to refer to engine's
btree structures. Tarantool used this field to store composition
of space_id and index_id. Recently both structures incorporated
native space_def/index_def descriptors.
This patch finally removes tnum field. It also refactors
init_callback machinery, removing varargs from declarations.

Closes #3482
---
Issue: https://github.com/tarantool/tarantool/issues/3482
Branch: https://github.com/tarantool/tarantool/commits/kyukhin/gh-3482-remove-tnum

 src/box/sql.c              | 108 ++++++++++++++-------------------------------
 src/box/sql/alter.c        |   5 ++-
 src/box/sql/analyze.c      |  16 +++----
 src/box/sql/build.c        |  43 +++++++-----------
 src/box/sql/delete.c       |   2 +-
 src/box/sql/expr.c         |   6 +--
 src/box/sql/fkey.c         |  12 +++--
 src/box/sql/insert.c       |  43 +++++++-----------
 src/box/sql/main.c         |  27 ------------
 src/box/sql/pragma.c       |  14 ++----
 src/box/sql/prepare.c      |  91 +++++++++++++++-----------------------
 src/box/sql/select.c       |   3 +-
 src/box/sql/sqliteInt.h    |  53 ++++++++++++++--------
 src/box/sql/tarantoolInt.h |  22 +++++++--
 src/box/sql/vdbe.c         |  56 +++++++++--------------
 src/box/sql/vdbe.h         |   1 -
 src/box/sql/vdbeaux.c      |   9 +---
 src/box/sql/where.c        |  69 ++++++++++++-----------------
 18 files changed, 227 insertions(+), 353 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index d2cc0a9..d48c3cf 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -726,28 +726,13 @@ rename_fail:
 	return SQL_TARANTOOL_ERROR;
 }
 
-/*
- * Rename the table in _space. Update tuple with corresponding id with
- * new name and statement fields and insert back. If sql_stmt is NULL,
- * then return from function after getting length of new statement:
- * it is the way how to dynamically allocate memory for new statement in VDBE.
- * So basically this function should be called twice: firstly to get length of
- * CREATE TABLE statement, and secondly to make routine of replacing tuple and
- * filling out param sql_stmt with new CREATE TABLE statement.
- *
- * @param iTab pageno of table to be renamed
- * @param new_name new name of table
- * @param[out] sql_stmt CREATE TABLE statement for new name table, can be NULL.
- *
- * @retval SQLITE_OK on success, SQLITE_TARANTOOL_ERROR otherwise.
- */
-int tarantoolSqlite3RenameTable(int iTab, const char *new_name, char **sql_stmt)
+int
+sql_rename_table(uint32_t space_id, const char *new_name, char **sql_stmt)
 {
-	assert(iTab > 0);
-	assert(new_name);
-	assert(sql_stmt);
+	assert(space_id != 0);
+	assert(new_name != NULL);
+	assert(sql_stmt != NULL);
 
-	int space_id = SQLITE_PAGENO_TO_SPACEID(iTab);
 	box_tuple_t *tuple;
 	uint32_t key_len = mp_sizeof_uint(space_id) + mp_sizeof_array(1);
 	char *key_begin = (char*) region_alloc(&fiber()->gc, key_len);
@@ -858,14 +843,13 @@ rename_fail:
  * Acts almost as tarantoolSqlite3RenameTable, but doesn't change
  * name of table, only statement.
  */
-int tarantoolSqlite3RenameParentTable(int iTab, const char *old_parent_name,
+int tarantoolSqlite3RenameParentTable(int space_id, const char *old_parent_name,
 				      const char *new_parent_name)
 {
-	assert(iTab > 0);
-	assert(old_parent_name);
-	assert(new_parent_name);
+	assert(space_id != 0);
+	assert(old_parent_name != NULL);
+	assert(new_parent_name != NULL);
 
-	int space_id = SQLITE_PAGENO_TO_SPACEID(iTab);
 	box_tuple_t *tuple;
 	uint32_t key_len = mp_sizeof_uint(space_id) + mp_sizeof_array(1);
 
@@ -1181,63 +1165,34 @@ cursor_advance(BtCursor *pCur, int *pRes)
  * Schema support.
  */
 
-/*
- * Manully add objects to SQLite in-memory schema.
- * This is loosely based on sqlite_master row format.
- * @Params
- *   name - object name
- *   id   - SQLITE_PAGENO_FROM_SPACEID_INDEXID(...)
- *          for tables and indices
- *   sql  - SQL statement that created this object
- */
-static void
-sql_schema_put(InitData *init,
-	       const char *name,
-	       uint32_t spaceid, uint32_t indexid,
-	       const char *sql)
-{
-	int pageno = SQLITE_PAGENO_FROM_SPACEID_AND_INDEXID(spaceid, indexid);
-
-	char *argv[] = {
-		(char *)name,
-		(char *)&pageno,
-		(char *)sql,
-		NULL
-	};
-
-	if (init->rc != SQLITE_OK) return;
-
-	sqlite3InitCallback(init, 3, argv, NULL);
-}
-
 static int
 space_foreach_put_cb(struct space *space, void *udata)
 {
 	if (space->def->opts.sql == NULL)
 		return 0; /* Not SQL space. */
-	sql_schema_put((InitData *) udata, space->def->name, space->def->id, 0,
-		       space->def->opts.sql);
+	sql_init_callback((struct init_data *) udata, space->def->name,
+			  space->def->id, 0, space->def->opts.sql);
 	for (uint32_t i = 0; i < space->index_count; ++i) {
 		struct index_def *def = space_index_def(space, i);
 		if (def->opts.sql != NULL) {
-			sql_schema_put((InitData *) udata, def->name,
-				       def->space_id, def->iid, def->opts.sql);
+			sql_init_callback((struct init_data *) udata, def->name,
+					  def->space_id, def->iid, def->opts.sql);
 		}
 	}
 	return 0;
 }
 
 /* Load database schema from Tarantool. */
-void tarantoolSqlite3LoadSchema(InitData *init)
+void tarantoolSqlite3LoadSchema(struct init_data *init)
 {
-	sql_schema_put(
+	sql_init_callback(
 		init, TARANTOOL_SYS_SCHEMA_NAME,
 		BOX_SCHEMA_ID, 0,
 		"CREATE TABLE \""TARANTOOL_SYS_SCHEMA_NAME
 		"\" (\"key\" TEXT PRIMARY KEY, \"value\")"
 	);
 
-	sql_schema_put(
+	sql_init_callback(
 		init, TARANTOOL_SYS_SPACE_NAME,
 		BOX_SPACE_ID, 0,
 		"CREATE TABLE \""TARANTOOL_SYS_SPACE_NAME
@@ -1245,7 +1200,7 @@ void tarantoolSqlite3LoadSchema(InitData *init)
 		"\"engine\" TEXT, \"field_count\" INT, \"opts\", \"format\")"
 	);
 
-	sql_schema_put(
+	sql_init_callback(
 		init, TARANTOOL_SYS_INDEX_NAME,
 		BOX_INDEX_ID, 0,
 		"CREATE TABLE \""TARANTOOL_SYS_INDEX_NAME"\" "
@@ -1253,38 +1208,41 @@ void tarantoolSqlite3LoadSchema(InitData *init)
 		"\"opts\", \"parts\", PRIMARY KEY (\"id\", \"iid\"))"
 	);
 
-	sql_schema_put(
+	sql_init_callback(
 		init, TARANTOOL_SYS_TRIGGER_NAME,
 		BOX_TRIGGER_ID, 0,
 		"CREATE TABLE \""TARANTOOL_SYS_TRIGGER_NAME"\" ("
 		"\"name\" TEXT PRIMARY KEY, \"space_id\" INT, \"opts\")"
 	);
 
-	sql_schema_put(
+	sql_init_callback(
 		init, TARANTOOL_SYS_TRUNCATE_NAME,
 		BOX_TRUNCATE_ID, 0,
 		"CREATE TABLE \""TARANTOOL_SYS_TRUNCATE_NAME
 		"\" (\"id\" INT PRIMARY KEY, \"count\" INT NOT NULL)"
 	);
 
-	sql_schema_put(init, TARANTOOL_SYS_SEQUENCE_NAME, BOX_SEQUENCE_ID, 0,
-		       "CREATE TABLE \""TARANTOOL_SYS_SEQUENCE_NAME
-		       "\" (\"id\" INT PRIMARY KEY, \"uid\" INT, \"name\" TEXT, \"step\" INT, "
-		       "\"max\" INT, \"min\" INT, \"start\" INT, \"cache\" INT, \"cycle\" INT)");
+	sql_init_callback(init, TARANTOOL_SYS_SEQUENCE_NAME, BOX_SEQUENCE_ID, 0,
+			  "CREATE TABLE \""TARANTOOL_SYS_SEQUENCE_NAME
+			  "\" (\"id\" INT PRIMARY KEY, \"uid\" INT, \"name\" TEXT, \"step\" INT, "
+			  "\"max\" INT, \"min\" INT, \"start\" INT, \"cache\" INT, \"cycle\" INT)");
 
-	sql_schema_put(init, TARANTOOL_SYS_SPACE_SEQUENCE_NAME, BOX_SPACE_SEQUENCE_ID, 0,
-		       "CREATE TABLE \""TARANTOOL_SYS_SPACE_SEQUENCE_NAME
-		       "\" (\"space_id\" INT PRIMARY KEY, \"sequence_id\" INT, \"flag\" INT)");
+	sql_init_callback(init, TARANTOOL_SYS_SPACE_SEQUENCE_NAME,
+			  BOX_SPACE_SEQUENCE_ID, 0,
+			  "CREATE TABLE \""TARANTOOL_SYS_SPACE_SEQUENCE_NAME
+			  "\" (\"space_id\" INT PRIMARY KEY, \"sequence_id\" INT, \"flag\" INT)");
 
-	sql_schema_put(init, TARANTOOL_SYS_SQL_STAT1_NAME, BOX_SQL_STAT1_ID, 0,
-		       "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT1_NAME
+	sql_init_callback(init, TARANTOOL_SYS_SQL_STAT1_NAME,
+			  BOX_SQL_STAT1_ID, 0,
+			  "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT1_NAME
 			       "\"(\"tbl\" text,"
 			       "\"idx\" text,"
 			       "\"stat\" not null,"
 			       "PRIMARY KEY(\"tbl\", \"idx\"))");
 
-	sql_schema_put(init, TARANTOOL_SYS_SQL_STAT4_NAME, BOX_SQL_STAT4_ID, 0,
-		       "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT4_NAME
+	sql_init_callback(init, TARANTOOL_SYS_SQL_STAT4_NAME,
+			  BOX_SQL_STAT4_ID, 0,
+			  "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT4_NAME
 			       "\"(\"tbl\" text,"
 			       "\"idx\" text,"
 			       "\"neq\" text,"
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index fe54e55..8c1c36b 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -60,7 +60,8 @@ reloadTableSchema(Parse * pParse, Table * pTab, const char *zName)
 		return;
 
 	char *zNewName = sqlite3MPrintf(pParse->db, "%s", zName);
-	sqlite3VdbeAddRenameTableOp(v, pTab->tnum, zNewName);
+	sqlite3VdbeAddOp4(v, OP_RenameTable, pTab->def->id, 0, 0, zNewName,
+			  P4_DYNAMIC);
 }
 
 /*
@@ -163,7 +164,7 @@ sqlite3AlterFinishAddColumn(Parse * pParse, Token * pColDef)
 	zTab = &pNew->def->name[16];
 	pCol = &pNew->aCol[pNew->def->field_count - 1];
 	assert(pNew->def != NULL);
-	pDflt = space_column_default_expr(SQLITE_PAGENO_TO_SPACEID(pNew->tnum),
+	pDflt = space_column_default_expr(pNew->def->id,
 					  pNew->def->field_count - 1);
 	pTab = sqlite3HashFind(&db->pSchema->tblHash, zTab);;
 	assert(pTab);
diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index 36648b3..00d96d2 100644
--- a/src/box/sql/analyze.c
+++ b/src/box/sql/analyze.c
@@ -803,7 +803,7 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 	if (v == 0 || NEVER(pTab == 0)) {
 		return;
 	}
-	assert(pTab->tnum != 0);
+	assert(pTab->def->id != 0);
 	if (sqlite3_strlike("\\_%", pTab->def->name, '\\') == 0) {
 		/* Do not gather statistics on system tables */
 		return;
@@ -882,9 +882,8 @@ analyzeOneTable(Parse * pParse,	/* Parser context */
 		pParse->nMem = MAX(pParse->nMem, regPrev + part_count);
 
 		/* Open a read-only cursor on the index being analyzed. */
-		struct space *space =
-			space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
-		int idx_id = SQLITE_PAGENO_TO_INDEXID(pIdx->tnum);
+		struct space *space = space_by_id(pIdx->def->space_id);
+		int idx_id = pIdx->def->iid;
 		assert(space != NULL);
 		sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, idx_id, 0,
 				  (void *) space, P4_SPACEPTR);
@@ -1624,7 +1623,7 @@ const log_est_t default_tuple_est[] = {DEFAULT_TUPLE_LOG_COUNT,
 LogEst
 sql_space_tuple_log_count(struct Table *tab)
 {
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(tab->tnum));
+	struct space *space = space_by_id(tab->def->id);
 	if (space == NULL)
 		return tab->tuple_log_count;
 	struct index *pk = space_index(space, 0);
@@ -1638,11 +1637,10 @@ sql_space_tuple_log_count(struct Table *tab)
 log_est_t
 index_field_tuple_est(struct Index *idx, uint32_t field)
 {
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(idx->tnum));
-	if (space == NULL)
+	struct space *space = space_by_id(idx->pTable->def->id);
+	if (space == NULL || strcmp(idx->def->opts.sql, "fake_autoindex") == 0)
 		return idx->def->opts.stat->tuple_log_est[field];
-	struct index *tnt_idx =
-		space_index(space, SQLITE_PAGENO_TO_INDEXID(idx->tnum));
+	struct index *tnt_idx = space_index(space, idx->def->iid);
 	assert(tnt_idx != NULL);
 	assert(field <= tnt_idx->def->key_def->part_count);
 	if (tnt_idx->def->opts.stat == NULL) {
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index fc6681a..2f29c52 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -278,8 +278,7 @@ sqlite3CommitInternalChanges()
 bool
 table_column_is_in_pk(Table *table, uint32_t column)
 {
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(table->tnum);
-	struct space *space = space_by_id(space_id);
+	struct space *space = space_by_id(table->def->id);
 	assert(space != NULL);
 
 	struct index *primary_idx = index_find(space, 0 /* PK */);
@@ -1604,8 +1603,10 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 	 * schema.
 	 */
 	if (db->init.busy) {
-		p->tnum = db->init.newTnum;
-		p->def->id = SQLITE_PAGENO_TO_SPACEID(p->tnum);
+		p->def->id = db->init.space_id;
+		for(struct Index *idx = p->pIndex; idx != NULL;
+		    idx = idx->pNext)
+			idx->def->space_id = p->def->id;
 	}
 
 	if (!p->def->opts.is_view) {
@@ -2263,15 +2264,9 @@ sqlite3DeferForeignKey(Parse * pParse, int isDeferred)
  * Generate code that will erase and refill index *pIdx.  This is
  * used to initialize a newly created index or to recompute the
  * content of an index in response to a REINDEX command.
- *
- * if memRootPage is not negative, it means that the index is newly
- * created.  The register specified by memRootPage contains the
- * root page number of the index.  If memRootPage is negative, then
- * the index already exists and must be cleared before being refilled and
- * the root page number of the index is taken from pIndex->tnum.
  */
 static void
-sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
+sqlite3RefillIndex(Parse * pParse, Index * pIndex)
 {
 	Table *pTab = pIndex->pTable;	/* The table that is indexed */
 	int iTab = pParse->nTab++;	/* Btree cursor used for pTab */
@@ -2279,7 +2274,6 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
 	int iSorter;		/* Cursor opened by OpenSorter (if in use) */
 	int addr1;		/* Address of top of loop */
 	int addr2;		/* Address to jump to for next iteration */
-	int tnum;		/* Root page of index */
 	int iPartIdxLabel;	/* Jump to this label to skip a row */
 	Vdbe *v;		/* Generate code into this virtual machine */
 	int regRecord;		/* Register holding assembled index record */
@@ -2287,11 +2281,6 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
 	v = sqlite3GetVdbe(pParse);
 	if (v == 0)
 		return;
-	if (memRootPage >= 0) {
-		tnum = memRootPage;
-	} else {
-		tnum = pIndex->tnum;
-	}
 	struct key_def *def = key_def_dup(pIndex->def->key_def);
 	if (def == NULL) {
 		sqlite3OomFault(db);
@@ -2318,13 +2307,11 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, int memRootPage)
 	sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1 + 1);
 	VdbeCoverage(v);
 	sqlite3VdbeJumpHere(v, addr1);
-	if (memRootPage < 0)
-		sqlite3VdbeAddOp2(v, OP_Clear, SQLITE_PAGENO_TO_SPACEID(tnum),
-				  0);
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(tnum));
-	vdbe_emit_open_cursor(pParse, iIdx, SQLITE_PAGENO_TO_INDEXID(tnum),
+	sqlite3VdbeAddOp2(v, OP_Clear, pIndex->pTable->def->id, 0);
+	struct space *space = space_by_id(pIndex->pTable->def->id);
+	vdbe_emit_open_cursor(pParse, iIdx, pIndex->def->iid,
 			      space);
-	sqlite3VdbeChangeP5(v, memRootPage >= 0 ? OPFLAG_P2ISREG : 0);
+	sqlite3VdbeChangeP5(v, 0);
 
 	addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
 	VdbeCoverage(v);
@@ -2722,7 +2709,7 @@ sql_create_index(struct Parse *parse, struct Token *token,
 	 */
 	uint32_t iid = idx_type != SQL_INDEX_TYPE_CONSTRAINT_PK;
 	if (db->init.busy)
-		iid = SQLITE_PAGENO_TO_INDEXID(db->init.newTnum);
+		iid = db->init.index_id;
 
 	if (index_fill_def(parse, index, table, iid, name, strlen(name),
 			   col_list, idx_type, sql_stmt) != 0)
@@ -2852,7 +2839,7 @@ sql_create_index(struct Parse *parse, struct Token *token,
 			goto exit_create_index;
 		}
 		user_session->sql_flags |= SQLITE_InternChanges;
-		index->tnum = db->init.newTnum;
+		index->def->iid = db->init.index_id;
 	}
 
 	/*
@@ -2885,7 +2872,7 @@ sql_create_index(struct Parse *parse, struct Token *token,
 		sqlite3VdbeChangeP5(vdbe, OPFLAG_SEEKEQ);
 
 		assert(start != NULL);
-		space_id = SQLITE_PAGENO_TO_SPACEID(table->tnum);
+		space_id = table->def->id;
 		index_id = getNewIid(parse, space_id, cursor);
 		sqlite3VdbeAddOp1(vdbe, OP_Close, cursor);
 		createIndex(parse, index, space_id, index_id, sql_stmt);
@@ -3583,7 +3570,7 @@ reindexTable(Parse * pParse, Table * pTab, struct coll *coll)
 	for (pIndex = pTab->pIndex; pIndex; pIndex = pIndex->pNext) {
 		if (coll == 0 || collationMatch(coll, pIndex)) {
 			sql_set_multi_write(pParse, false);
-			sqlite3RefillIndex(pParse, pIndex, -1);
+			sqlite3RefillIndex(pParse, pIndex);
 		}
 	}
 }
@@ -3677,7 +3664,7 @@ sqlite3Reindex(Parse * pParse, Token * pName1, Token * pName2)
 	pIndex = sqlite3HashFind(&pTab->idxHash, z);
 	if (pIndex != NULL) {
 		sql_set_multi_write(pParse, false);
-		sqlite3RefillIndex(pParse, pIndex, -1);
+		sqlite3RefillIndex(pParse, pIndex);
 		return;
 	}
 
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index f9d3498..0681177 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -125,7 +125,7 @@ sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
 		table = sql_list_lookup_table(parse, tab_list);
 		if (table == NULL)
 			goto delete_from_cleanup;
-		space_id = SQLITE_PAGENO_TO_SPACEID(table->tnum);
+		space_id = table->def->id;
 		space = space_by_id(space_id);
 		assert(space != NULL);
 		trigger_list = sql_triggers_exist(table, TK_DELETE, NULL, NULL);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 360558a..d408adb 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2474,10 +2474,8 @@ sqlite3FindInIndex(Parse * pParse,	/* Parsing context */
 							  pIdx->def->name),
 							  P4_DYNAMIC);
 					struct space *space =
-						space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
-					uint32_t idx_id =
-						SQLITE_PAGENO_TO_INDEXID(pIdx->
-									 tnum);
+						space_by_id(pIdx->pTable->def->id);
+					uint32_t idx_id = pIdx->def->iid;
 					vdbe_emit_open_cursor(pParse, iTab,
 							      idx_id, space);
 					VdbeComment((v, "%s", pIdx->def->name));
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index 8cacfe7..6dd9130 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -426,9 +426,9 @@ fkLookupParent(Parse * pParse,	/* Parse context */
 			int regTemp = sqlite3GetTempRange(pParse, nCol);
 			int regRec = sqlite3GetTempReg(pParse);
 			struct space *space =
-				space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
-			uint32_t idx_id = SQLITE_PAGENO_TO_INDEXID(pIdx->tnum);
-			vdbe_emit_open_cursor(pParse, iCur, idx_id, space);
+				space_by_id(pIdx->pTable->def->id);
+			vdbe_emit_open_cursor(pParse, iCur, pIdx->def->iid,
+					      space);
 			for (i = 0; i < nCol; i++) {
 				sqlite3VdbeAddOp2(v, OP_Copy,
 						  aiCol[i] + 1 + regData,
@@ -1304,12 +1304,10 @@ fkActionTrigger(struct Parse *pParse, struct Table *pTab, struct FKey *pFKey,
 									     &tToCol,
 									     0));
 				} else if (action == OE_SetDflt) {
-					uint32_t space_id =
-						SQLITE_PAGENO_TO_SPACEID(
-							pFKey->pFrom->tnum);
 					Expr *pDflt =
 						space_column_default_expr(
-							space_id, (uint32_t)iFromCol);
+							pFKey->pFrom->def->id,
+							(uint32_t)iFromCol);
 					if (pDflt) {
 						pNew =
 						    sqlite3ExprDup(db, pDflt,
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 3af9f9a..504701d 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -384,7 +384,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	if (pTab == NULL)
 		goto insert_cleanup;
 
-	space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
+	space_id = pTab->def->id;
 
 	/* Figure out if we have any triggers and if the table being
 	 * inserted into is a view
@@ -742,7 +742,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 				if (i == pTab->iAutoIncPKey) {
 					sqlite3VdbeAddOp2(v,
 							  OP_NextAutoincValue,
-							  pTab->tnum,
+							  SQLITE_PAGENO_FROM_SPACEID_AND_INDEXID(pTab->def->id, 0),
 							  iRegStore);
 					continue;
 				}
@@ -1075,9 +1075,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 			on_error = ON_CONFLICT_ACTION_ABORT;
 
 		struct Expr *dflt = NULL;
-		dflt = space_column_default_expr(
-			SQLITE_PAGENO_TO_SPACEID(pTab->tnum),
-			i);
+		dflt = space_column_default_expr(pTab->def->id, i);
 		if (on_error == ON_CONFLICT_ACTION_REPLACE && dflt == 0)
 			on_error = ON_CONFLICT_ACTION_ABORT;
 
@@ -1124,8 +1122,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 	 * Get server checks.
 	 * Test all CHECK constraints.
 	 */
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
-	ExprList *checks = space_checks_expr_list(space_id);
+	ExprList *checks = space_checks_expr_list(pTab->def->id);
 	if (checks != NULL &&
 	    (user_session->sql_flags & SQLITE_IgnoreChecks) == 0) {
 		pParse->ckBase = regNewData + 1;
@@ -1389,7 +1386,7 @@ sqlite3GenerateConstraintChecks(Parse * pParse,		/* The parser context */
 				     ++i, ++part) {
 					char *p4 = (char *) part->coll;
 					x = part->fieldno;
-					if (pPk->tnum==0)
+					if (pTab->def->id == 0)
 						x = -1;
 					if (i == (pk_part_count - 1)) {
 						addrJump = addrUniqueOk;
@@ -1531,7 +1528,7 @@ sqlite3OpenTableAndIndices(Parse * pParse,	/* Parsing context */
 		*piDataCur = iDataCur;
 	if (piIdxCur)
 		*piIdxCur = iBase;
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(pTab->tnum));
+	struct space *space = space_by_id(pTab->def->id);
 	assert(space != NULL);
 	/* One iteration of this cycle adds OpenRead/OpenWrite which
 	 * opens cursor for current index.
@@ -1579,10 +1576,9 @@ sqlite3OpenTableAndIndices(Parse * pParse,	/* Parsing context */
 				p5 = 0;
 			}
 			if (aToOpen == 0 || aToOpen[i + 1]) {
-				int idx_id =
-					SQLITE_PAGENO_TO_INDEXID(pIdx->tnum);
-				sqlite3VdbeAddOp4(v, op, iIdxCur, idx_id, 0,
-						  (void *) space, P4_SPACEPTR);
+				sqlite3VdbeAddOp4(v, op, iIdxCur, pIdx->def->iid,
+						  0, (void *) space,
+						  P4_SPACEPTR);
 				sqlite3VdbeChangeP5(v, p5);
 				VdbeComment((v, "%s", pIdx->def->name));
 			}
@@ -1781,12 +1777,10 @@ xferOptimization(Parse * pParse,	/* Parser context */
 		}
 		/* Default values for second and subsequent columns need to match. */
 		if (i > 0) {
-			uint32_t src_space_id =
-				SQLITE_PAGENO_TO_SPACEID(pSrc->tnum);
+			uint32_t src_space_id = pSrc->def->id;
 			struct space *src_space =
 				space_cache_find(src_space_id);
-			uint32_t dest_space_id =
-				SQLITE_PAGENO_TO_SPACEID(pDest->tnum);
+			uint32_t dest_space_id = pDest->def->id;
 			struct space *dest_space =
 				space_cache_find(dest_space_id);
 			assert(src_space != NULL && dest_space != NULL);
@@ -1814,10 +1808,8 @@ xferOptimization(Parse * pParse,	/* Parser context */
 			return 0;
 	}
 	/* Get server checks. */
-	ExprList *pCheck_src = space_checks_expr_list(
-		SQLITE_PAGENO_TO_SPACEID(pSrc->tnum));
-	ExprList *pCheck_dest = space_checks_expr_list(
-		SQLITE_PAGENO_TO_SPACEID(pDest->tnum));
+	ExprList *pCheck_src = space_checks_expr_list(pSrc->def->id);
+	ExprList *pCheck_dest = space_checks_expr_list(pDest->def->id);
 	if (pCheck_dest != NULL &&
 	    sqlite3ExprListCompare(pCheck_src, pCheck_dest, -1) != 0) {
 		/* Tables have different CHECK constraints.  Ticket #2252 */
@@ -1885,15 +1877,14 @@ xferOptimization(Parse * pParse,	/* Parser context */
 		}
 		assert(pSrcIdx);
 		struct space *src_space =
-			space_by_id(SQLITE_PAGENO_TO_SPACEID(pSrcIdx->tnum));
+			space_by_id(pSrc->def->id);
 		vdbe_emit_open_cursor(pParse, iSrc,
-				      SQLITE_PAGENO_TO_INDEXID(pSrcIdx->tnum),
+				      pSrcIdx->def->iid,
 				      src_space);
 		VdbeComment((v, "%s", pSrcIdx->def->name));
-		struct space *dest_space =
-			space_by_id(SQLITE_PAGENO_TO_SPACEID(pDestIdx->tnum));
+		struct space *dest_space = space_by_id(pDest->def->id);
 		vdbe_emit_open_cursor(pParse, iDest,
-				      SQLITE_PAGENO_TO_INDEXID(pDestIdx->tnum),
+				      pDestIdx->def->iid,
 				      dest_space);
 		VdbeComment((v, "%s", pDestIdx->def->name));
 		addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index 85bc7e9..ded3b5b 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -2388,33 +2388,6 @@ sqlite3_test_control(int op, ...)
 				rc = SQLITE_ERROR;
 			break;
 		}
-
-		/*  sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
-		 *
-		 * This test control is used to create imposter tables.  "db" is a pointer
-		 * to the database connection.  dbName is the database name (ex: "main" or
-		 * "temp") which will receive the imposter.  "onOff" turns imposter mode on
-		 * or off.  "tnum" is the root page of the b-tree to which the imposter
-		 * table should connect.
-		 *
-		 * Enable imposter mode only when the schema has already been parsed.  Then
-		 * run a single CREATE TABLE statement to construct the imposter table in
-		 * the parsed schema.  Then turn imposter mode back off again.
-		 *
-		 * If onOff==0 and tnum>0 then reset the schema for all databases, causing
-		 * the schema to be reparsed the next time it is needed.  This has the
-		 * effect of erasing all imposter tables.
-		 */
-	case SQLITE_TESTCTRL_IMPOSTER:{
-			sqlite3 *db = va_arg(ap, sqlite3 *);
-			db->init.busy = db->init.imposterTable =
-			    va_arg(ap, int);
-			db->init.newTnum = va_arg(ap, int);
-			if (db->init.busy == 0 && db->init.newTnum > 0) {
-				sqlite3ResetAllSchemasOfConnection(db);
-			}
-			break;
-		}
 	}
 	va_end(ap);
 #endif				/* SQLITE_UNTESTABLE */
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index cabe22b..0c838fa 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -432,9 +432,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			for (i = sqliteHashFirst(&db->pSchema->tblHash); i;
 			     i = sqliteHashNext(i)) {
 				Table *pTab = sqliteHashData(i);
-				uint32_t space_id =
-					SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
-				struct space *space = space_by_id(space_id);
+				struct space *space;
+				space = space_by_id(pTab->def->id);
 				assert(space != NULL);
 				struct index *pk = space_index(space, 0);
 				size_t avg_tuple_size_pk =
@@ -447,10 +446,8 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
 				for (pIdx = pTab->pIndex; pIdx;
 				     pIdx = pIdx->pNext) {
-					uint32_t iid =
-						SQLITE_PAGENO_TO_INDEXID(pIdx->tnum);
 					struct index *idx =
-						space_index(space, iid);
+						space_index(space, pIdx->def->iid);
 					assert(idx != NULL);
 					size_t avg_tuple_size_idx =
 						sql_index_tuple_size(space, idx);
@@ -689,12 +686,9 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 					struct space *space =
 						space_cache_find(pIdx->pTable->
 								 def->id);
-					int idx_id =
-						SQLITE_PAGENO_TO_INDEXID(pIdx->
-									 tnum);
 					assert(space != NULL);
 					sqlite3VdbeAddOp4(v, OP_OpenRead, i,
-							  idx_id, 0,
+							  pIdx->def->iid, 0,
 							  (void *) space,
 							  P4_SPACEPTR);
 
diff --git a/src/box/sql/prepare.c b/src/box/sql/prepare.c
index 629f68e..14239c4 100644
--- a/src/box/sql/prepare.c
+++ b/src/box/sql/prepare.c
@@ -44,12 +44,12 @@
  * that the database is corrupt.
  */
 static void
-corruptSchema(InitData * pData,	/* Initialization context */
+corruptSchema(struct init_data *data,	/* Initialization context */
 	      const char *zObj,	/* Object being parsed at the point of error */
 	      const char *zExtra	/* Error information */
     )
 {
-	sqlite3 *db = pData->db;
+	sqlite3 *db = data->db;
 	if (!db->mallocFailed) {
 		char *z;
 		if (zObj == 0)
@@ -57,46 +57,30 @@ corruptSchema(InitData * pData,	/* Initialization context */
 		z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
 		if (zExtra)
 			z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
-		sqlite3DbFree(db, *pData->pzErrMsg);
-		*pData->pzErrMsg = z;
+		sqlite3DbFree(db, *data->pzErrMsg);
+		*data->pzErrMsg = z;
 	}
-	pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
+	data->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
 }
 
 /* Necessary for appropriate value return in InitCallback.
  * Otherwise it will return uint32_t instead of 64 bit pointer.
  */
 struct space *space_by_id(uint32_t id);
-/*
- * This is the callback routine for the code that initializes the
- * database.  See sqlite3Init() below for additional information.
- * This routine is also called from the OP_ParseSchema opcode of the VDBE.
- *
- * Each callback contains the following information:
- *
- *     argv[0] = name of thing being created
- *     argv[1] = root page number address.
- *     argv[2] = SQL text for the CREATE statement.
- *
- */
+
 int
-sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed)
+sql_init_callback(struct init_data *init, const char *name,
+		  uint32_t space_id, uint32_t index_id, const char *sql)
 {
-	InitData *pData = (InitData *) pInit;
-	sqlite3 *db = pData->db;
-	assert(argc == 3);
-	UNUSED_PARAMETER2(NotUsed, argc);
+	sqlite3 *db = init->db;
 	if (db->mallocFailed) {
-		corruptSchema(pData, argv[0], 0);
+		corruptSchema(init, name, 0);
 		return 1;
 	}
 
-	if (argv == 0)
-		return 0;	/* Might happen if EMPTY_RESULT_CALLBACKS are on */
-	if (argv[1] == 0) {
-		corruptSchema(pData, argv[0], 0);
-	} else if ((strlen(argv[2]) > 7) &&
-		   sqlite3_strnicmp(argv[2], "create ", 7) == 0) {
+	assert(space_id > 0);
+	if ((strlen(sql) > 7) &&
+	    sqlite3_strnicmp(sql, "create ", 7) == 0) {
 		/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
 		 * But because db->init.busy is set to 1, no VDBE code is generated
 		 * or executed.  All the parser does is build the internal data
@@ -107,25 +91,24 @@ sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed)
 		TESTONLY(int rcp);	/* Return code from sqlite3_prepare() */
 
 		assert(db->init.busy);
-		db->init.newTnum = *((int *)argv[1]);
+		db->init.space_id = space_id;
+		db->init.index_id = index_id;
 		db->init.orphanTrigger = 0;
-		TESTONLY(rcp =) sqlite3_prepare(db, argv[2],
-						strlen(argv[2]) + 1, &pStmt, 0);
+		TESTONLY(rcp =) sqlite3_prepare(db, sql,
+						strlen(sql) + 1, &pStmt, 0);
 		rc = db->errCode;
 		assert((rc & 0xFF) == (rcp & 0xFF));
 		if (SQLITE_OK != rc) {
-			pData->rc = rc;
-			if (rc == SQLITE_NOMEM) {
+			init->rc = rc;
+			if (rc == SQLITE_NOMEM)
 				sqlite3OomFault(db);
-			} else if (rc != SQLITE_INTERRUPT
-				   && (rc & 0xFF) != SQLITE_LOCKED) {
-				corruptSchema(pData, argv[0],
-					      sqlite3_errmsg(db));
-			}
+			else if (rc != SQLITE_INTERRUPT &&
+				 (rc & 0xFF) != SQLITE_LOCKED)
+				corruptSchema(init, name, sqlite3_errmsg(db));
 		}
 		sqlite3_finalize(pStmt);
-	} else if (argv[0] == 0 || (argv[2] != 0 && argv[2][0] != 0)) {
-		corruptSchema(pData, argv[0], 0);
+	} else if (name == NULL || (sql != NULL && sql[0] != 0)) {
+		corruptSchema(init, name, 0);
 	} else {
 		/* If the SQL column is blank it means this is an index that
 		 * was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -134,12 +117,10 @@ sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed)
 		 * to do here is record the root page number for that index.
 		 */
 		Index *pIndex;
-		long pageNo = *((long *)argv[1]);
-		int iSpace = (int)SQLITE_PAGENO_TO_SPACEID(pageNo);
-		struct space *pSpace = space_by_id(iSpace);
-		const char *zSpace = space_name(pSpace);
-		pIndex = sqlite3LocateIndex(db, argv[0], zSpace);
-		if (pIndex == 0) {
+		struct space *space = space_by_id(space_id);
+		const char *zSpace = space_name(space);
+		pIndex = sqlite3LocateIndex(db, name, zSpace);
+		if (pIndex == NULL) {
 			/* This can occur if there exists an index on a TEMP table which
 			 * has the same name as another index on a permanent index.  Since
 			 * the permanent table is hidden by the TEMP table, we can also
@@ -147,7 +128,7 @@ sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed)
 			 */
 			/* Do Nothing */ ;
 		}
-		pIndex->tnum = pageNo;
+		pIndex->def->iid = index_id;
 	}
 	return 0;
 }
@@ -161,18 +142,18 @@ extern int
 sqlite3InitDatabase(sqlite3 * db)
 {
 	int rc;
-	InitData initData;
+	struct init_data init;
 
 	assert(db->pSchema != NULL);
 
-	memset(&initData, 0, sizeof(InitData));
-	initData.db = db;
+	memset(&init, 0, sizeof(init));
+	init.db = db;
 
 	/* Load schema from Tarantool - into the primary db only. */
-	tarantoolSqlite3LoadSchema(&initData);
+	tarantoolSqlite3LoadSchema(&init);
 
-	if (initData.rc) {
-		rc = initData.rc;
+	if (init.rc) {
+		rc = init.rc;
 		goto error_out;
 	}
 
@@ -185,7 +166,7 @@ sqlite3InitDatabase(sqlite3 * db)
 	 */
 	assert(db->init.busy);
 	{
-		rc = initData.rc;
+		rc = init.rc;
 		if (rc == SQLITE_OK)
 			sql_analysis_load(db);
 	}
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index e548021..cf25326 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -4364,8 +4364,7 @@ is_simple_count(struct Select *select, struct AggInfo *agg_info)
 	    select->pSrc->nSrc != 1 || select->pSrc->a[0].pSelect != NULL) {
 		return NULL;
 	}
-	uint32_t space_id =
-		SQLITE_PAGENO_TO_SPACEID(select->pSrc->a[0].pTab->tnum);
+	uint32_t space_id = select->pSrc->a[0].pTab->def->id;
 	struct space *space = space_by_id(space_id);
 	assert(space != NULL && !space->def->opts.is_view);
 	struct Expr *expr = select->pEList->a[0].pExpr;
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index f122b3f..b989331 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -844,8 +844,7 @@ sqlite3_vfs_find(const char *zVfsName);
 #define SQLITE_TESTCTRL_BYTEORDER               22
 #define SQLITE_TESTCTRL_ISINIT                  23
 #define SQLITE_TESTCTRL_SORTER_MMAP             24
-#define SQLITE_TESTCTRL_IMPOSTER                25
-#define SQLITE_TESTCTRL_LAST                    25
+#define SQLITE_TESTCTRL_LAST                    24
 
 int
 sqlite3_status64(int op, sqlite3_int64 * pCurrent,
@@ -1608,7 +1607,8 @@ struct sqlite3 {
 	int aLimit[SQLITE_N_LIMIT];	/* Limits */
 	int nMaxSorterMmap;	/* Maximum size of regions mapped by sorter */
 	struct sqlite3InitInfo {	/* Information used during initialization */
-		int newTnum;	/* Rootpage of table being initialized */
+		uint32_t space_id;
+		uint32_t index_id;
 		u8 busy;	/* TRUE if currently initializing */
 		u8 orphanTrigger;	/* Last statement is orphaned TEMP trigger */
 		u8 imposterTable;	/* Building an imposter table */
@@ -1916,7 +1916,6 @@ struct Table {
 	char *zColAff;		/* String defining the affinity of each column */
 	/*   ... also used as column name list in a VIEW */
 	Hash idxHash;		/* All (named) indices indexed by name */
-	int tnum;		/* Root BTree page for this table */
 	u32 nTabRef;		/* Number of pointers to this Table */
 	i16 iAutoIncPKey;	/* If PK is marked INTEGER PRIMARY KEY AUTOINCREMENT, store
 				   column number here, -1 otherwise Tarantool specifics */
@@ -2092,10 +2091,7 @@ enum sql_index_type {
  * While parsing a CREATE TABLE or CREATE INDEX statement in order to
  * generate VDBE code (as opposed to reading from Tarantool's _space
  * space as part of parsing an existing database schema), transient instances
- * of this structure may be created. In this case the Index.tnum variable is
- * used to store the address of a VDBE instruction, not a database page
- * number (it cannot - the database page is not allocated until the VDBE
- * program is executed). See convertToWithoutRowidTable() for details.
+ * of this structure may be created.
  */
 struct Index {
 	/** The SQL table being indexed. */
@@ -2108,8 +2104,6 @@ struct Index {
 	Schema *pSchema;
 	/** WHERE clause for partial indices. */
 	Expr *pPartIdxWhere;
-	/** DB Page containing root of this index. */
-	int tnum;
 	/**
 	 * Conflict resolution algorithm to employ whenever an
 	 * attempt is made to insert a non-unique element in
@@ -3131,15 +3125,18 @@ struct StrAccum {
 
 #define isMalloced(X)  (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
 
-/*
+/**
  * A pointer to this structure is used to communicate information
- * from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
- */
-typedef struct {
-	sqlite3 *db;		/* The database being initialized */
-	char **pzErrMsg;	/* Error message stored here */
-	int rc;			/* Result code stored here */
-} InitData;
+ * from sqlite3Init and OP_ParseSchema into the sql_init_callback.
+ */
+struct init_data {
+	/* The database being initialized */
+	sqlite3 *db;
+	/* Error message stored here */
+	char **pzErrMsg;
+	/* Result code stored here */
+	int rc;
+};
 
 /*
  * Structure containing global configuration data for the SQLite library.
@@ -3478,7 +3475,25 @@ void sqlite3ExprListSetName(Parse *, ExprList *, Token *, int);
 void sqlite3ExprListSetSpan(Parse *, ExprList *, ExprSpan *);
 u32 sqlite3ExprListFlags(const ExprList *);
 int sqlite3Init(sqlite3 *);
-int sqlite3InitCallback(void *, int, char **, char **);
+
+/**
+ * This is the callback routine for the code that initializes the
+ * database.  See sqlite3Init() below for additional information.
+ * This routine is also called from the OP_ParseSchema2 opcode of
+ * the VDBE.
+ *
+ * @param init Initialization context.
+ * @param name Name of thing being created.
+ * @param space_id Space identifier.
+ * @param index_id Index identifier.
+ * @param sql Text of SQL query.
+ *
+ * @retval 0 on success, 1 otherwise.
+ */
+int
+sql_init_callback(struct init_data *init, const char *name,
+		  uint32_t space_id, uint32_t index_id, const char *sql);
+
 void sqlite3Pragma(Parse *, Token *, Token *, Token *, int);
 void sqlite3ResetAllSchemasOfConnection(sqlite3 *);
 void sqlite3CommitInternalChanges();
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index f043a60..b34e671 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -44,7 +44,7 @@
   ((pgno) & 1023)
 
 /* Load database schema from Tarantool. */
-void tarantoolSqlite3LoadSchema(InitData * init);
+void tarantoolSqlite3LoadSchema(struct init_data * init);
 
 /* Misc */
 const char *tarantoolErrorMessage();
@@ -82,10 +82,24 @@ int
 sql_delete_by_key(struct space *space, char *key, uint32_t key_size);
 int tarantoolSqlite3ClearTable(struct space *space);
 
-/* Rename table pTab with zNewName by inserting new tuple to _space.
- * SQL statement, which creates table with new name is saved in pzSqlStmt.
+/**
+ * Rename the table in _space. Update tuple with corresponding id
+ * with new name and statement fields and insert back. If sql_stmt
+ * is NULL, then return from function after getting length of new
+ * statement: it is the way how to dynamically allocate memory for
+ * new statement in VDBE. So basically this function should be
+ * called twice: firstly to get length of CREATE TABLE statement,
+ * and secondly to make routine of replacing tuple and filling out
+ * param sql_stmt with new CREATE TABLE statement.
+ *
+ * @param space_id Table's space identifier.
+ * @param new_name new name of table
+ * @param[out] sql_stmt CREATE TABLE statement for new name table, can be NULL.
+ *
+ * @retval SQLITE_OK on success, SQLITE_TARANTOOL_ERROR otherwise.
  */
-int tarantoolSqlite3RenameTable(int iTab, const char *zNewName, char **zSqlStmt);
+int
+sql_rename_table(uint32_t space_id, const char *new_name, char **sql_stmt);
 
 /* Alter trigger statement after rename table. */
 int tarantoolSqlite3RenameTrigger(const char *zTriggerName,
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 195638e..d07bb00 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4615,19 +4615,16 @@ case OP_ResetSorter: {
  *  <name, pageno (which is hash(spaceId, indexId)), sql>
  */
 case OP_ParseSchema2: {
-	InitData initData;
+	struct init_data init;
 	Mem *pRec, *pRecEnd;
-	char *argv[4] = {NULL, NULL, NULL, NULL};
-
-
 	assert(db->pSchema != NULL);
 
-	initData.db = db;
-	initData.pzErrMsg = &p->zErrMsg;
+	init.db = db;
+	init.pzErrMsg = &p->zErrMsg;
 
 	assert(db->init.busy==0);
 	db->init.busy = 1;
-	initData.rc = SQLITE_OK;
+	init.rc = SQLITE_OK;
 	assert(!db->mallocFailed);
 
 	pRec = &aMem[pOp->p1];
@@ -4641,16 +4638,12 @@ case OP_ParseSchema2: {
 	 *
 	 * Uppdate the schema.
 	 */
-	for( ; pRecEnd-pRec>=4 && initData.rc==SQLITE_OK; pRec+=4) {
-		argv[0] = pRec[0].z;
-		int pageNo = SQLITE_PAGENO_FROM_SPACEID_AND_INDEXID(pRec[1].u.i,
-								    pRec[2].u.i);
-		argv[1] = (char *)&pageNo;
-		argv[2] = pRec[3].z;
-		sqlite3InitCallback(&initData, 3, argv, NULL);
+	for(; pRecEnd - pRec >= 4 && init.rc == SQLITE_OK; pRec += 4) {
+		sql_init_callback(&init, pRec[0].z, pRec[1].u.i, pRec[2].u.i,
+				  pRec[3].z);
 	}
 
-	rc = initData.rc;
+	rc = init.rc;
 	db->init.busy = 0;
 
 	if (rc) {
@@ -4664,7 +4657,7 @@ case OP_ParseSchema2: {
 }
 
 /* Opcode: RenameTable P1 * * P4 *
- * Synopsis: P1 = root, P4 = name
+ * Synopsis: P1 = space_id, P4 = name
  *
  * Rename table P1 with name from P4.
  * Invoke tarantoolSqlite3RenameTable, which updates tuple with
@@ -4676,18 +4669,16 @@ case OP_ParseSchema2: {
  *
  */
 case OP_RenameTable: {
-	unsigned space_id;
+	uint32_t space_id;
 	struct space *space;
 	const char *zOldTableName;
 	const char *zNewTableName;
 	Table *pTab;
 	FKey *pFKey;
-	int iRootPage;
-	InitData initData;
-	char *argv[4] = {NULL, NULL, NULL, NULL};
+	struct init_data init;
 	char *zSqlStmt;
 
-	space_id = SQLITE_PAGENO_TO_SPACEID(pOp->p1);
+	space_id = pOp->p1;
 	space = space_by_id(space_id);
 	assert(space);
 	/* Rename space op doesn't change triggers. */
@@ -4696,19 +4687,17 @@ case OP_RenameTable: {
 	assert(zOldTableName);
 	pTab = sqlite3HashFind(&db->pSchema->tblHash, zOldTableName);
 	assert(pTab);
-	iRootPage = pTab->tnum;
 	zNewTableName = pOp->p4.z;
 	zOldTableName = sqlite3DbStrNDup(db, zOldTableName,
 					 sqlite3Strlen30(zOldTableName));
-	rc = tarantoolSqlite3RenameTable(pTab->tnum, zNewTableName,
-					 &zSqlStmt);
+	rc = sql_rename_table(space_id, zNewTableName, &zSqlStmt);
 	if (rc) goto abort_due_to_error;
 
 	/* If it is parent table, all children statements should be updated. */
 	for (pFKey = sqlite3FkReferences(pTab); pFKey; pFKey = pFKey->pNextTo) {
-		assert(pFKey->zTo);
-		assert(pFKey->pFrom);
-		rc = tarantoolSqlite3RenameParentTable(pFKey->pFrom->tnum,
+		assert(pFKey->zTo != NULL);
+		assert(pFKey->pFrom != NULL);
+		rc = tarantoolSqlite3RenameParentTable(pFKey->pFrom->def->id,
 						       pFKey->zTo,
 						       zNewTableName);
 		if (rc) goto abort_due_to_error;
@@ -4720,17 +4709,14 @@ case OP_RenameTable: {
 
 	sqlite3UnlinkAndDeleteTable(db, pTab->def->name);
 
-	initData.db = db;
-	initData.pzErrMsg = &p->zErrMsg;
+	init.db = db;
+	init.pzErrMsg = &p->zErrMsg;
 	assert(db->init.busy == 0);
 	db->init.busy = 1;
-	initData.rc = SQLITE_OK;
-	argv[0] = (char*) zNewTableName;
-	argv[1] = (char*) &iRootPage;
-	argv[2] = zSqlStmt;
-	sqlite3InitCallback(&initData, 3, argv, NULL);
+	init.rc = SQLITE_OK;
+	sql_init_callback(&init, zNewTableName, space_id, 0, zSqlStmt);
 	db->init.busy = 0;
-	rc = initData.rc;
+	rc = init.rc;
 	if (rc) {
 		sqlite3CommitInternalChanges();
 		goto abort_due_to_error;
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 03ae44e..cfcc262 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -234,7 +234,6 @@ void sqlite3VdbeVerifyNoResultRow(Vdbe * p);
 VdbeOp *sqlite3VdbeAddOpList(Vdbe *, int nOp, VdbeOpList const *aOp,
 			     int iLineno);
 void sqlite3VdbeAddParseSchema2Op(Vdbe * p, int, int);
-void sqlite3VdbeAddRenameTableOp(Vdbe * p, int, char *);
 void sqlite3VdbeChangeOpcode(Vdbe *, u32 addr, u8);
 void sqlite3VdbeChangeP1(Vdbe *, u32 addr, int P1);
 void sqlite3VdbeChangeP2(Vdbe *, u32 addr, int P2);
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index c96157a..c71e0fe 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -410,12 +410,6 @@ sqlite3VdbeAddParseSchema2Op(Vdbe * p, int iRec, int n)
 	sqlite3VdbeAddOp3(p, OP_ParseSchema2, iRec, n, 0);
 }
 
-void
-sqlite3VdbeAddRenameTableOp(Vdbe * p, int iTab, char* zNewName)
-{
-	sqlite3VdbeAddOp4(p, OP_RenameTable, iTab, 0, 0, zNewName, P4_DYNAMIC);
-}
-
 /*
  * Add an opcode that includes the p4 value as an integer.
  */
@@ -4001,8 +3995,7 @@ sqlite3VdbeRecordUnpackMsgpack(struct key_def *key_def,	/* Information about the
 enum on_conflict_action
 table_column_nullable_action(struct Table *tab, uint32_t column)
 {
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(tab->tnum);
-	struct space *space = space_cache_find(space_id);
+	struct space *space = space_cache_find(tab->def->id);
 
 	assert(space != NULL);
 
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index c115c4a..5d59837 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -373,11 +373,10 @@ whereScanInit(WhereScan * pScan,	/* The WhereScan object being initialized */
 	if (pIdx != NULL) {
 		int j = iColumn;
 		/*
-		 * pIdx->def->opts.sql == "fake_autoindex" means that
+		 * pIdx->def->iid == UINT32_MAX means that
 		 * pIdx is a fake integer primary key index.
 		 */
-		if (pIdx->def->opts.sql != NULL &&
-		    strcmp(pIdx->def->opts.sql, "fake_autoindex") != 0) {
+		if (pIdx->def->iid != UINT32_MAX) {
 			iColumn = pIdx->def->key_def->parts[iColumn].fieldno;
 			pScan->idxaff =
 				pIdx->pTable->def->fields[iColumn].affinity;
@@ -938,10 +937,9 @@ whereKeyStats(Parse * pParse,	/* Database connection */
 	      int roundUp,	/* Round up if true.  Round down if false */
 	      tRowcnt * aStat)	/* OUT: stats written here */
 {
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pIdx->tnum);
-	struct space *space = space_by_id(space_id);
+	struct space *space = space_by_id(pIdx->pTable->def->id);
 	assert(space != NULL);
-	uint32_t iid = SQLITE_PAGENO_TO_INDEXID(pIdx->tnum);
+	uint32_t iid = pIdx->def->iid;
 	struct index *idx = space_index(space, iid);
 	assert(idx != NULL && idx->def->opts.stat != NULL);
 	struct index_sample *samples = idx->def->opts.stat->samples;
@@ -1217,10 +1215,9 @@ whereRangeSkipScanEst(Parse * pParse,		/* Parsing & code generating context */
 		      int *pbDone)		/* Set to true if at least one expr. value extracted */
 {
 	Index *p = pLoop->pIndex;
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(p->tnum));
+	struct space *space = space_by_id(p->pTable->def->id);
 	assert(space != NULL);
-	struct index *index = space_index(space,
-					  SQLITE_PAGENO_TO_INDEXID(p->tnum));
+	struct index *index = space_index(space, p->def->iid);
 	assert(index != NULL && index->def->opts.stat != NULL);
 	int nEq = pLoop->nEq;
 	sqlite3 *db = pParse->db;
@@ -1348,11 +1345,10 @@ whereRangeScanEst(Parse * pParse,	/* Parsing & code generating context */
 
 	Index *p = pLoop->pIndex;
 	int nEq = pLoop->nEq;
-	uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(p->tnum);
+	uint32_t space_id = p->pTable->def->id;
 	struct space *space = space_by_id(space_id);
 	assert(space != NULL);
-	uint32_t iid = SQLITE_PAGENO_TO_INDEXID(p->tnum);
-	struct index *idx = space_index(space, iid);
+	struct index *idx = space_index(space, p->def->iid);
 	assert(idx != NULL);
 	struct index_stat *stat = idx->def->opts.stat;
 	/*
@@ -1406,14 +1402,11 @@ whereRangeScanEst(Parse * pParse,	/* Parsing & code generating context */
 				 * are in range.
 				 */
 				iLower = 0;
-				uint32_t space_id =
-					SQLITE_PAGENO_TO_SPACEID(p->tnum);
+				uint32_t space_id = p->def->space_id;
 				struct space *space = space_by_id(space_id);
 				assert(space != NULL);
-				uint32_t iid =
-					SQLITE_PAGENO_TO_INDEXID(p->tnum);
 				struct index *idx =
-					space_index(space, iid);
+					space_index(space, p->def->iid);
 				assert(idx != NULL);
 				iUpper = index_size(idx);
 			} else {
@@ -2178,8 +2171,8 @@ whereLoopInsert(WhereLoopBuilder * pBuilder, WhereLoop * pTemplate)
 	}
 	rc = whereLoopXfer(db, p, pTemplate);
 	Index *pIndex = p->pIndex;
-	if (pIndex && pIndex->tnum == 0)
-		p->pIndex = 0;
+	if (pIndex != NULL && pIndex->pTable->def->opts.is_view)
+		p->pIndex = NULL;
 	return rc;
 }
 
@@ -2347,8 +2340,8 @@ whereRangeVectorLen(Parse * pParse,	/* Parsing context */
  * terms only. If it is modified, this value is restored before this
  * function returns.
  *
- * If pProbe->tnum==0, that means pIndex is a fake index used for the
- * INTEGER PRIMARY KEY.
+ * If pProbe->def->space_id==0, that means pIndex is a fake index
+ * used for the INTEGER PRIMARY KEY.
  */
 static int
 whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,	/* The WhereLoop factory */
@@ -2391,12 +2384,11 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,	/* The WhereLoop factory */
 		opMask =
 		    WO_EQ | WO_IN | WO_GT | WO_GE | WO_LT | WO_LE | WO_ISNULL;
 	}
-	struct space *space =
-		space_by_id(SQLITE_PAGENO_TO_SPACEID(pProbe->tnum));
+	struct space *space = space_by_id(pProbe->def->space_id);
 	struct index *idx = NULL;
 	struct index_stat *stat = NULL;
-	if (space != NULL) {
-		idx = space_index(space, SQLITE_PAGENO_TO_INDEXID(pProbe->tnum));
+	if (space != NULL && pProbe->def->iid != UINT32_MAX) {
+		idx = space_index(space, pProbe->def->iid);
 		assert(idx != NULL);
 		stat = idx->def->opts.stat;
 	}
@@ -2514,7 +2506,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,	/* The WhereLoop factory */
 				bool index_is_unique_not_null =
 					pProbe->def->key_def->is_nullable &&
 					pProbe->def->opts.is_unique;
-				if (pProbe->tnum != 0 &&
+				if (pProbe->def->space_id != 0 &&
 				    !index_is_unique_not_null) {
 					pNew->wsFlags |= WHERE_UNQ_WANTED;
 				} else {
@@ -2577,7 +2569,7 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,	/* The WhereLoop factory */
 			assert(eOp & (WO_ISNULL | WO_EQ | WO_IN));
 
 			assert(pNew->nOut == saved_nOut);
-			if (pTerm->truthProb <= 0 && pProbe->tnum != 0 ) {
+			if (pTerm->truthProb <= 0 && !pProbe->pTable->def->opts.is_view) {
 				assert((eOp & WO_IN) || nIn == 0);
 				testcase(eOp & WO_IN);
 				pNew->nOut += pTerm->truthProb;
@@ -2639,11 +2631,10 @@ whereLoopAddBtreeIndex(WhereLoopBuilder * pBuilder,	/* The WhereLoop factory */
 		 * visiting the rows in the main table.
 		 */
 		struct space *space =
-			space_by_id(SQLITE_PAGENO_TO_SPACEID(pProbe->tnum));
+			space_by_id(pProbe->pTable->def->id);
 		assert(space != NULL);
 		struct index *idx =
-			space_index(space,
-				    SQLITE_PAGENO_TO_INDEXID(pProbe->tnum));
+			space_index(space, pProbe->def->iid);
 		assert(idx != NULL);
 		/*
 		 * FIXME: currently, the procedure below makes no
@@ -2750,11 +2741,10 @@ static bool
 index_is_unordered(struct Index *idx)
 {
 	assert(idx != NULL);
-	struct space *space = space_by_id(SQLITE_PAGENO_TO_SPACEID(idx->tnum));
+	struct space *space = space_by_id(idx->pTable->def->id);
 	if (space == NULL)
 		return false;
-	uint32_t iid = SQLITE_PAGENO_TO_INDEXID(idx->tnum);
-	struct index *tnt_idx = space_index(space, iid);
+	struct index *tnt_idx = space_index(space, idx->def->iid);
 	if (tnt_idx == NULL)
 		return false;
 	if (tnt_idx->def->opts.stat != NULL)
@@ -2920,6 +2910,8 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,	/* WHERE clause information */
 					sizeof("fake_autoindex") - 1,
 					TREE, &opts, key_def, NULL);
 		key_def_delete(key_def);
+		/* Special marker for  non-existent index. */
+		fake_index.def->iid = UINT32_MAX;
 
 		if (fake_index.def == NULL) {
 			pWInfo->pParse->nErr++;
@@ -3026,7 +3018,7 @@ whereLoopAddBtree(WhereLoopBuilder * pBuilder,	/* WHERE clause information */
 		/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
 		assert((pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED) == 0
 		       || b == 0);
-		if (pProbe->tnum <= 0) {
+		if (pProbe->def->iid == UINT32_MAX) {
 			/* Integer primary key index */
 			pNew->wsFlags = WHERE_IPK;
 
@@ -4778,15 +4770,12 @@ sqlite3WhereBegin(Parse * pParse,	/* The parser context */
 			if (op) {
 				if (pIx != NULL) {
 					uint32_t space_id =
-						SQLITE_PAGENO_TO_SPACEID(pIx->
-									 tnum);
+						pIx->pTable->def->id;
 					struct space *space =
 						space_by_id(space_id);
-					uint32_t idx_id =
-						SQLITE_PAGENO_TO_INDEXID(pIx->
-									 tnum);
 					vdbe_emit_open_cursor(pParse, iIndexCur,
-							      idx_id, space);
+							      pIx->def->iid,
+							      space);
 				} else {
 					vdbe_emit_open_cursor(pParse, iIndexCur,
 							      idx_def->iid,
-- 
2.16.2

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-07-20 18:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-20 11:37 [tarantool-patches] [PATCH] sql: get rid off tnum field of struct Table Kirill Yukhin
2018-07-20 14:07 ` [tarantool-patches] " n.pettik
2018-07-20 14:32   ` Kirill Yukhin
2018-07-20 16:12     ` n.pettik
2018-07-20 16:53 ` Kirill Yukhin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox