[tarantool-patches] Re: [PATCH] sql: get rid off tnum field of struct Table

  • From: Kirill Yukhin <kyukhin@xxxxxxxxxxxxx>
  • To: "n.pettik" <korablev@xxxxxxxxxxxxx>
  • Date: Fri, 20 Jul 2018 17:32:48 +0300

Hello Nikita,
Thanks for review. Answers inlined.
Updated patch in the bottom.

On 20 июл 17:07, n.pettik wrote:


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),

It looks disgusting.. Lets also refactor OP_NextAutoincValue so that
it accepts raw space_id. After that, remove these SQLITE_PAGENO
macroses at all.
All macros removed.

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); 
Squash two lines into one:
struct space *space = space_by_id(pTab->def->id);
Done.

@@ -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;
    }

-/*
+/**
 * 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 */

Comments inside struct definition should look like:
/** … */
And put dot at the end of sentences.
Done.

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);
struct init_data *init — remove extra space.
Done.

@@ -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;
}
These conditions don’t seem to be equivalent: view features ordinary space_id 
AFAIK.
Fixed.

@@ -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.
But in fact you use another sign of fake index:
iid == UINT32_MAX
Updated comment.

 */
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;
    }

@@ -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) {

The same as previous remark: these conditions don’t seem to be equivalent
Fixed.

--
Regards, Kirill Yukhin

commit 3856d92e699ca9e3320f64ec4c1e3d695e5d1a18
Author: Kirill Yukhin <kyukhin@xxxxxxxxxxxxx>
Date:   Tue Jul 17 15:37:46 2018 +0300

    sql: get rid off tnum field of struct Table
    
    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

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 cb7f1e4..755208b 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 */);
@@ -1598,8 +1597,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) {
@@ -2257,15 +2258,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 */
@@ -2273,7 +2268,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 */
@@ -2281,11 +2275,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);
@@ -2312,13 +2301,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);
@@ -2717,7 +2704,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)
@@ -2847,7 +2834,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;
        }
 
        /*
@@ -2880,7 +2867,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);
@@ -3578,7 +3565,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);
                }
        }
 }
@@ -3672,7 +3659,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..231b06c 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,
+                                                         pTab->def->id,
                                                          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 a258bfc..d427f78 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -432,9 +432,7 @@ 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_by_id(pTab->def->id);
                                assert(space != NULL);
                                struct index *pk = space_index(space, 0);
                                size_t avg_tuple_size_pk =
@@ -447,10 +445,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 +685,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 9ea7c78..a9bfa67 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 */
@@ -2091,10 +2090,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).
+ * of this structure may be created.
  */
 struct Index {
        /** The SQL table being indexed. */
@@ -2107,8 +2103,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
@@ -3129,15 +3123,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.
@@ -3476,7 +3473,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..e1430a3 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -28,23 +28,8 @@
 #define TARANTOOL_INDEX_INSERT 1
 #define TARANTOOL_INDEX_REPLACE 2
 
-/*
- * SQLite uses the root page number to identify a Table or Index BTree.
- * We switched it to using Tarantool spaces and indices instead of the
- * BTrees. Hence the functions to encode index and space id in
- * a page number.
- */
-#define SQLITE_PAGENO_FROM_SPACEID_AND_INDEXID(spaceid, iid) \
-  (((unsigned)(spaceid) << 10) | (iid))
-
-#define SQLITE_PAGENO_TO_SPACEID(pgno) \
-  ((unsigned)(pgno) >> 10)
-
-#define SQLITE_PAGENO_TO_INDEXID(pgno) \
-  ((pgno) & 1023)
-
 /* Load database schema from Tarantool. */
-void tarantoolSqlite3LoadSchema(InitData * init);
+void tarantoolSqlite3LoadSchema(struct init_data *init);
 
 /* Misc */
 const char *tarantoolErrorMessage();
@@ -82,10 +67,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..1a75f77 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -1155,15 +1155,13 @@ case OP_NextAutoincValue: {
        assert(pOp->p1 > 0);
        assert(pOp->p2 > 0);
 
-       int64_t value;
-       uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pOp->p1);
-
-       struct space *space = space_by_id(space_id);
+       struct space *space = space_by_id(pOp->p1);
        if (space == NULL) {
                rc = SQL_TARANTOOL_ERROR;
                goto abort_due_to_error;
        }
 
+       int64_t value;
        struct sequence *sequence = space->sequence;
        if (sequence == NULL || sequence_next(sequence, &value) != 0) {
                rc = SQL_TARANTOOL_ERROR;
@@ -4615,19 +4613,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 +4636,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 +4655,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 +4667,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 +4685,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 +4707,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..1173576 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->id == 0)
+               p->pIndex = NULL;
        return rc;
 }
 
@@ -2343,12 +2336,12 @@ whereRangeVectorLen(Parse * pParse,     /* Parsing 
context */
  * index pIndex. Try to match one more.
  *
  * When this function is called, pBuilder->pNew->nOut contains the
- * number of rows expected to be visited by filtering using the nEq
- * terms only. If it is modified, this value is restored before this
- * function returns.
+ * number of rows expected to be visited by filtering using the
+ * nEq 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==UIN32_MAX, 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->id != 
0) {
                                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,

Other related posts: