From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 483C8288AB for ; Thu, 22 Mar 2018 06:07:34 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zW4IhH2-27Uu for ; Thu, 22 Mar 2018 06:07:34 -0400 (EDT) Received: from smtp34.i.mail.ru (smtp34.i.mail.ru [94.100.177.94]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 7F4522856E for ; Thu, 22 Mar 2018 06:07:32 -0400 (EDT) From: "n.pettik" Content-Type: multipart/alternative; boundary="Apple-Mail=_F6035853-4E10-4750-88F4-F96E79F71D66" Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\)) Subject: [tarantool-patches] Re: [PATCH 1/4] sql: pass space pointer to OP_OpenRead/OpenWrite Date: Thu, 22 Mar 2018 13:07:21 +0300 References: <46d0750257b6b5a256210b063515b1b05f4d7d37.1521583434.git.korablev@tarantool.org> <20180321131450.otxkluudlhf3yh2i@tarantool.org> In-Reply-To: <20180321131450.otxkluudlhf3yh2i@tarantool.org> Message-Id: <7F0DB390-F7BA-4E1F-AB93-9DB8498BCFD5@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org, =?utf-8?B?0JrQuNGA0LjQu9C7INCu0YXQuNC9?= --Apple-Mail=_F6035853-4E10-4750-88F4-F96E79F71D66 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On 21 Mar 2018, at 16:14, Kirill Yukhin wrote: >=20 > Hello, > My comments inlined. >=20 > On 21 =D0=BC=D0=B0=D1=80 02:48, Nikita Pettik wrote: >> Originally in SQLite, to open table (i.e. btree) it was required to = pass >> number of page root to OP_OpenRead or OP_OpenWrite opcodes as an >> argument. However, now there are only Tarantool spaces and nothing >> prevents from operating directly on pointers to them. On the other = hand, >> pointers are able to expire after schema changes (i.e. after DML >> routine). For this reason, schema version is saved to VDBE at compile >> time and checked each time during cursor opening. >>=20 >> Part of #3252 >> --- >> src/box/sql/analyze.c | 17 +++++++++++++++-- >> src/box/sql/build.c | 7 ++++++- >> src/box/sql/expr.c | 14 ++++++++++++-- >> src/box/sql/fkey.c | 11 ++++++++++- >> src/box/sql/insert.c | 37 ++++++++++++++++++++++++++++++++----- >> src/box/sql/select.c | 11 ++++++++++- >> src/box/sql/vdbe.c | 12 ++++++++++-- >> src/box/sql/vdbe.h | 1 + >> src/box/sql/vdbeInt.h | 1 + >> src/box/sql/vdbeaux.c | 13 +++++++++++++ >> src/box/sql/where.c | 12 +++++++++++- >> 11 files changed, 121 insertions(+), 15 deletions(-) >>=20 >> diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c >> index db06d0182..57fc33c70 100644 >> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c >> index 9929dfb96..5d1227afa 100644 >> --- a/src/box/sql/vdbe.c >> +++ b/src/box/sql/vdbe.c >> @@ -3217,9 +3217,17 @@ case OP_OpenWrite: >>=20 >> assert(p2 >=3D 1); >> pBtCur =3D pCur->uc.pCursor; >> - pBtCur->space =3D space_by_id(SQLITE_PAGENO_TO_SPACEID(p2)); >> + if (box_schema_version() =3D=3D p->schema_ver) { >> + pIn3 =3D &aMem[pOp->p3]; >> + /* Make sure that 64-bit pointer can fit into int64_t. = */ >> + assert(sizeof(pBtCur->space) >=3D sizeof(pIn3->u.i)); > I don't like this. If we're going to extensively use pointers = space/index then > let's extend Memory struct adding dedicated types to the union. > Note, that new opcode (say, LoadPtr) will be needed. Done.=20 >=20 >> + pBtCur->space =3D ((struct space *) pIn3->u.i); >> + } else { >> + pBtCur->space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(p2)); >> + } > Don't surround single stmt withcurly braces pls. This is only only advise = (https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-b= races-and-spaces = ): "Do not unnecessarily use braces where a single statement will do." So, I guess, both variants are allowed.=20 > Also, if schema was changed then error should be returned (stmt = expired or > smth). I have dedicated separate patch (the last one) for this issue. It can=E2=80=99t be done right here since new DDL processing is also introduced in next patch. In order to make no confusions, I will remove this diff and place it to the last patch. >> diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h >> index 7241963e4..a1ecf729d 100644 >> --- a/src/box/sql/vdbe.h >> +++ b/src/box/sql/vdbe.h >> diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h >> index 8b622de5b..99262ab7b 100644 >> --- a/src/box/sql/vdbeInt.h >> +++ b/src/box/sql/vdbeInt.h >> @@ -378,6 +378,7 @@ struct Vdbe { >> i64 nFkConstraint; /* Number of imm. FK constraints this VM = */ >> i64 nStmtDefCons; /* Number of def. constraints when stmt = started */ >> i64 nStmtDefImmCons; /* Number of def. imm constraints when = stmt started */ >> + uint32_t schema_ver; /* Schema version at the moment of VDBE = creation. */ >>=20 >> /* >> * In recursive triggers we can execute INSERT/UPDATE OR IGNORE >> diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c >> index 92bf9943b..b35d0712e 100644 >> --- a/src/box/sql/vdbeaux.c >> +++ b/src/box/sql/vdbeaux.c >> @@ -66,6 +66,7 @@ sqlite3VdbeCreate(Parse * pParse) >> p->magic =3D VDBE_MAGIC_INIT; >> p->pParse =3D pParse; >> p->autoCommit =3D (char)box_txn() =3D=3D 0 ? 1 : 0; >> + p->schema_ver =3D box_schema_version(); >> if (!p->autoCommit) { >> p->psql_txn =3D in_txn()->psql_txn; >> p->nDeferredCons =3D p->psql_txn->nDeferredConsSave; >> @@ -413,6 +414,18 @@ sqlite3VdbeAddOp4Int(Vdbe * p, /* Add the = opcode to this VM */ >> return addr; >> } >>=20 >> +int >> +sqlite3VdbeAddOp4Int64(Vdbe *p, int op, int p1, int p2, int p3, = int64_t p4) >> +{ >> + int addr =3D sqlite3VdbeAddOp3(p, op, p1, p2, p3); >> + VdbeOp *pOp =3D &p->aOp[addr]; >> + pOp->p4type =3D P4_INT64; >> + pOp->p4.pI64 =3D sqlite3DbMallocRawNN(sqlite3VdbeDb(p), = sizeof(int64_t)); >> + if (p->db->mallocFailed =3D=3D 0) >> + *pOp->p4.pI64 =3D p4; >> + return addr; >> +} > This is useless if LoadPTR will be introduced. Done. The whole patch is below: =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Originally in SQLite, to open table (i.e. btree) it was required to pass number of page root to OP_OpenRead or OP_OpenWrite opcodes as an argument. However, now there are only Tarantool spaces and nothing prevents from operating directly on pointers to them. Thus, to pass pointers from compile time to runtime, opcode OP_LoadPtr has been introduced. It fetches pointer from P4 and stores to the register specified by P2. It is worth mentioning that, pointers are able to expire after schema changes (i.e. after DML routine). For this reason, schema version is saved to VDBE at compile time and checked each time during cursor opening. Part of #3252 --- src/box/sql/analyze.c | 17 +++++- src/box/sql/build.c | 7 ++- src/box/sql/expr.c | 14 ++++- src/box/sql/fkey.c | 11 +++- src/box/sql/insert.c | 36 ++++++++++-- src/box/sql/opcodes.c | 137 +++++++++++++++++++++---------------------- src/box/sql/opcodes.h | 157 = +++++++++++++++++++++++++------------------------- src/box/sql/select.c | 11 +++- src/box/sql/vdbe.c | 13 +++++ src/box/sql/vdbe.h | 2 + src/box/sql/vdbeInt.h | 3 + src/box/sql/vdbeaux.c | 11 ++++ src/box/sql/where.c | 12 +++- 13 files changed, 272 insertions(+), 159 deletions(-) diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index db06d0182..d121dd2b9 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -174,10 +174,16 @@ openStatTable(Parse * pParse, /* Parsing = context */ =20 /* Open the sql_stat[134] tables for writing. */ for (i =3D 0; aTable[i]; i++) { + struct space *space =3D + space_by_id(SQLITE_PAGENO_TO_SPACEID(aRoot[i])); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, 0, + (void *) space); int addr; addr =3D sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur + i, = aRoot[i], - 0); + space_ptr_reg); v->aOp[addr].p4.pKeyInfo =3D 0; v->aOp[addr].p4type =3D P4_KEYINFO; sqlite3VdbeChangeP5(v, aCreateTbl[i]); @@ -814,6 +820,7 @@ analyzeOneTable(Parse * pParse, /* Parser = context */ int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ + int space_ptr_reg =3D iMem++; int regStat4 =3D iMem++; /* Register to hold Stat4Accum = object */ int regChng =3D iMem++; /* Index of changed index field */ int regKey =3D iMem++; /* Key argument passed to stat_push() */ @@ -910,7 +917,13 @@ analyzeOneTable(Parse * pParse, /* Parser = context */ =20 /* Open a read-only cursor on the index being analyzed. = */ assert(sqlite3SchemaToIndex(db, pIdx->pSchema) =3D=3D = 0); - sqlite3VdbeAddOp2(v, OP_OpenRead, iIdxCur, pIdx->tnum); + struct space *space =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum)); + assert(space !=3D NULL); + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, 0, + (void *) space); + sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, + space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); =20 diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 9ad0c0605..9cdfd0b7a 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -2603,7 +2603,12 @@ sqlite3RefillIndex(Parse * pParse, Index * = pIndex, int memRootPage) sqlite3VdbeJumpHere(v, addr1); if (memRootPage < 0) sqlite3VdbeAddOp2(v, OP_Clear, tnum, 0); - sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, 0, + struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, 0, + (void *) space); + sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, space_ptr_reg, (char *)pKey, P4_KEYINFO); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR | ((memRootPage >=3D 0) ? diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c index b69a176cb..009538095 100644 --- a/src/box/sql/expr.c +++ b/src/box/sql/expr.c @@ -35,7 +35,9 @@ */ #include #include "sqliteInt.h" +#include "tarantoolInt.h" #include "box/session.h" +#include "box/schema.h" =20 /* Forward declarations */ static void exprCodeBetween(Parse *, Expr *, int, @@ -2586,8 +2588,16 @@ sqlite3FindInIndex(Parse * pParse, /* = Parsing context */ pIdx->zName), P4_DYNAMIC); #endif - sqlite3VdbeAddOp2(v, = OP_OpenRead, iTab, - pIdx->tnum); + struct space *space =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D = ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, + = space_ptr_reg, 0, + (void *) = space); + sqlite3VdbeAddOp3(v, = OP_OpenRead, iTab, + pIdx->tnum, + = space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, = pIdx); VdbeComment((v, "%s", = pIdx->zName)); assert(IN_INDEX_INDEX_DESC =3D=3D diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c index 439f38352..77565cb50 100644 --- a/src/box/sql/fkey.c +++ b/src/box/sql/fkey.c @@ -35,7 +35,9 @@ */ #include #include "sqliteInt.h" +#include "tarantoolInt.h" #include "box/session.h" +#include "box/schema.h" =20 #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER @@ -434,7 +436,14 @@ fkLookupParent(Parse * pParse, /* Parse context = */ int regTemp =3D sqlite3GetTempRange(pParse, = nCol); int regRec =3D sqlite3GetTempReg(pParse); =20 - sqlite3VdbeAddOp2(v, OP_OpenRead, iCur, = pIdx->tnum); + struct space *space =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, = space_ptr_reg, 0, + (void *) space); + sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, = pIdx->tnum, + space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for (i =3D 0; i < nCol; i++) { sqlite3VdbeAddOp2(v, OP_Copy, diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c index 54fcca5c9..4f3e2f316 100644 --- a/src/box/sql/insert.c +++ b/src/box/sql/insert.c @@ -34,7 +34,9 @@ * to handle INSERT statements in SQLite. */ #include "sqliteInt.h" +#include "tarantoolInt.h" #include "box/session.h" +#include "box/schema.h" =20 /* * Generate code that will open pTab as cursor iCur. @@ -51,7 +53,12 @@ sqlite3OpenTable(Parse * pParse, /* Generate code = into this VDBE */ Index *pPk =3D sqlite3PrimaryKeyIndex(pTab); assert(pPk !=3D 0); assert(pPk->tnum =3D=3D pTab->tnum); - sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, 0); + struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(pPk->tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, 0, + (void *) space); + sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pPk); VdbeComment((v, "%s", pTab->zName)); } @@ -183,7 +190,7 @@ readsTable(Parse * p, Table * pTab) for (i =3D 1; i < iEnd; i++) { VdbeOp *pOp =3D sqlite3VdbeGetOp(v, i); assert(pOp !=3D 0); - if (pOp->opcode =3D=3D OP_OpenRead && pOp->p3 =3D=3D 0) = { + if (pOp->opcode =3D=3D OP_OpenRead) { Index *pIndex; int tnum =3D pOp->p2; if (tnum =3D=3D pTab->tnum) { @@ -1560,6 +1567,10 @@ sqlite3OpenTableAndIndices(Parse * pParse, = /* Parsing context */ *piDataCur =3D iDataCur; if (piIdxCur) *piIdxCur =3D iBase; + struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(pTab->tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, 0, (void = *) space); =20 /* One iteration of this cycle adds OpenRead/OpenWrite which * opens cursor for current index. @@ -1607,7 +1618,8 @@ sqlite3OpenTableAndIndices(Parse * pParse, = /* Parsing context */ p5 =3D 0; } if (aToOpen =3D=3D 0 || aToOpen[i + 1]) { - sqlite3VdbeAddOp2(v, op, iIdxCur, = pIdx->tnum); + sqlite3VdbeAddOp3(v, op, iIdxCur, = pIdx->tnum, + space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); sqlite3VdbeChangeP5(v, p5); VdbeComment((v, "%s", pIdx->zName)); @@ -1911,10 +1923,24 @@ xferOptimization(Parse * pParse, /* = Parser context */ break; } assert(pSrcIdx); - sqlite3VdbeAddOp2(v, OP_OpenRead, iSrc, pSrcIdx->tnum); + struct space *space_src =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pSrcIdx->tnum)); + assert(space_src !=3D NULL); + int space_src_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, = space_src_ptr_reg, 0, + (void *) space_src); + sqlite3VdbeAddOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum, + space_src_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); - sqlite3VdbeAddOp2(v, OP_OpenWrite, iDest, = pDestIdx->tnum); + struct space *space_dest =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pDestIdx->tnum)); + assert(space_dest !=3D NULL); + int space_dest_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, = space_dest_ptr_reg, 0, + (void *) space_dest); + sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, = pDestIdx->tnum, + space_dest_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); diff --git a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c index 7a40b28a8..b108d5f9e 100644 --- a/src/box/sql/opcodes.c +++ b/src/box/sql/opcodes.c @@ -78,76 +78,77 @@ const char *sqlite3OpcodeName(int i){ /* 64 */ "Integer" OpHelp("r[P2]=3DP1"), /* 65 */ "Bool" OpHelp("r[P2]=3DP1"), /* 66 */ "Int64" OpHelp("r[P2]=3DP4"), - /* 67 */ "String" OpHelp("r[P2]=3D'P4' (len=3DP1)"), - /* 68 */ "Null" OpHelp("r[P2..P3]=3DNULL"), - /* 69 */ "SoftNull" OpHelp("r[P1]=3DNULL"), - /* 70 */ "Blob" OpHelp("r[P2]=3DP4 (len=3DP1, = subtype=3DP3)"), - /* 71 */ "Variable" OpHelp("r[P2]=3Dparameter(P1,P4)"), - /* 72 */ "Move" OpHelp("r[P2@P3]=3Dr[P1@P3]"), - /* 73 */ "Copy" OpHelp("r[P2@P3+1]=3Dr[P1@P3+1]"), - /* 74 */ "SCopy" OpHelp("r[P2]=3Dr[P1]"), + /* 67 */ "LoadPtr" OpHelp("r[P2] =3D P4"), + /* 68 */ "String" OpHelp("r[P2]=3D'P4' (len=3DP1)"), + /* 69 */ "Null" OpHelp("r[P2..P3]=3DNULL"), + /* 70 */ "SoftNull" OpHelp("r[P1]=3DNULL"), + /* 71 */ "Blob" OpHelp("r[P2]=3DP4 (len=3DP1, = subtype=3DP3)"), + /* 72 */ "Variable" OpHelp("r[P2]=3Dparameter(P1,P4)"), + /* 73 */ "Move" OpHelp("r[P2@P3]=3Dr[P1@P3]"), + /* 74 */ "Copy" OpHelp("r[P2@P3+1]=3Dr[P1@P3+1]"), /* 75 */ "String8" OpHelp("r[P2]=3D'P4'"), - /* 76 */ "IntCopy" OpHelp("r[P2]=3Dr[P1]"), - /* 77 */ "ResultRow" OpHelp("output=3Dr[P1@P2]"), - /* 78 */ "CollSeq" OpHelp(""), - /* 79 */ "Function0" OpHelp("r[P3]=3Dfunc(r[P2@P5])"), - /* 80 */ "Function" OpHelp("r[P3]=3Dfunc(r[P2@P5])"), - /* 81 */ "AddImm" OpHelp("r[P1]=3Dr[P1]+P2"), - /* 82 */ "RealAffinity" OpHelp(""), - /* 83 */ "Cast" OpHelp("affinity(r[P1])"), - /* 84 */ "Permutation" OpHelp(""), - /* 85 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 86 */ "Column" OpHelp("r[P3]=3DPX"), - /* 87 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 88 */ "MakeRecord" OpHelp("r[P3]=3Dmkrec(r[P1@P2])"), - /* 89 */ "Count" OpHelp("r[P2]=3Dcount()"), - /* 90 */ "FkCheckCommit" OpHelp(""), - /* 91 */ "TTransaction" OpHelp(""), - /* 92 */ "ReadCookie" OpHelp(""), - /* 93 */ "SetCookie" OpHelp(""), - /* 94 */ "ReopenIdx" OpHelp("root=3DP2"), - /* 95 */ "OpenRead" OpHelp("root=3DP2"), - /* 96 */ "OpenWrite" OpHelp("root=3DP2"), - /* 97 */ "OpenTEphemeral" OpHelp("nColumn =3D P2"), - /* 98 */ "SorterOpen" OpHelp(""), - /* 99 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc =3D = P2"), - /* 100 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), - /* 101 */ "Close" OpHelp(""), - /* 102 */ "ColumnsUsed" OpHelp(""), - /* 103 */ "Sequence" OpHelp("r[P2]=3Dcursor[P1].ctr++"), - /* 104 */ "NextId" = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"), - /* 105 */ "NextIdEphemeral" = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"), - /* 106 */ "FCopy" OpHelp("reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), - /* 107 */ "Delete" OpHelp(""), - /* 108 */ "ResetCount" OpHelp(""), - /* 109 */ "SorterCompare" OpHelp("if key(P1)!=3Dtrim(r[P3],P4) = goto P2"), - /* 110 */ "SorterData" OpHelp("r[P2]=3Ddata"), - /* 111 */ "RowData" OpHelp("r[P2]=3Ddata"), - /* 112 */ "NullRow" OpHelp(""), - /* 113 */ "SorterInsert" OpHelp("key=3Dr[P2]"), - /* 114 */ "IdxReplace" OpHelp("key=3Dr[P2]"), + /* 76 */ "SCopy" OpHelp("r[P2]=3Dr[P1]"), + /* 77 */ "IntCopy" OpHelp("r[P2]=3Dr[P1]"), + /* 78 */ "ResultRow" OpHelp("output=3Dr[P1@P2]"), + /* 79 */ "CollSeq" OpHelp(""), + /* 80 */ "Function0" OpHelp("r[P3]=3Dfunc(r[P2@P5])"), + /* 81 */ "Function" OpHelp("r[P3]=3Dfunc(r[P2@P5])"), + /* 82 */ "AddImm" OpHelp("r[P1]=3Dr[P1]+P2"), + /* 83 */ "RealAffinity" OpHelp(""), + /* 84 */ "Cast" OpHelp("affinity(r[P1])"), + /* 85 */ "Permutation" OpHelp(""), + /* 86 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 87 */ "Column" OpHelp("r[P3]=3DPX"), + /* 88 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 89 */ "MakeRecord" OpHelp("r[P3]=3Dmkrec(r[P1@P2])"), + /* 90 */ "Count" OpHelp("r[P2]=3Dcount()"), + /* 91 */ "FkCheckCommit" OpHelp(""), + /* 92 */ "TTransaction" OpHelp(""), + /* 93 */ "ReadCookie" OpHelp(""), + /* 94 */ "SetCookie" OpHelp(""), + /* 95 */ "ReopenIdx" OpHelp("root=3DP2"), + /* 96 */ "OpenRead" OpHelp("root=3DP2"), + /* 97 */ "OpenWrite" OpHelp("root=3DP2"), + /* 98 */ "OpenTEphemeral" OpHelp("nColumn =3D P2"), + /* 99 */ "SorterOpen" OpHelp(""), + /* 100 */ "SequenceTest" OpHelp("if (cursor[P1].ctr++) pc =3D = P2"), + /* 101 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"), + /* 102 */ "Close" OpHelp(""), + /* 103 */ "ColumnsUsed" OpHelp(""), + /* 104 */ "Sequence" OpHelp("r[P2]=3Dcursor[P1].ctr++"), + /* 105 */ "NextId" = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"), + /* 106 */ "NextIdEphemeral" = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"), + /* 107 */ "FCopy" OpHelp("reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)]"), + /* 108 */ "Delete" OpHelp(""), + /* 109 */ "ResetCount" OpHelp(""), + /* 110 */ "SorterCompare" OpHelp("if key(P1)!=3Dtrim(r[P3],P4) = goto P2"), + /* 111 */ "SorterData" OpHelp("r[P2]=3Ddata"), + /* 112 */ "RowData" OpHelp("r[P2]=3Ddata"), + /* 113 */ "NullRow" OpHelp(""), + /* 114 */ "SorterInsert" OpHelp("key=3Dr[P2]"), /* 115 */ "Real" OpHelp("r[P2]=3DP4"), - /* 116 */ "IdxInsert" OpHelp("key=3Dr[P2]"), - /* 117 */ "IdxDelete" OpHelp("key=3Dr[P2@P3]"), - /* 118 */ "Clear" OpHelp("space id =3D P1"), - /* 119 */ "ResetSorter" OpHelp(""), - /* 120 */ "ParseSchema2" OpHelp("rows=3Dr[P1@P2]"), - /* 121 */ "ParseSchema3" OpHelp("name=3Dr[P1] sql=3Dr[P1+1]"), - /* 122 */ "RenameTable" OpHelp("P1 =3D root, P4 =3D name"), - /* 123 */ "LoadAnalysis" OpHelp(""), - /* 124 */ "DropTable" OpHelp(""), - /* 125 */ "DropIndex" OpHelp(""), - /* 126 */ "DropTrigger" OpHelp(""), - /* 127 */ "Param" OpHelp(""), - /* 128 */ "FkCounter" OpHelp("fkctr[P1]+=3DP2"), - /* 129 */ "OffsetLimit" OpHelp("if r[P1]>0 then = r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1)"), - /* 130 */ "AggStep0" OpHelp("accum=3Dr[P3] = step(r[P2@P5])"), - /* 131 */ "AggStep" OpHelp("accum=3Dr[P3] = step(r[P2@P5])"), - /* 132 */ "AggFinal" OpHelp("accum=3Dr[P1] N=3DP2"), - /* 133 */ "Expire" OpHelp(""), - /* 134 */ "IncMaxid" OpHelp(""), - /* 135 */ "Noop" OpHelp(""), - /* 136 */ "Explain" OpHelp(""), + /* 116 */ "IdxReplace" OpHelp("key=3Dr[P2]"), + /* 117 */ "IdxInsert" OpHelp("key=3Dr[P2]"), + /* 118 */ "IdxDelete" OpHelp("key=3Dr[P2@P3]"), + /* 119 */ "Clear" OpHelp("space id =3D P1"), + /* 120 */ "ResetSorter" OpHelp(""), + /* 121 */ "ParseSchema2" OpHelp("rows=3Dr[P1@P2]"), + /* 122 */ "ParseSchema3" OpHelp("name=3Dr[P1] sql=3Dr[P1+1]"), + /* 123 */ "RenameTable" OpHelp("P1 =3D root, P4 =3D name"), + /* 124 */ "LoadAnalysis" OpHelp(""), + /* 125 */ "DropTable" OpHelp(""), + /* 126 */ "DropIndex" OpHelp(""), + /* 127 */ "DropTrigger" OpHelp(""), + /* 128 */ "Param" OpHelp(""), + /* 129 */ "FkCounter" OpHelp("fkctr[P1]+=3DP2"), + /* 130 */ "OffsetLimit" OpHelp("if r[P1]>0 then = r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1)"), + /* 131 */ "AggStep0" OpHelp("accum=3Dr[P3] = step(r[P2@P5])"), + /* 132 */ "AggStep" OpHelp("accum=3Dr[P3] = step(r[P2@P5])"), + /* 133 */ "AggFinal" OpHelp("accum=3Dr[P1] N=3DP2"), + /* 134 */ "Expire" OpHelp(""), + /* 135 */ "IncMaxid" OpHelp(""), + /* 136 */ "Noop" OpHelp(""), + /* 137 */ "Explain" OpHelp(""), }; return azName[i]; } diff --git a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h index af2ba1963..7b62f6d80 100644 --- a/src/box/sql/opcodes.h +++ b/src/box/sql/opcodes.h @@ -67,76 +67,77 @@ #define OP_Integer 64 /* synopsis: r[P2]=3DP1 = */ #define OP_Bool 65 /* synopsis: r[P2]=3DP1 = */ #define OP_Int64 66 /* synopsis: r[P2]=3DP4 = */ -#define OP_String 67 /* synopsis: r[P2]=3D'P4' (len=3DP1) = */ -#define OP_Null 68 /* synopsis: r[P2..P3]=3DNULL = */ -#define OP_SoftNull 69 /* synopsis: r[P1]=3DNULL = */ -#define OP_Blob 70 /* synopsis: r[P2]=3DP4 (len=3DP1, = subtype=3DP3) */ -#define OP_Variable 71 /* synopsis: r[P2]=3Dparameter(P1,P4) = */ -#define OP_Move 72 /* synopsis: r[P2@P3]=3Dr[P1@P3] = */ -#define OP_Copy 73 /* synopsis: r[P2@P3+1]=3Dr[P1@P3+1] = */ -#define OP_SCopy 74 /* synopsis: r[P2]=3Dr[P1] = */ +#define OP_LoadPtr 67 /* synopsis: r[P2] =3D P4 = */ +#define OP_String 68 /* synopsis: r[P2]=3D'P4' (len=3DP1) = */ +#define OP_Null 69 /* synopsis: r[P2..P3]=3DNULL = */ +#define OP_SoftNull 70 /* synopsis: r[P1]=3DNULL = */ +#define OP_Blob 71 /* synopsis: r[P2]=3DP4 (len=3DP1, = subtype=3DP3) */ +#define OP_Variable 72 /* synopsis: r[P2]=3Dparameter(P1,P4) = */ +#define OP_Move 73 /* synopsis: r[P2@P3]=3Dr[P1@P3] = */ +#define OP_Copy 74 /* synopsis: r[P2@P3+1]=3Dr[P1@P3+1] = */ #define OP_String8 75 /* same as TK_STRING, synopsis: r[P2]=3D'P4'= */ -#define OP_IntCopy 76 /* synopsis: r[P2]=3Dr[P1] = */ -#define OP_ResultRow 77 /* synopsis: output=3Dr[P1@P2] = */ -#define OP_CollSeq 78 -#define OP_Function0 79 /* synopsis: r[P3]=3Dfunc(r[P2@P5]) = */ -#define OP_Function 80 /* synopsis: r[P3]=3Dfunc(r[P2@P5]) = */ -#define OP_AddImm 81 /* synopsis: r[P1]=3Dr[P1]+P2 = */ -#define OP_RealAffinity 82 -#define OP_Cast 83 /* synopsis: affinity(r[P1]) = */ -#define OP_Permutation 84 -#define OP_Compare 85 /* synopsis: r[P1@P3] <-> r[P2@P3] = */ -#define OP_Column 86 /* synopsis: r[P3]=3DPX = */ -#define OP_Affinity 87 /* synopsis: affinity(r[P1@P2]) = */ -#define OP_MakeRecord 88 /* synopsis: r[P3]=3Dmkrec(r[P1@P2]) = */ -#define OP_Count 89 /* synopsis: r[P2]=3Dcount() = */ -#define OP_FkCheckCommit 90 -#define OP_TTransaction 91 -#define OP_ReadCookie 92 -#define OP_SetCookie 93 -#define OP_ReopenIdx 94 /* synopsis: root=3DP2 = */ -#define OP_OpenRead 95 /* synopsis: root=3DP2 = */ -#define OP_OpenWrite 96 /* synopsis: root=3DP2 = */ -#define OP_OpenTEphemeral 97 /* synopsis: nColumn =3D P2 = */ -#define OP_SorterOpen 98 -#define OP_SequenceTest 99 /* synopsis: if (cursor[P1].ctr++) pc =3D = P2 */ -#define OP_OpenPseudo 100 /* synopsis: P3 columns in r[P2] = */ -#define OP_Close 101 -#define OP_ColumnsUsed 102 -#define OP_Sequence 103 /* synopsis: r[P2]=3Dcursor[P1].ctr++ = */ -#define OP_NextId 104 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */ -#define OP_NextIdEphemeral 105 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */ -#define OP_FCopy 106 /* synopsis: reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ -#define OP_Delete 107 -#define OP_ResetCount 108 -#define OP_SorterCompare 109 /* synopsis: if key(P1)!=3Dtrim(r[P3],P4) = goto P2 */ -#define OP_SorterData 110 /* synopsis: r[P2]=3Ddata = */ -#define OP_RowData 111 /* synopsis: r[P2]=3Ddata = */ -#define OP_NullRow 112 -#define OP_SorterInsert 113 /* synopsis: key=3Dr[P2] = */ -#define OP_IdxReplace 114 /* synopsis: key=3Dr[P2] = */ +#define OP_SCopy 76 /* synopsis: r[P2]=3Dr[P1] = */ +#define OP_IntCopy 77 /* synopsis: r[P2]=3Dr[P1] = */ +#define OP_ResultRow 78 /* synopsis: output=3Dr[P1@P2] = */ +#define OP_CollSeq 79 +#define OP_Function0 80 /* synopsis: r[P3]=3Dfunc(r[P2@P5]) = */ +#define OP_Function 81 /* synopsis: r[P3]=3Dfunc(r[P2@P5]) = */ +#define OP_AddImm 82 /* synopsis: r[P1]=3Dr[P1]+P2 = */ +#define OP_RealAffinity 83 +#define OP_Cast 84 /* synopsis: affinity(r[P1]) = */ +#define OP_Permutation 85 +#define OP_Compare 86 /* synopsis: r[P1@P3] <-> r[P2@P3] = */ +#define OP_Column 87 /* synopsis: r[P3]=3DPX = */ +#define OP_Affinity 88 /* synopsis: affinity(r[P1@P2]) = */ +#define OP_MakeRecord 89 /* synopsis: r[P3]=3Dmkrec(r[P1@P2]) = */ +#define OP_Count 90 /* synopsis: r[P2]=3Dcount() = */ +#define OP_FkCheckCommit 91 +#define OP_TTransaction 92 +#define OP_ReadCookie 93 +#define OP_SetCookie 94 +#define OP_ReopenIdx 95 /* synopsis: root=3DP2 = */ +#define OP_OpenRead 96 /* synopsis: root=3DP2 = */ +#define OP_OpenWrite 97 /* synopsis: root=3DP2 = */ +#define OP_OpenTEphemeral 98 /* synopsis: nColumn =3D P2 = */ +#define OP_SorterOpen 99 +#define OP_SequenceTest 100 /* synopsis: if (cursor[P1].ctr++) pc =3D = P2 */ +#define OP_OpenPseudo 101 /* synopsis: P3 columns in r[P2] = */ +#define OP_Close 102 +#define OP_ColumnsUsed 103 +#define OP_Sequence 104 /* synopsis: r[P2]=3Dcursor[P1].ctr++ = */ +#define OP_NextId 105 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */ +#define OP_NextIdEphemeral 106 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */ +#define OP_FCopy 107 /* synopsis: reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)] */ +#define OP_Delete 108 +#define OP_ResetCount 109 +#define OP_SorterCompare 110 /* synopsis: if key(P1)!=3Dtrim(r[P3],P4) = goto P2 */ +#define OP_SorterData 111 /* synopsis: r[P2]=3Ddata = */ +#define OP_RowData 112 /* synopsis: r[P2]=3Ddata = */ +#define OP_NullRow 113 +#define OP_SorterInsert 114 /* synopsis: key=3Dr[P2] = */ #define OP_Real 115 /* same as TK_FLOAT, synopsis: r[P2]=3DP4 = */ -#define OP_IdxInsert 116 /* synopsis: key=3Dr[P2] = */ -#define OP_IdxDelete 117 /* synopsis: key=3Dr[P2@P3] = */ -#define OP_Clear 118 /* synopsis: space id =3D P1 = */ -#define OP_ResetSorter 119 -#define OP_ParseSchema2 120 /* synopsis: rows=3Dr[P1@P2] = */ -#define OP_ParseSchema3 121 /* synopsis: name=3Dr[P1] sql=3Dr[P1+1] = */ -#define OP_RenameTable 122 /* synopsis: P1 =3D root, P4 =3D name = */ -#define OP_LoadAnalysis 123 -#define OP_DropTable 124 -#define OP_DropIndex 125 -#define OP_DropTrigger 126 -#define OP_Param 127 -#define OP_FkCounter 128 /* synopsis: fkctr[P1]+=3DP2 = */ -#define OP_OffsetLimit 129 /* synopsis: if r[P1]>0 then = r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1) */ -#define OP_AggStep0 130 /* synopsis: accum=3Dr[P3] step(r[P2@P5]) = */ -#define OP_AggStep 131 /* synopsis: accum=3Dr[P3] step(r[P2@P5]) = */ -#define OP_AggFinal 132 /* synopsis: accum=3Dr[P1] N=3DP2 = */ -#define OP_Expire 133 -#define OP_IncMaxid 134 -#define OP_Noop 135 -#define OP_Explain 136 +#define OP_IdxReplace 116 /* synopsis: key=3Dr[P2] = */ +#define OP_IdxInsert 117 /* synopsis: key=3Dr[P2] = */ +#define OP_IdxDelete 118 /* synopsis: key=3Dr[P2@P3] = */ +#define OP_Clear 119 /* synopsis: space id =3D P1 = */ +#define OP_ResetSorter 120 +#define OP_ParseSchema2 121 /* synopsis: rows=3Dr[P1@P2] = */ +#define OP_ParseSchema3 122 /* synopsis: name=3Dr[P1] sql=3Dr[P1+1] = */ +#define OP_RenameTable 123 /* synopsis: P1 =3D root, P4 =3D name = */ +#define OP_LoadAnalysis 124 +#define OP_DropTable 125 +#define OP_DropIndex 126 +#define OP_DropTrigger 127 +#define OP_Param 128 +#define OP_FkCounter 129 /* synopsis: fkctr[P1]+=3DP2 = */ +#define OP_OffsetLimit 130 /* synopsis: if r[P1]>0 then = r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1) */ +#define OP_AggStep0 131 /* synopsis: accum=3Dr[P3] step(r[P2@P5]) = */ +#define OP_AggStep 132 /* synopsis: accum=3Dr[P3] step(r[P2@P5]) = */ +#define OP_AggFinal 133 /* synopsis: accum=3Dr[P1] N=3DP2 = */ +#define OP_Expire 134 +#define OP_IncMaxid 135 +#define OP_Noop 136 +#define OP_Explain 137 =20 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -157,16 +158,16 @@ /* 40 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01, 0x01,\ /* 48 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\ /* 56 */ 0x03, 0x03, 0x03, 0x01, 0x02, 0x02, 0x08, 0x00,\ -/* 64 */ 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,\ -/* 72 */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,\ -/* 80 */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\ -/* 88 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ -/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 104 */ 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 112 */ 0x00, 0x04, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00,\ -/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\ -/* 128 */ 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 136 */ 0x00,} +/* 64 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10,\ +/* 72 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\ +/* 80 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,\ +/* 88 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 104 */ 0x10, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\ +/* 112 */ 0x00, 0x00, 0x04, 0x10, 0x00, 0x04, 0x00, 0x00,\ +/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 128 */ 0x10, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 136 */ 0x00, 0x00,} =20 /* The sqlite3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum diff --git a/src/box/sql/select.c b/src/box/sql/select.c index 2a8c83d06..39c1be53d 100644 --- a/src/box/sql/select.c +++ b/src/box/sql/select.c @@ -35,7 +35,9 @@ */ #include #include "sqliteInt.h" +#include "tarantoolInt.h" #include "box/session.h" +#include "box/schema.h" =20 /* * Trace output macros @@ -6187,8 +6189,15 @@ sqlite3Select(Parse * pParse, /* The = parser context */ } =20 /* Open a read-only cursor, execute the = OP_Count, close the cursor. */ + struct space *space =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(iRoot)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, + space_ptr_reg, 0, + (void *) space); sqlite3VdbeAddOp4Int(v, OP_OpenRead, = iCsr, - iRoot, 0, 1); + iRoot, = space_ptr_reg, 1); if (pKeyInfo) { sqlite3VdbeChangeP4(v, -1, (char = *)pKeyInfo, diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c index 9929dfb96..a44a17062 100644 --- a/src/box/sql/vdbe.c +++ b/src/box/sql/vdbe.c @@ -1072,6 +1072,19 @@ case OP_Int64: { /* out2 */ break; } =20 +/* Opcode: LoadPtr * P2 * P4 * + * Synopsis: r[P2] =3D P4 + * + * P4 is a generic pointer. Copy it into register P2. + */ +case OP_LoadPtr: { + pOut =3D out2Prerelease(p, pOp); + assert(pOp->p4type =3D=3D P4_PTR); + pOut->u.p =3D pOp->p4.p; + pOut->flags =3D MEM_Ptr; + break; +} + #ifndef SQLITE_OMIT_FLOATING_POINT /* Opcode: Real * P2 * P4 * * Synopsis: r[P2]=3DP4 diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h index 7241963e4..340ddc766 100644 --- a/src/box/sql/vdbe.h +++ b/src/box/sql/vdbe.h @@ -144,6 +144,7 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INDEX (-15) /* P4 is a pointer to a Index structure = */ #define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context = object */ #define P4_BOOL (-17) /* P4 is a bool value */ +#define P4_PTR (-18) /* P4 is a generic pointer */ =20 =20 /* Error message codes for OP_Halt */ @@ -200,6 +201,7 @@ int sqlite3VdbeAddOp3(Vdbe *, int, int, int, int); int sqlite3VdbeAddOp4(Vdbe *, int, int, int, int, const char *zP4, = int); int sqlite3VdbeAddOp4Dup8(Vdbe *, int, int, int, int, const u8 *, int); int sqlite3VdbeAddOp4Int(Vdbe *, int, int, int, int, int); +int sqlite3VdbeAddOp4Ptr(Vdbe *, int, int, int, int, void *); void sqlite3VdbeEndCoroutine(Vdbe *, int); #if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) void sqlite3VdbeVerifyNoMallocRequired(Vdbe * p, int N); diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h index 8b622de5b..fcb45c8a8 100644 --- a/src/box/sql/vdbeInt.h +++ b/src/box/sql/vdbeInt.h @@ -196,6 +196,7 @@ struct Mem { i64 i; /* Integer value used when MEM_Int is = set in flags */ bool b; /* Boolean value used when MEM_Bool is = set in flags */ int nZero; /* Used when bit MEM_Zero is set in = flags */ + void *p; /* Generic pointer */ FuncDef *pDef; /* Used only when flags=3D=3DMEM_Agg */ VdbeFrame *pFrame; /* Used when flags=3D=3DMEM_Frame = */ } u; @@ -239,6 +240,7 @@ struct Mem { #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_Bool 0x0020 /* Value is a bool */ +#define MEM_Ptr 0x0040 /* Value is a generic pointer */ #define MEM_AffMask 0x003f /* Mask of affinity bits */ #define MEM_Frame 0x0080 /* Value is a VdbeFrame object */ #define MEM_Undefined 0x0100 /* Value is undefined */ @@ -378,6 +380,7 @@ struct Vdbe { i64 nFkConstraint; /* Number of imm. FK constraints this VM = */ i64 nStmtDefCons; /* Number of def. constraints when stmt = started */ i64 nStmtDefImmCons; /* Number of def. imm constraints when = stmt started */ + uint32_t schema_ver; /* Schema version at the moment of VDBE = creation. */ =20 /* * In recursive triggers we can execute INSERT/UPDATE OR IGNORE diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c index 92bf9943b..37a3c90d2 100644 --- a/src/box/sql/vdbeaux.c +++ b/src/box/sql/vdbeaux.c @@ -66,6 +66,7 @@ sqlite3VdbeCreate(Parse * pParse) p->magic =3D VDBE_MAGIC_INIT; p->pParse =3D pParse; p->autoCommit =3D (char)box_txn() =3D=3D 0 ? 1 : 0; + p->schema_ver =3D box_schema_version(); if (!p->autoCommit) { p->psql_txn =3D in_txn()->psql_txn; p->nDeferredCons =3D p->psql_txn->nDeferredConsSave; @@ -413,6 +414,16 @@ sqlite3VdbeAddOp4Int(Vdbe * p, /* Add the = opcode to this VM */ return addr; } =20 +int +sqlite3VdbeAddOp4Ptr(Vdbe *p, int op, int p1, int p2, int p3, void = *ptr) +{ + int addr =3D sqlite3VdbeAddOp3(p, op, p1, p2, p3); + VdbeOp *pOp =3D &p->aOp[addr]; + pOp->p4type =3D P4_PTR; + pOp->p4.p =3D ptr; + return addr; +} + /* Insert the end of a co-routine */ void diff --git a/src/box/sql/where.c b/src/box/sql/where.c index 2f1c627e5..47da3c84c 100644 --- a/src/box/sql/where.c +++ b/src/box/sql/where.c @@ -42,6 +42,8 @@ #include "vdbeInt.h" #include "whereInt.h" #include "box/session.h" +#include "box/schema.h" +#include "tarantoolInt.h" =20 /* Forward declaration of methods */ static int whereLoopResize(sqlite3 *, WhereLoop *, int); @@ -4606,7 +4608,15 @@ sqlite3WhereBegin(Parse * pParse, /* The = parser context */ assert(pIx->pSchema =3D=3D pTab->pSchema); assert(iIndexCur >=3D 0); if (op) { - sqlite3VdbeAddOp2(v, op, iIndexCur, = pIx->tnum); + struct space *space =3D + = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIx->tnum)); + assert(space !=3D NULL); + int space_ptr_reg =3D ++pParse->nMem; + sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, + space_ptr_reg, 0, + (void *) space); + sqlite3VdbeAddOp3(v, op, iIndexCur, = pIx->tnum, + space_ptr_reg); sqlite3VdbeSetP4KeyInfo(pParse, pIx); if ((pLoop->wsFlags & WHERE_CONSTRAINT) = !=3D 0 && (pLoop-> --Apple-Mail=_F6035853-4E10-4750-88F4-F96E79F71D66 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=utf-8
On 21 Mar 2018, at 16:14, Kirill Yukhin <kyukhin@tarantool.org> wrote:

Hello,
My comments inlined.
On 21 =D0=BC=D0=B0=D1=80 02:48, Nikita Pettik = wrote:
Originally in SQLite, to open table (i.e. btree) it was = required to pass
number of page root to OP_OpenRead or = OP_OpenWrite opcodes as an
argument. However, now there = are only Tarantool spaces and nothing
prevents from = operating directly on pointers to them. On the other hand,
pointers are able to expire after schema changes (i.e. after = DML
routine). For this reason, schema version is saved to = VDBE at compile
time and checked each time during cursor = opening.

Part of #3252
---
src/box/sql/analyze.c | 17 +++++++++++++++--
src/box/sql/build.c   |  7 ++++++-
src/box/sql/expr.c    | 14 ++++++++++++--
src/box/sql/fkey.c    | 11 ++++++++++-
src/box/sql/insert.c  | 37 = ++++++++++++++++++++++++++++++++-----
src/box/sql/select.c =  | 11 ++++++++++-
src/box/sql/vdbe.c =    | 12 ++++++++++--
src/box/sql/vdbe.h =    |  1 +
src/box/sql/vdbeInt.h | =  1 +
src/box/sql/vdbeaux.c | 13 +++++++++++++
src/box/sql/where.c   | 12 +++++++++++-
11 files changed, 121 insertions(+), 15 deletions(-)

diff --git a/src/box/sql/analyze.c = b/src/box/sql/analyze.c
index db06d0182..57fc33c70 = 100644
diff --git a/src/box/sql/vdbe.c = b/src/box/sql/vdbe.c
index 9929dfb96..5d1227afa 100644
--- a/src/box/sql/vdbe.c
+++ = b/src/box/sql/vdbe.c
@@ -3217,9 +3217,17 @@ case = OP_OpenWrite:

assert(p2 >=3D 1);
= pBtCur =3D pCur->uc.pCursor;
- = pBtCur->space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(p2));
+ if = (box_schema_version() =3D=3D p->schema_ver) {
+ pIn3 =3D = &aMem[pOp->p3];
+ /* Make sure that 64-bit pointer = can fit into int64_t. */
+ assert(sizeof(pBtCur->space) = >=3D sizeof(pIn3->u.i));
I don't like this. If we're = going to extensively use pointers space/index then
let's extend Memory struct adding dedicated = types to the union.
Note, that new opcode (say, = LoadPtr) will be needed.

Done. 


+ = pBtCur->space =3D ((struct space *) pIn3->u.i);
+ = } else {
+ pBtCur->space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(p2));
+ }
Don't surround single stmt withcurly = braces pls.

"Do not unnecessarily use braces where a single statement = will do."

So, I guess, both variants are = allowed. 

Also, if schema was changed then = error should be returned (stmt expired or
smth).

I have dedicated = separate patch (the last one) for this issue.
It can=E2=80=99t = be done right here since new DDL processing is also
introduced = in next patch. In order to make no confusions,
I will remove = this diff and place it to the last patch.


diff --git = a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index = 7241963e4..a1ecf729d 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
diff --git = a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index = 8b622de5b..99262ab7b 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -378,6 +378,7 @@ = struct Vdbe {
i64 nFkConstraint; /* Number = of imm. FK constraints this VM */
i64 = nStmtDefCons; = /* Number of def. constraints when stmt started */
= i64 nStmtDefImmCons; /* Number of def. imm constraints = when stmt started */
+ uint32_t schema_ver; /* Schema = version at the moment of VDBE creation. */

= /*
 * In recursive triggers we = can execute INSERT/UPDATE OR IGNORE
diff --git = a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index = 92bf9943b..b35d0712e 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -66,6 +66,7 @@ = sqlite3VdbeCreate(Parse * pParse)
= p->magic =3D VDBE_MAGIC_INIT;
= p->pParse =3D pParse;
= p->autoCommit =3D (char)box_txn() =3D=3D 0 ? 1 : 0;
+ = p->schema_ver =3D box_schema_version();
if = (!p->autoCommit) {
p->psql_txn =3D = in_txn()->psql_txn;
p->nDeferredCons =3D = p->psql_txn->nDeferredConsSave;
@@ -413,6 +414,18 @@ = sqlite3VdbeAddOp4Int(Vdbe * p, /* Add the opcode to this VM = */
return addr;
}

+int
+sqlite3VdbeAddOp4Int64(Vdbe *p, int op, = int p1, int p2, int p3, int64_t p4)
+{
+ int addr = =3D sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ VdbeOp = *pOp =3D &p->aOp[addr];
+ = pOp->p4type =3D P4_INT64;
+ = pOp->p4.pI64 =3D sqlite3DbMallocRawNN(sqlite3VdbeDb(p), = sizeof(int64_t));
+ if (p->db->mallocFailed =3D=3D= 0)
+ *pOp->p4.pI64 =3D p4;
+ return = addr;
+}
This is useless if LoadPTR will = be introduced.

Done.

The = whole patch is = below:
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D

Originally in SQLite, to = open table (i.e. btree) it was required to pass
number of page = root to OP_OpenRead or OP_OpenWrite opcodes as an
argument. = However, now there are only Tarantool spaces and = nothing
prevents from operating directly on pointers to them. = Thus, to pass
pointers from compile time to runtime, opcode = OP_LoadPtr has been
introduced. It fetches pointer from P4 and = stores to the register
specified by P2.
It is worth = mentioning that, pointers are able to expire after = schema
changes (i.e. after DML routine). For this reason, = schema version is
saved to VDBE at compile time and checked = each time during cursor
opening.

Part of = #3252
---
 src/box/sql/analyze.c |  17 = +++++-
 src/box/sql/build.c   |   7 = ++-
 src/box/sql/expr.c    |  14 = ++++-
 src/box/sql/fkey.c    |  11 = +++-
 src/box/sql/insert.c  |  36 = ++++++++++--
 src/box/sql/opcodes.c | 137 = +++++++++++++++++++++----------------------
 src/box/sql/op= codes.h | 157 = +++++++++++++++++++++++++-------------------------
 src/box= /sql/select.c  |  11 +++-
 src/box/sql/vdbe.c =    |  13 +++++
 src/box/sql/vdbe.h   =  |   2 +
 src/box/sql/vdbeInt.h |   3 = +
 src/box/sql/vdbeaux.c |  11 = ++++
 src/box/sql/where.c   |  12 = +++-
 13 files changed, 272 insertions(+), 159 = deletions(-)

diff --git = a/src/box/sql/analyze.c b/src/box/sql/analyze.c
index = db06d0182..d121dd2b9 100644
--- = a/src/box/sql/analyze.c
+++ = b/src/box/sql/analyze.c
@@ -174,10 +174,16 @@ = openStatTable(Parse * pParse, /* Parsing context = */
 
  /* Open the sql_stat[134] tables = for writing. */
  for (i =3D 0; aTable[i]; i++) = {
+ = struct space *space =3D
+ = space_by_id(SQLITE_PAGENO_TO_SPACEID(aRoot[i]));
+ = assert(space !=3D NULL);
+ int space_ptr_reg =3D = ++pParse->nMem;
+ sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, space_ptr_reg, 0,
+   =   (void *) space);
  int = addr;
  addr = =3D
    =  sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur + i, = aRoot[i],
-   =    0);
+   =    space_ptr_reg);
  = v->aOp[addr].p4.pKeyInfo =3D 0;
  = v->aOp[addr].p4type =3D P4_KEYINFO;
  = sqlite3VdbeChangeP5(v, aCreateTbl[i]);
@@ -814,6 +820,7 = @@ analyzeOneTable(Parse * pParse, /* Parser context = */
  int iTabCur; = /* Table cursor */
  Vdbe *v; = /* The virtual machine being built up */
  int = i; = /* Loop counter */
+ int space_ptr_reg =3D = iMem++;
  int regStat4 =3D iMem++; /* = Register to hold Stat4Accum object */
  int = regChng =3D iMem++; /* Index of changed index field = */
  int regKey =3D iMem++; /* Key = argument passed to stat_push() */
@@ -910,7 +917,13 @@ = analyzeOneTable(Parse * pParse, /* Parser context = */
 
  /* Open a read-only = cursor on the index being analyzed. */
  = assert(sqlite3SchemaToIndex(db, pIdx->pSchema) =3D=3D = 0);
- = sqlite3VdbeAddOp2(v, OP_OpenRead, iIdxCur, = pIdx->tnum);
+ struct space *space = =3D
+ = = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
+ = assert(space !=3D NULL);
+ sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, space_ptr_reg, 0,
+   =   (void *) space);
+ sqlite3VdbeAddOp3(v, = OP_OpenRead, iIdxCur, pIdx->tnum,
+ =  space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  = VdbeComment((v, "%s", = pIdx->zName));
 
diff --git = a/src/box/sql/build.c b/src/box/sql/build.c
index = 9ad0c0605..9cdfd0b7a 100644
--- = a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ = -2603,7 +2603,12 @@ sqlite3RefillIndex(Parse * pParse, Index * pIndex, = int memRootPage)
  sqlite3VdbeJumpHere(v, = addr1);
  if (memRootPage < = 0)
  sqlite3VdbeAddOp2(v, = OP_Clear, tnum, 0);
- sqlite3VdbeAddOp4(v, = OP_OpenWrite, iIdx, tnum, 0,
+ struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(tnum));
+ = assert(space !=3D NULL);
+ int space_ptr_reg =3D = ++pParse->nMem;
+ sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, space_ptr_reg, 0,
+     = (void *) space);
+ sqlite3VdbeAddOp4(v, = OP_OpenWrite, iIdx, tnum, space_ptr_reg,
  =  (char *)pKey, P4_KEYINFO);
  = sqlite3VdbeChangeP5(v,
  =    OPFLAG_BULKCSR | ((memRootPage >=3D 0) = ?
diff --git a/src/box/sql/expr.c = b/src/box/sql/expr.c
index b69a176cb..009538095 = 100644
--- a/src/box/sql/expr.c
+++ = b/src/box/sql/expr.c
@@ -35,7 +35,9 @@
  = */
 #include <box/coll.h>
 #include = "sqliteInt.h"
+#include = "tarantoolInt.h"
 #include = "box/session.h"
+#include = "box/schema.h"
 
 /* Forward declarations = */
 static void exprCodeBetween(Parse *, Expr *, = int,
@@ -2586,8 +2588,16 @@ sqlite3FindInIndex(Parse * = pParse, = /* Parsing context */
  = =  pIdx->zName),
  =  P4_DYNAMIC);
 #endif
- = sqlite3VdbeAddOp2(v, OP_OpenRead, iTab,
- =  pIdx->tnum);
+ = struct space *space =3D
+ = = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
+ = assert(space !=3D NULL);
+ = int space_ptr_reg =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0,
+ =       space_ptr_reg, = 0,
+ =       = (void *) space);
+ = sqlite3VdbeAddOp3(v, OP_OpenRead, iTab,
+ =  pIdx->tnum,
+ = =  space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  = VdbeComment((v, "%s", = pIdx->zName));
  = assert(IN_INDEX_INDEX_DESC =3D=3D
diff --git = a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index = 439f38352..77565cb50 100644
--- = a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ = -35,7 +35,9 @@
  */
 #include = <box/coll.h>
 #include = "sqliteInt.h"
+#include = "tarantoolInt.h"
 #include = "box/session.h"
+#include = "box/schema.h"
 
 #ifndef = SQLITE_OMIT_FOREIGN_KEY
 #ifndef = SQLITE_OMIT_TRIGGER
@@ -434,7 +436,14 @@ fkLookupParent(Parse = * pParse, = /* Parse context */
  int regTemp =3D = sqlite3GetTempRange(pParse, nCol);
  = int regRec =3D = sqlite3GetTempReg(pParse);
 
- = sqlite3VdbeAddOp2(v, OP_OpenRead, iCur, = pIdx->tnum);
+ struct space = *space =3D
+ = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIdx->tnum));
+ = assert(space !=3D NULL);
+ int space_ptr_reg = =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_ptr_reg, = 0,
+ =     (void *) = space);
+ = sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, = pIdx->tnum,
+ =  space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  = for (i =3D 0; i < nCol; i++) {
  = sqlite3VdbeAddOp2(v, OP_Copy,
diff --git = a/src/box/sql/insert.c b/src/box/sql/insert.c
index = 54fcca5c9..4f3e2f316 100644
--- = a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ = -34,7 +34,9 @@
  * to handle INSERT statements in = SQLite.
  */
 #include = "sqliteInt.h"
+#include = "tarantoolInt.h"
 #include = "box/session.h"
+#include = "box/schema.h"
 
 /*
  * = Generate code that will open pTab as cursor iCur.
@@ -51,7 = +53,12 @@ sqlite3OpenTable(Parse * pParse, /* Generate code into this VDBE = */
  Index *pPk =3D = sqlite3PrimaryKeyIndex(pTab);
  = assert(pPk !=3D 0);
  assert(pPk->tnum =3D=3D = pTab->tnum);
- sqlite3VdbeAddOp3(v, opcode, = iCur, pPk->tnum, 0);
+ struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(pPk->tnum));
+ = assert(space !=3D NULL);
+ int space_ptr_reg =3D = ++pParse->nMem;
+ sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, space_ptr_reg, 0,
+     = (void *) space);
+ sqlite3VdbeAddOp3(v, opcode, = iCur, pPk->tnum, space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pPk);
  = VdbeComment((v, "%s", = pTab->zName));
 }
@@ -183,7 +190,7 @@ = readsTable(Parse * p, Table * pTab)
  for (i =3D = 1; i < iEnd; i++) {
  VdbeOp *pOp =3D = sqlite3VdbeGetOp(v, i);
  assert(pOp !=3D = 0);
- = if (pOp->opcode =3D=3D OP_OpenRead && = pOp->p3 =3D=3D 0) {
+ if (pOp->opcode =3D=3D = OP_OpenRead) {
  Index = *pIndex;
  int tnum =3D = pOp->p2;
  if (tnum =3D=3D = pTab->tnum) {
@@ -1560,6 +1567,10 @@ = sqlite3OpenTableAndIndices(Parse * pParse, /* Parsing context = */
  *piDataCur =3D = iDataCur;
  if = (piIdxCur)
  *piIdxCur =3D = iBase;
+ struct space *space =3D = space_by_id(SQLITE_PAGENO_TO_SPACEID(pTab->tnum));
+ = assert(space !=3D NULL);
+ int space_ptr_reg =3D = ++pParse->nMem;
+ sqlite3VdbeAddOp4Ptr(v, = OP_LoadPtr, 0, space_ptr_reg, 0, (void *) = space);
 
  /* One iteration of this cycle = adds OpenRead/OpenWrite which
  * opens = cursor for current index.
@@ -1607,7 +1618,8 @@ = sqlite3OpenTableAndIndices(Parse * pParse, /* Parsing context = */
  p5 =3D = 0;
  = }
  if (aToOpen =3D=3D = 0 || aToOpen[i + 1]) {
- = sqlite3VdbeAddOp2(v, op, iIdxCur, = pIdx->tnum);
+ = sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum,
+ =  space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
  = sqlite3VdbeChangeP5(v, p5);
  = VdbeComment((v, "%s", pIdx->zName));
@@ -1911,10 = +1923,24 @@ xferOptimization(Parse * pParse, /* Parser context = */
  = break;
  }
  = assert(pSrcIdx);
- sqlite3VdbeAddOp2(v, = OP_OpenRead, iSrc, pSrcIdx->tnum);
+ = struct space *space_src =3D
+ = space_by_id(SQLITE_PAGENO_TO_SPACEID(pSrcIdx->tnum));
= + = assert(space_src !=3D NULL);
+ = int space_src_ptr_reg =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_src_ptr_reg, = 0,
+ =     (void *) = space_src);
+ sqlite3VdbeAddOp3(v, = OP_OpenRead, iSrc, pSrcIdx->tnum,
+ =  space_src_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx);
  = VdbeComment((v, "%s", pSrcIdx->zName));
- = sqlite3VdbeAddOp2(v, OP_OpenWrite, iDest, = pDestIdx->tnum);
+ struct space *space_dest = =3D
+ = = space_by_id(SQLITE_PAGENO_TO_SPACEID(pDestIdx->tnum));
+ = assert(space_dest !=3D NULL);
+ = int space_dest_ptr_reg =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0, space_dest_ptr_reg, = 0,
+ =     (void *) = space_dest);
+ sqlite3VdbeAddOp3(v, = OP_OpenWrite, iDest, pDestIdx->tnum,
+ =  space_dest_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx);
  = sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
  = VdbeComment((v, "%s", pDestIdx->zName));
diff --git = a/src/box/sql/opcodes.c b/src/box/sql/opcodes.c
index = 7a40b28a8..b108d5f9e 100644
--- = a/src/box/sql/opcodes.c
+++ = b/src/box/sql/opcodes.c
@@ -78,76 +78,77 @@ const char = *sqlite3OpcodeName(int i){
     /*  64 */ = "Integer"         =  OpHelp("r[P2]=3DP1"),
     /*  65 */ = "Bool"             = OpHelp("r[P2]=3DP1"),
     /*  66 */ = "Int64"           =  OpHelp("r[P2]=3DP4"),
-    /*  67 */ = "String"           OpHelp("r[P2]=3D'P4' = (len=3DP1)"),
-    /*  68 */ "Null"   =           OpHelp("r[P2..P3]=3DNULL"),
-=    /*  69 */ "SoftNull"         = OpHelp("r[P1]=3DNULL"),
-    /*  70 */ "Blob" =             OpHelp("r[P2]=3DP4 (len=3DP1, = subtype=3DP3)"),
-    /*  71 */ "Variable" =         = OpHelp("r[P2]=3Dparameter(P1,P4)"),
-    /*  72 = */ "Move"             = OpHelp("r[P2@P3]=3Dr[P1@P3]"),
-    /*  73 */ = "Copy"             = OpHelp("r[P2@P3+1]=3Dr[P1@P3+1]"),
-    /*  74 = */ "SCopy"           =  OpHelp("r[P2]=3Dr[P1]"),
+    /*  67 */ = "LoadPtr"          OpHelp("r[P2] =3D = P4"),
+    /*  68 */ "String"     =       OpHelp("r[P2]=3D'P4' (len=3DP1)"),
+ =    /*  69 */ "Null"           =   OpHelp("r[P2..P3]=3DNULL"),
+    /*  70 = */ "SoftNull"         = OpHelp("r[P1]=3DNULL"),
+    /*  71 */ "Blob" =             OpHelp("r[P2]=3DP4 (len=3DP1, = subtype=3DP3)"),
+    /*  72 */ "Variable" =         = OpHelp("r[P2]=3Dparameter(P1,P4)"),
+    /*  73 = */ "Move"             = OpHelp("r[P2@P3]=3Dr[P1@P3]"),
+    /*  74 */ = "Copy"             = OpHelp("r[P2@P3+1]=3Dr[P1@P3+1]"),
     /* =  75 */ "String8"         =  OpHelp("r[P2]=3D'P4'"),
-    /*  76 */ = "IntCopy"         =  OpHelp("r[P2]=3Dr[P1]"),
-    /*  77 */ = "ResultRow"       =  OpHelp("output=3Dr[P1@P2]"),
-    /*  78 = */ "CollSeq"          OpHelp(""),
- =    /*  79 */ "Function0"       =  OpHelp("r[P3]=3Dfunc(r[P2@P5])"),
-    /* =  80 */ "Function"         = OpHelp("r[P3]=3Dfunc(r[P2@P5])"),
-    /*  81 = */ "AddImm"           = OpHelp("r[P1]=3Dr[P1]+P2"),
-    /*  82 */ = "RealAffinity"     OpHelp(""),
-    /* =  83 */ "Cast"             = OpHelp("affinity(r[P1])"),
-    /*  84 */ = "Permutation"      OpHelp(""),
-   =  /*  85 */ "Compare"         =  OpHelp("r[P1@P3] <-> r[P2@P3]"),
-    /* =  86 */ "Column"           = OpHelp("r[P3]=3DPX"),
-    /*  87 */ "Affinity" =         OpHelp("affinity(r[P1@P2])"),
- =    /*  88 */ "MakeRecord"       = OpHelp("r[P3]=3Dmkrec(r[P1@P2])"),
-    /*  89 = */ "Count"           =  OpHelp("r[P2]=3Dcount()"),
-    /*  90 */ = "FkCheckCommit"    OpHelp(""),
-    /* =  91 */ "TTransaction"     OpHelp(""),
-   =  /*  92 */ "ReadCookie"       = OpHelp(""),
-    /*  93 */ "SetCookie"   =      OpHelp(""),
-    /*  94 */ = "ReopenIdx"        OpHelp("root=3DP2"),
- =    /*  95 */ "OpenRead"         = OpHelp("root=3DP2"),
-    /*  96 */ "OpenWrite" =        OpHelp("root=3DP2"),
-   =  /*  97 */ "OpenTEphemeral"   OpHelp("nColumn =3D = P2"),
-    /*  98 */ "SorterOpen"     =   OpHelp(""),
-    /*  99 */ = "SequenceTest"     OpHelp("if (cursor[P1].ctr++) pc =3D = P2"),
-    /* 100 */ "OpenPseudo"     =   OpHelp("P3 columns in r[P2]"),
-    /* 101 */ = "Close"            OpHelp(""),
- =    /* 102 */ "ColumnsUsed"     =  OpHelp(""),
-    /* 103 */ "Sequence"   =       OpHelp("r[P2]=3Dcursor[P1].ctr++"),
- =    /* 104 */ "NextId"           = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"),
- =    /* 105 */ "NextIdEphemeral" =  OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"),
- =    /* 106 */ "FCopy"           =  OpHelp("reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)]"),
-    /* 107 = */ "Delete"           OpHelp(""),
- =    /* 108 */ "ResetCount"       = OpHelp(""),
-    /* 109 */ "SorterCompare"   =  OpHelp("if key(P1)!=3Dtrim(r[P3],P4) goto P2"),
-   =  /* 110 */ "SorterData"       = OpHelp("r[P2]=3Ddata"),
-    /* 111 */ "RowData" =          OpHelp("r[P2]=3Ddata"),
- =    /* 112 */ "NullRow"         =  OpHelp(""),
-    /* 113 */ "SorterInsert" =     OpHelp("key=3Dr[P2]"),
-    /* 114 */ = "IdxReplace"       OpHelp("key=3Dr[P2]"),
+ =    /*  76 */ "SCopy"           =  OpHelp("r[P2]=3Dr[P1]"),
+    /*  77 */ = "IntCopy"         =  OpHelp("r[P2]=3Dr[P1]"),
+    /*  78 */ = "ResultRow"       =  OpHelp("output=3Dr[P1@P2]"),
+    /*  79 = */ "CollSeq"          OpHelp(""),
+ =    /*  80 */ "Function0"       =  OpHelp("r[P3]=3Dfunc(r[P2@P5])"),
+    /* =  81 */ "Function"         = OpHelp("r[P3]=3Dfunc(r[P2@P5])"),
+    /*  82 = */ "AddImm"           = OpHelp("r[P1]=3Dr[P1]+P2"),
+    /*  83 */ = "RealAffinity"     OpHelp(""),
+    /* =  84 */ "Cast"             = OpHelp("affinity(r[P1])"),
+    /*  85 */ = "Permutation"      OpHelp(""),
+   =  /*  86 */ "Compare"         =  OpHelp("r[P1@P3] <-> r[P2@P3]"),
+    /* =  87 */ "Column"           = OpHelp("r[P3]=3DPX"),
+    /*  88 */ "Affinity" =         OpHelp("affinity(r[P1@P2])"),
+ =    /*  89 */ "MakeRecord"       = OpHelp("r[P3]=3Dmkrec(r[P1@P2])"),
+    /*  90 = */ "Count"           =  OpHelp("r[P2]=3Dcount()"),
+    /*  91 */ = "FkCheckCommit"    OpHelp(""),
+    /* =  92 */ "TTransaction"     OpHelp(""),
+   =  /*  93 */ "ReadCookie"       = OpHelp(""),
+    /*  94 */ "SetCookie"   =      OpHelp(""),
+    /*  95 */ = "ReopenIdx"        OpHelp("root=3DP2"),
+ =    /*  96 */ "OpenRead"         = OpHelp("root=3DP2"),
+    /*  97 */ "OpenWrite" =        OpHelp("root=3DP2"),
+   =  /*  98 */ "OpenTEphemeral"   OpHelp("nColumn =3D = P2"),
+    /*  99 */ "SorterOpen"     =   OpHelp(""),
+    /* 100 */ "SequenceTest" =     OpHelp("if (cursor[P1].ctr++) pc =3D P2"),
+ =    /* 101 */ "OpenPseudo"       OpHelp("P3 = columns in r[P2]"),
+    /* 102 */ "Close"   =          OpHelp(""),
+   =  /* 103 */ "ColumnsUsed"     =  OpHelp(""),
+    /* 104 */ "Sequence"   =       OpHelp("r[P2]=3Dcursor[P1].ctr++"),
+ =    /* 105 */ "NextId"           = OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"),
+ =    /* 106 */ "NextIdEphemeral" =  OpHelp("r[P3]=3Dget_max(space_index[P1]{Column[P2]})"),
+ =    /* 107 */ "FCopy"           =  OpHelp("reg[P2@cur_frame]=3D = reg[P1@root_frame(OPFLAG_SAME_FRAME)]"),
+    /* 108 = */ "Delete"           OpHelp(""),
+ =    /* 109 */ "ResetCount"       = OpHelp(""),
+    /* 110 */ "SorterCompare"   =  OpHelp("if key(P1)!=3Dtrim(r[P3],P4) goto P2"),
+   =  /* 111 */ "SorterData"       = OpHelp("r[P2]=3Ddata"),
+    /* 112 */ "RowData" =          OpHelp("r[P2]=3Ddata"),
+ =    /* 113 */ "NullRow"         =  OpHelp(""),
+    /* 114 */ "SorterInsert" =     OpHelp("key=3Dr[P2]"),
     /* = 115 */ "Real"             = OpHelp("r[P2]=3DP4"),
-    /* 116 */ "IdxInsert" =        OpHelp("key=3Dr[P2]"),
-   =  /* 117 */ "IdxDelete"       =  OpHelp("key=3Dr[P2@P3]"),
-    /* 118 */ = "Clear"            OpHelp("space id =3D = P1"),
-    /* 119 */ "ResetSorter"     =  OpHelp(""),
-    /* 120 */ "ParseSchema2" =     OpHelp("rows=3Dr[P1@P2]"),
-    /* 121 = */ "ParseSchema3"     OpHelp("name=3Dr[P1] = sql=3Dr[P1+1]"),
-    /* 122 */ "RenameTable"   =    OpHelp("P1 =3D root, P4 =3D name"),
-   =  /* 123 */ "LoadAnalysis"     OpHelp(""),
- =    /* 124 */ "DropTable"       =  OpHelp(""),
-    /* 125 */ "DropIndex"   =      OpHelp(""),
-    /* 126 */ = "DropTrigger"      OpHelp(""),
-   =  /* 127 */ "Param"           =  OpHelp(""),
-    /* 128 */ "FkCounter"   =      OpHelp("fkctr[P1]+=3DP2"),
-   =  /* 129 */ "OffsetLimit"      OpHelp("if r[P1]>0 = then r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1)"),
-   =  /* 130 */ "AggStep0"         = OpHelp("accum=3Dr[P3] step(r[P2@P5])"),
-    /* 131 = */ "AggStep"          OpHelp("accum=3Dr[P3] = step(r[P2@P5])"),
-    /* 132 */ "AggFinal"   =       OpHelp("accum=3Dr[P1] N=3DP2"),
-   =  /* 133 */ "Expire"           = OpHelp(""),
-    /* 134 */ "IncMaxid"     =     OpHelp(""),
-    /* 135 */ "Noop" =             OpHelp(""),
-   =  /* 136 */ "Explain"         =  OpHelp(""),
+    /* 116 */ "IdxReplace"   =     OpHelp("key=3Dr[P2]"),
+    /* 117 */ = "IdxInsert"        OpHelp("key=3Dr[P2]"),
+ =    /* 118 */ "IdxDelete"       =  OpHelp("key=3Dr[P2@P3]"),
+    /* 119 */ = "Clear"            OpHelp("space id =3D = P1"),
+    /* 120 */ "ResetSorter"     =  OpHelp(""),
+    /* 121 */ "ParseSchema2" =     OpHelp("rows=3Dr[P1@P2]"),
+    /* 122 = */ "ParseSchema3"     OpHelp("name=3Dr[P1] = sql=3Dr[P1+1]"),
+    /* 123 */ "RenameTable"   =    OpHelp("P1 =3D root, P4 =3D name"),
+   =  /* 124 */ "LoadAnalysis"     OpHelp(""),
+ =    /* 125 */ "DropTable"       =  OpHelp(""),
+    /* 126 */ "DropIndex"   =      OpHelp(""),
+    /* 127 */ = "DropTrigger"      OpHelp(""),
+   =  /* 128 */ "Param"           =  OpHelp(""),
+    /* 129 */ "FkCounter"   =      OpHelp("fkctr[P1]+=3DP2"),
+   =  /* 130 */ "OffsetLimit"      OpHelp("if r[P1]>0 = then r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1)"),
+   =  /* 131 */ "AggStep0"         = OpHelp("accum=3Dr[P3] step(r[P2@P5])"),
+    /* 132 = */ "AggStep"          OpHelp("accum=3Dr[P3] = step(r[P2@P5])"),
+    /* 133 */ "AggFinal"   =       OpHelp("accum=3Dr[P1] N=3DP2"),
+   =  /* 134 */ "Expire"           = OpHelp(""),
+    /* 135 */ "IncMaxid"     =     OpHelp(""),
+    /* 136 */ "Noop" =             OpHelp(""),
+   =  /* 137 */ "Explain"         =  OpHelp(""),
   };
  =  return azName[i];
 }
diff --git = a/src/box/sql/opcodes.h b/src/box/sql/opcodes.h
index = af2ba1963..7b62f6d80 100644
--- = a/src/box/sql/opcodes.h
+++ = b/src/box/sql/opcodes.h
@@ -67,76 +67,77 = @@
 #define OP_Integer        64 /* = synopsis: r[P2]=3DP1               =           */
 #define OP_Bool =           65 /* synopsis: r[P2]=3DP1   =                     =   */
 #define OP_Int64         =  66 /* synopsis: r[P2]=3DP4           =               */
-#define = OP_String         67 /* synopsis: r[P2]=3D'P4' = (len=3DP1)             =  */
-#define OP_Null           = 68 /* synopsis: r[P2..P3]=3DNULL           =         */
-#define OP_SoftNull   =     69 /* synopsis: r[P1]=3DNULL         =               */
-#define = OP_Blob           70 /* synopsis: r[P2]=3DP4 = (len=3DP1, subtype=3DP3)    */
-#define OP_Variable =       71 /* synopsis: r[P2]=3Dparameter(P1,P4)   =         */
-#define OP_Move     =       72 /* synopsis: r[P2@P3]=3Dr[P1@P3]     =            */
-#define OP_Copy =           73 /* synopsis: r[P2@P3+1]=3Dr[P1@P3+1]=            */
-#define OP_SCopy =          74 /* synopsis: r[P2]=3Dr[P1]   =                   =  */
+#define OP_LoadPtr        67 /* = synopsis: r[P2] =3D P4               =         */
+#define OP_String   =       68 /* synopsis: r[P2]=3D'P4' (len=3DP1)   =            */
+#define OP_Null =           69 /* synopsis: r[P2..P3]=3DNULL =                   = */
+#define OP_SoftNull       70 /* synopsis: = r[P1]=3DNULL                 =       */
+#define OP_Blob       =     71 /* synopsis: r[P2]=3DP4 (len=3DP1, subtype=3DP3)   =  */
+#define OP_Variable       72 /* = synopsis: r[P2]=3Dparameter(P1,P4)           = */
+#define OP_Move           73 /* = synopsis: r[P2@P3]=3Dr[P1@P3]             =    */
+#define OP_Copy         =   74 /* synopsis: r[P2@P3+1]=3Dr[P1@P3+1]       =      */
 #define OP_String8     =    75 /* same as TK_STRING, synopsis: r[P2]=3D'P4'   =  */
-#define OP_IntCopy        76 /* = synopsis: r[P2]=3Dr[P1]               =        */
-#define OP_ResultRow   =    77 /* synopsis: output=3Dr[P1@P2]       =            */
-#define = OP_CollSeq        78
-#define OP_Function0 =      79 /* synopsis: r[P3]=3Dfunc(r[P2@P5])     =         */
-#define OP_Function   =     80 /* synopsis: r[P3]=3Dfunc(r[P2@P5])     =         */
-#define OP_AddImm   =       81 /* synopsis: r[P1]=3Dr[P1]+P2     =               */
-#define = OP_RealAffinity   82
-#define OP_Cast     =       83 /* synopsis: affinity(r[P1])     =              */
-#define = OP_Permutation    84
-#define OP_Compare   =      85 /* synopsis: r[P1@P3] <-> r[P2@P3]   =          */
-#define OP_Column   =       86 /* synopsis: r[P3]=3DPX       =                   = */
-#define OP_Affinity       87 /* synopsis: = affinity(r[P1@P2])               = */
-#define OP_MakeRecord     88 /* synopsis: = r[P3]=3Dmkrec(r[P1@P2])           =  */
-#define OP_Count         =  89 /* synopsis: r[P2]=3Dcount()           =          */
-#define OP_FkCheckCommit =  90
-#define OP_TTransaction   91
-#define = OP_ReadCookie     92
-#define OP_SetCookie   =    93
-#define OP_ReopenIdx      94 = /* synopsis: root=3DP2               =            */
-#define = OP_OpenRead       95 /* synopsis: root=3DP2     =                     =  */
-#define OP_OpenWrite      96 /* = synopsis: root=3DP2               =            */
-#define = OP_OpenTEphemeral  97 /* synopsis: nColumn =3D P2     =                 = */
-#define OP_SorterOpen     98
-#define = OP_SequenceTest   99 /* synopsis: if (cursor[P1].ctr++) pc =3D P2 =    */
-#define OP_OpenPseudo    100 /* = synopsis: P3 columns in r[P2]             =  */
-#define OP_Close         = 101
-#define OP_ColumnsUsed   102
-#define = OP_Sequence      103 /* synopsis: r[P2]=3Dcursor[P1].ctr++ =           */
-#define OP_NextId =        104 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */
-#define = OP_NextIdEphemeral 105 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */
-#define = OP_FCopy         106 /* synopsis: reg[P2@cur_frame]=3D= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */
-#define OP_Delete =        107
-#define OP_ResetCount   =  108
-#define OP_SorterCompare 109 /* synopsis: if = key(P1)!=3Dtrim(r[P3],P4) goto P2 */
-#define OP_SorterData =    110 /* synopsis: r[P2]=3Ddata         =               */
-#define = OP_RowData       111 /* synopsis: r[P2]=3Ddata   =                     = */
-#define OP_NullRow       = 112
-#define OP_SorterInsert  113 /* synopsis: key=3Dr[P2] =                     =    */
-#define OP_IdxReplace    114 /* = synopsis: key=3Dr[P2]               =          */
+#define OP_SCopy   =        76 /* synopsis: r[P2]=3Dr[P1]     =                 =  */
+#define OP_IntCopy        77 /* = synopsis: r[P2]=3Dr[P1]               =        */
+#define OP_ResultRow   =    78 /* synopsis: output=3Dr[P1@P2]       =            */
+#define = OP_CollSeq        79
+#define OP_Function0 =      80 /* synopsis: r[P3]=3Dfunc(r[P2@P5])     =         */
+#define OP_Function   =     81 /* synopsis: r[P3]=3Dfunc(r[P2@P5])     =         */
+#define OP_AddImm   =       82 /* synopsis: r[P1]=3Dr[P1]+P2     =               */
+#define = OP_RealAffinity   83
+#define OP_Cast     =       84 /* synopsis: affinity(r[P1])     =              */
+#define = OP_Permutation    85
+#define OP_Compare   =      86 /* synopsis: r[P1@P3] <-> r[P2@P3]   =          */
+#define OP_Column   =       87 /* synopsis: r[P3]=3DPX       =                   = */
+#define OP_Affinity       88 /* synopsis: = affinity(r[P1@P2])               = */
+#define OP_MakeRecord     89 /* synopsis: = r[P3]=3Dmkrec(r[P1@P2])           =  */
+#define OP_Count         =  90 /* synopsis: r[P2]=3Dcount()           =          */
+#define OP_FkCheckCommit =  91
+#define OP_TTransaction   92
+#define = OP_ReadCookie     93
+#define OP_SetCookie   =    94
+#define OP_ReopenIdx      95 = /* synopsis: root=3DP2               =            */
+#define = OP_OpenRead       96 /* synopsis: root=3DP2     =                     =  */
+#define OP_OpenWrite      97 /* = synopsis: root=3DP2               =            */
+#define = OP_OpenTEphemeral  98 /* synopsis: nColumn =3D P2     =                 = */
+#define OP_SorterOpen     99
+#define = OP_SequenceTest  100 /* synopsis: if (cursor[P1].ctr++) pc =3D P2 =    */
+#define OP_OpenPseudo    101 /* = synopsis: P3 columns in r[P2]             =  */
+#define OP_Close         = 102
+#define OP_ColumnsUsed   103
+#define = OP_Sequence      104 /* synopsis: r[P2]=3Dcursor[P1].ctr++ =           */
+#define OP_NextId =        105 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */
+#define = OP_NextIdEphemeral 106 /* synopsis: = r[P3]=3Dget_max(space_index[P1]{Column[P2]}) */
+#define = OP_FCopy         107 /* synopsis: reg[P2@cur_frame]=3D= reg[P1@root_frame(OPFLAG_SAME_FRAME)] */
+#define OP_Delete =        108
+#define OP_ResetCount   =  109
+#define OP_SorterCompare 110 /* synopsis: if = key(P1)!=3Dtrim(r[P3],P4) goto P2 */
+#define OP_SorterData =    111 /* synopsis: r[P2]=3Ddata         =               */
+#define = OP_RowData       112 /* synopsis: r[P2]=3Ddata   =                     = */
+#define OP_NullRow       = 113
+#define OP_SorterInsert  114 /* synopsis: key=3Dr[P2] =                     =    */
 #define OP_Real       =    115 /* same as TK_FLOAT, synopsis: r[P2]=3DP4     =   */
-#define OP_IdxInsert     116 /* synopsis: = key=3Dr[P2]                 =        */
-#define OP_IdxDelete   =   117 /* synopsis: key=3Dr[P2@P3]         =             */
-#define OP_Clear =         118 /* synopsis: space id =3D P1   =                 =  */
-#define OP_ResetSorter   119
-#define = OP_ParseSchema2  120 /* synopsis: rows=3Dr[P1@P2]     =               =  */
-#define OP_ParseSchema3  121 /* synopsis: = name=3Dr[P1] sql=3Dr[P1+1]           = */
-#define OP_RenameTable   122 /* synopsis: P1 =3D = root, P4 =3D name             = */
-#define OP_LoadAnalysis  123
-#define = OP_DropTable     124
-#define OP_DropIndex   =   125
-#define OP_DropTrigger   = 126
-#define OP_Param         = 127
-#define OP_FkCounter     128 /* synopsis: = fkctr[P1]+=3DP2                 =    */
-#define OP_OffsetLimit   129 /* = synopsis: if r[P1]>0 then r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1) = */
-#define OP_AggStep0      130 /* synopsis: = accum=3Dr[P3] step(r[P2@P5])       */
-#define = OP_AggStep       131 /* synopsis: accum=3Dr[P3] = step(r[P2@P5])       */
-#define OP_AggFinal =      132 /* synopsis: accum=3Dr[P1] N=3DP2     =             */
-#define = OP_Expire        133
-#define OP_IncMaxid =      134
-#define OP_Noop       =    135
-#define OP_Explain       = 136
+#define OP_IdxReplace    116 /* synopsis: = key=3Dr[P2]                 =        */
+#define OP_IdxInsert   =   117 /* synopsis: key=3Dr[P2]           =              */
+#define = OP_IdxDelete     118 /* synopsis: key=3Dr[P2@P3]     =                 = */
+#define OP_Clear         119 /* = synopsis: space id =3D P1             =        */
+#define OP_ResetSorter   = 120
+#define OP_ParseSchema2  121 /* synopsis: = rows=3Dr[P1@P2]                 =    */
+#define OP_ParseSchema3  122 /* = synopsis: name=3Dr[P1] sql=3Dr[P1+1]           = */
+#define OP_RenameTable   123 /* synopsis: P1 =3D = root, P4 =3D name             = */
+#define OP_LoadAnalysis  124
+#define = OP_DropTable     125
+#define OP_DropIndex   =   126
+#define OP_DropTrigger   = 127
+#define OP_Param         = 128
+#define OP_FkCounter     129 /* synopsis: = fkctr[P1]+=3DP2                 =    */
+#define OP_OffsetLimit   130 /* = synopsis: if r[P1]>0 then r[P2]=3Dr[P1]+max(0,r[P3]) else r[P2]=3D(-1) = */
+#define OP_AggStep0      131 /* synopsis: = accum=3Dr[P3] step(r[P2@P5])       */
+#define = OP_AggStep       132 /* synopsis: accum=3Dr[P3] = step(r[P2@P5])       */
+#define OP_AggFinal =      133 /* synopsis: accum=3Dr[P1] N=3DP2     =             */
+#define = OP_Expire        134
+#define OP_IncMaxid =      135
+#define OP_Noop       =    136
+#define OP_Explain       = 137
 
 /* Properties such as "out2" or = "jump" that are specified in
 ** comments following the = "case" for each opcode in the vdbe.c
@@ -157,16 +158,16 = @@
 /*  40 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, = 0x01, 0x01,\
 /*  48 */ 0x01, 0x01, 0x01, 0x01, = 0x01, 0x01, 0x01, 0x01,\
 /*  56 */ 0x03, 0x03, = 0x03, 0x01, 0x02, 0x02, 0x08, 0x00,\
-/*  64 */ 0x10, = 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10,\
-/*  72 */ = 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,\
-/*  80 = */ 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* =  88 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, = 0x00,\
-/*  96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, = 0x00, 0x10,\
-/* 104 */ 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, = 0x00, 0x00,\
-/* 112 */ 0x00, 0x04, 0x00, 0x10, 0x04, 0x00, = 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, = 0x00, 0x10,\
-/* 128 */ 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, = 0x00, 0x00,\
-/* 136 */ 0x00,}
+/*  64 */ 0x10, = 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x10,\
+/*  72 */ = 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00,\
+/*  80 = */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00,\
+/* =  88 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, = 0x00,\
+/*  96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, = 0x00, 0x00,\
+/* 104 */ 0x10, 0x20, 0x00, 0x10, 0x00, 0x00, = 0x00, 0x00,\
+/* 112 */ 0x00, 0x00, 0x04, 0x10, 0x00, 0x04, = 0x00, 0x00,\
+/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, = 0x00, 0x00,\
+/* 128 */ 0x10, 0x00, 0x1a, 0x00, 0x00, 0x00, = 0x00, 0x00,\
+/* 136 */ 0x00, = 0x00,}
 
 /* The sqlite3P2Values() routine = is able to run faster if it knows
 ** the value of the = largest JUMP opcode.  The smaller the maximum
diff --git = a/src/box/sql/select.c b/src/box/sql/select.c
index = 2a8c83d06..39c1be53d 100644
--- = a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ = -35,7 +35,9 @@
  */
 #include = <box/coll.h>
 #include = "sqliteInt.h"
+#include = "tarantoolInt.h"
 #include = "box/session.h"
+#include = "box/schema.h"
 
 /*
  * = Trace output macros
@@ -6187,8 +6189,15 @@ sqlite3Select(Parse = * pParse, = /* The parser context */
  = }
 
  /* Open a = read-only cursor, execute the OP_Count, close the cursor. = */
+ = struct space *space =3D
+ = = space_by_id(SQLITE_PAGENO_TO_SPACEID(iRoot));
+ = assert(space !=3D NULL);
+ int = space_ptr_reg =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0,
+ =     space_ptr_reg, 0,
+ =     (void *) = space);
  = sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr,
- =     iRoot, 0, 1);
+ =     iRoot, space_ptr_reg, = 1);
  if = (pKeyInfo) {
  = sqlite3VdbeChangeP4(v, -1,
  =    (char = *)pKeyInfo,
diff --git a/src/box/sql/vdbe.c = b/src/box/sql/vdbe.c
index 9929dfb96..a44a17062 = 100644
--- a/src/box/sql/vdbe.c
+++ = b/src/box/sql/vdbe.c
@@ -1072,6 +1072,19 @@ case OP_Int64: { =           /* out2 */
  = break;
 }
 
+/* Opcode: = LoadPtr * P2 * P4 *
+ * Synopsis: r[P2] =3D P4
+ = *
+ * P4 is a generic pointer. Copy it into register = P2.
+ */
+case OP_LoadPtr: {
+ pOut =3D = out2Prerelease(p, pOp);
+ assert(pOp->p4type =3D=3D = P4_PTR);
+ pOut->u.p =3D = pOp->p4.p;
+ pOut->flags =3D = MEM_Ptr;
+ = break;
+}
+
 #ifndef = SQLITE_OMIT_FLOATING_POINT
 /* Opcode: Real * P2 * P4 = *
  * Synopsis: r[P2]=3DP4
diff --git = a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index = 7241963e4..340ddc766 100644
--- = a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ = -144,6 +144,7 @@ typedef struct VdbeOpList = VdbeOpList;
 #define P4_INDEX    (-15) /* P4 is = a pointer to a Index structure */
 #define P4_FUNCCTX =  (-16) = /* P4 is a pointer to an sqlite3_context object = */
 #define P4_BOOL     (-17) /* P4 is = a bool value */
+#define P4_PTR      (-18) /* P4 is = a generic pointer = */
 
 
 /* Error message = codes for OP_Halt */
@@ -200,6 +201,7 @@ int = sqlite3VdbeAddOp3(Vdbe *, int, int, int, int);
 int = sqlite3VdbeAddOp4(Vdbe *, int, int, int, int, const char *zP4, = int);
 int sqlite3VdbeAddOp4Dup8(Vdbe *, int, int, int, = int, const u8 *, int);
 int sqlite3VdbeAddOp4Int(Vdbe *, = int, int, int, int, int);
+int sqlite3VdbeAddOp4Ptr(Vdbe *, = int, int, int, int, void *);
 void = sqlite3VdbeEndCoroutine(Vdbe *, int);
 #if = defined(SQLITE_DEBUG) && = !defined(SQLITE_TEST_REALLOC_STRESS)
 void = sqlite3VdbeVerifyNoMallocRequired(Vdbe * p, int N);
diff --git = a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index = 8b622de5b..fcb45c8a8 100644
--- = a/src/box/sql/vdbeInt.h
+++ = b/src/box/sql/vdbeInt.h
@@ -196,6 +196,7 @@ struct Mem = {
  i64 i; = /* Integer value used when MEM_Int is set in flags = */
  bool b;     =     /* Boolean value used when MEM_Bool is set in flags = */
  int nZero; /* Used = when bit MEM_Zero is set in flags */
+ = void *p; = /* Generic pointer */
  = FuncDef *pDef; /* Used only when flags=3D=3DMEM_Ag= g */
  VdbeFrame *pFrame; /* Used = when flags=3D=3DMEM_Frame */
  } = u;
@@ -239,6 +240,7 @@ struct Mem {
 #define = MEM_Real      0x0008 /* Value is a real number = */
 #define MEM_Blob      0x0010 /* Value = is a BLOB */
 #define MEM_Bool      0x0020 =    /* Value is a bool */
+#define MEM_Ptr   =     0x0040 /* Value is a generic pointer = */
 #define MEM_AffMask   0x003f /* Mask = of affinity bits */
 #define MEM_Frame     = 0x0080 = /* Value is a VdbeFrame object */
 #define = MEM_Undefined 0x0100 /* Value is undefined = */
@@ -378,6 +380,7 @@ struct Vdbe {
  i64 = nFkConstraint; = /* Number of imm. FK constraints this VM */
  i64 = nStmtDefCons; = /* Number of def. constraints when stmt started = */
  i64 nStmtDefImmCons; /* Number = of def. imm constraints when stmt started */
+ uint32_t = schema_ver; = /* Schema version at the moment of VDBE creation. = */
 
  /*
  * In = recursive triggers we can execute INSERT/UPDATE OR IGNORE
diff = --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index = 92bf9943b..37a3c90d2 100644
--- = a/src/box/sql/vdbeaux.c
+++ = b/src/box/sql/vdbeaux.c
@@ -66,6 +66,7 @@ = sqlite3VdbeCreate(Parse * pParse)
  = p->magic =3D VDBE_MAGIC_INIT;
  = p->pParse =3D pParse;
  = p->autoCommit =3D (char)box_txn() =3D=3D 0 ? 1 : = 0;
+ = p->schema_ver =3D box_schema_version();
  if = (!p->autoCommit) {
  p->psql_txn =3D = in_txn()->psql_txn;
  p->nDeferredCons =3D = p->psql_txn->nDeferredConsSave;
@@ -413,6 +414,16 @@ = sqlite3VdbeAddOp4Int(Vdbe * p, /* Add the opcode to this VM = */
  return = addr;
 }
 
+int
+sqlite3= VdbeAddOp4Ptr(Vdbe *p, int op, int p1, int p2, int p3, void = *ptr)
+{
+ int addr =3D sqlite3VdbeAddOp3(p, = op, p1, p2, p3);
+ VdbeOp *pOp =3D = &p->aOp[addr];
+ pOp->p4type =3D = P4_PTR;
+ pOp->p4.p =3D = ptr;
+ = return addr;
+}
+
 /* Insert = the end of a co-routine
  = */
 void
diff --git a/src/box/sql/where.c = b/src/box/sql/where.c
index 2f1c627e5..47da3c84c = 100644
--- a/src/box/sql/where.c
+++ = b/src/box/sql/where.c
@@ -42,6 +42,8 = @@
 #include "vdbeInt.h"
 #include = "whereInt.h"
 #include = "box/session.h"
+#include "box/schema.h"
+#include = "tarantoolInt.h"
 
 /* Forward declaration = of methods */
 static int whereLoopResize(sqlite3 *, = WhereLoop *, int);
@@ -4606,7 +4608,15 @@ = sqlite3WhereBegin(Parse * pParse, /* The parser context = */
  = assert(pIx->pSchema =3D=3D = pTab->pSchema);
  assert(iIndexCur = >=3D 0);
  if (op) = {
- = sqlite3VdbeAddOp2(v, op, iIndexCur, = pIx->tnum);
+ struct = space *space =3D
+ = space_by_id(SQLITE_PAGENO_TO_SPACEID(pIx->tnum));
+ = assert(space !=3D NULL);
+ int = space_ptr_reg =3D ++pParse->nMem;
+ = sqlite3VdbeAddOp4Ptr(v, OP_LoadPtr, 0,
+ =     space_ptr_reg, 0,
+ =     (void *) space);
+ = sqlite3VdbeAddOp3(v, op, iIndexCur, = pIx->tnum,
+ =  space_ptr_reg);
  = sqlite3VdbeSetP4KeyInfo(pParse, pIx);
  = if ((pLoop->wsFlags & WHERE_CONSTRAINT) !=3D = 0
    =  && (pLoop->


= --Apple-Mail=_F6035853-4E10-4750-88F4-F96E79F71D66--