mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
More work toward converting the VM into a register-based machine. (CVS 4704)
FossilOrigin-Name: 8cbd46517f407b3b1ce187b623db10f00aa415ea
This commit is contained in:
36
manifest
36
manifest
@@ -1,5 +1,5 @@
|
||||
C Continuing\swork\stoward\sregisterizing\sthe\scode\sgenerator.\s(CVS\s4703)
|
||||
D 2008-01-10T03:46:36
|
||||
C More\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister-based\smachine.\s(CVS\s4704)
|
||||
D 2008-01-10T23:50:11
|
||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -79,24 +79,24 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
|
||||
F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc
|
||||
F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04
|
||||
F src/analyze.c 6cd38a981cac4491d71f99bfc10df32139b3a16a
|
||||
F src/analyze.c 52cbc3577c962975445d3e1341cba046f228d21e
|
||||
F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2
|
||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
||||
F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
|
||||
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
||||
F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76
|
||||
F src/build.c 785139de34c0141208f7f70865bcc603e29faf70
|
||||
F src/build.c e5bb1ddf630d4fbd042bf6a09168fe2feb4f7549
|
||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||
F src/delete.c 4f760fb7e9b0bb3cf05534bb9d43ea9e726b7e74
|
||||
F src/delete.c 44eac0a8a1bad1e62ee64e59e07a5a97a838bd0f
|
||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||
F src/expr.c 522ba17fa6253a98dc6451e600341277ea43d5c6
|
||||
F src/expr.c 560fbd4aff7c65e716e0310f85f044141abd9523
|
||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||
F src/insert.c b8406b40cc1cac732932ef587cbc0da006bfd68b
|
||||
F src/insert.c 405cf0550252cdd3ba5b14ce1545571c82e35250
|
||||
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
||||
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
||||
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
||||
@@ -127,16 +127,16 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c 0cb6ccea4b9615627d61d7c4417cedc45776d429
|
||||
F src/pager.h f504f7ae84060fee0416a853e368d3d113c3d6fa
|
||||
F src/parse.y 2ae06e8d3190faace49c5b82e7cea1fc60d084a1
|
||||
F src/pragma.c bc6063d91d56a8b3cdad9e3478bba86700759cc4
|
||||
F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b
|
||||
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
|
||||
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
||||
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
||||
F src/select.c 095296a572c296c9ce718768c6c984d33b239e5a
|
||||
F src/select.c ff00897172bad962c7f775f0a1daa19e2a3ed80a
|
||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||
F src/sqliteInt.h 0606321d38df78adef2325e0b51cd3963731f290
|
||||
F src/sqliteInt.h ba917f5ed26ab1b47d3814d624e36a73dfe4c5bd
|
||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||
@@ -163,17 +163,17 @@ F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5
|
||||
F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
||||
F src/test_thread.c e297dd41db0b249646e69f97d36ec13e56e8b730
|
||||
F src/tokenize.c a4e04438c11fed2c67ec47fe3edbef9cca2d1b48
|
||||
F src/trigger.c 1e77b3c21c129ad01f7f23a497ae1d224b4e5bc4
|
||||
F src/update.c 18f2f3af050399da584fe94548d7e15aa45e884d
|
||||
F src/trigger.c 69df777f7626507d04ef23b9cb185d31ebd8e91a
|
||||
F src/update.c aad823f97a930e6982264299863837d4c6107d3b
|
||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
||||
F src/vdbe.c b094a8834bc44e790aef0b0024daf45570b7d56e
|
||||
F src/vdbe.c 2a62b69e8344f28438ba0a007582be93b33b53ca
|
||||
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
|
||||
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
|
||||
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
|
||||
F src/vdbeaux.c 53cc9e2d3a870fe64f23c43b9417f28118e58d8f
|
||||
F src/vdbeblob.c b90f7494c408d47ce6835000b01e40b371e27baf
|
||||
F src/vdbeaux.c db33a4c2477546da05e772352be43896d24d51d5
|
||||
F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
|
||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||
F src/vdbemem.c a94f3e9e85578ba457133ad3446fc6114a03ec5a
|
||||
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
|
||||
@@ -605,7 +605,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P 05fbca91085cb1b271a05e62181596b4f6f1bb9e
|
||||
R 44353c14eaa458d109462754e477c6c2
|
||||
P 173698c963473ab1b9db88b23a2de82e4097b96d
|
||||
R 8bf48b53bfdac6453062e461bf371d81
|
||||
U drh
|
||||
Z d88167e0b41893f49eaf4061856356de
|
||||
Z e7ee9d7977b0629978f5e3008b2a0c6d
|
||||
|
@@ -1 +1 @@
|
||||
173698c963473ab1b9db88b23a2de82e4097b96d
|
||||
8cbd46517f407b3b1ce187b623db10f00aa415ea
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code associated with the ANALYZE command.
|
||||
**
|
||||
** @(#) $Id: analyze.c,v 1.36 2008/01/09 23:04:12 drh Exp $
|
||||
** @(#) $Id: analyze.c,v 1.37 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#include "sqliteInt.h"
|
||||
@@ -120,6 +120,12 @@ static void analyzeOneTable(
|
||||
iIdxCur = pParse->nTab;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
int regFields; /* Register block for building records */
|
||||
int regRec; /* Register holding completed record */
|
||||
int regTemp; /* Temporary use register */
|
||||
int regCol; /* Content of a column from the table being analyzed */
|
||||
int regRowid; /* Rowid for the inserted record */
|
||||
int regF2;
|
||||
|
||||
/* Open a cursor to the index to be analyzed
|
||||
*/
|
||||
@@ -128,8 +134,11 @@ static void analyzeOneTable(
|
||||
(char *)pKey, P4_KEYINFO_HANDOFF);
|
||||
VdbeComment((v, "%s", pIdx->zName));
|
||||
nCol = pIdx->nColumn;
|
||||
if( iMem+nCol*2>=pParse->nMem ){
|
||||
pParse->nMem = iMem+nCol*2+1;
|
||||
regFields = iMem+nCol*2;
|
||||
regTemp = regRowid = regCol = regFields+3;
|
||||
regRec = regCol+1;
|
||||
if( regRec>pParse->nMem ){
|
||||
pParse->nMem = regRec;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iIdxCur, nCol+1);
|
||||
|
||||
@@ -160,15 +169,15 @@ static void analyzeOneTable(
|
||||
topOfLoop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, i);
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, iMem+nCol+i+1);
|
||||
sqlite3VdbeAddOp0(v, OP_Ne ); /* Use Collating sequence */
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol);
|
||||
sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1);
|
||||
/**** TODO: add collating sequence *****/
|
||||
sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop);
|
||||
for(i=0; i<nCol; i++){
|
||||
addr = sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
|
||||
sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr);
|
||||
sqlite3VdbeJumpHere(v, topOfLoop + 2*(i + 1));
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
@@ -193,23 +202,24 @@ static void analyzeOneTable(
|
||||
** If K>0 then it is always the case the D>0 so division by zero
|
||||
** is never possible.
|
||||
*/
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, iMem);
|
||||
addr = sqlite3VdbeAddOp0(v, OP_IfNot);
|
||||
sqlite3VdbeAddOp1(v, OP_NewRowid, iStatCur);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, iMem);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regFields, 0, pTab->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regFields+1, 0, pIdx->zName, 0);
|
||||
regF2 = regFields+2;
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regF2);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, " ", 0);
|
||||
sqlite3VdbeAddOp0(v, OP_Concat);
|
||||
sqlite3VdbeAddOp2(v, OP_Add, iMem, iMem+i+1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_Divide, iMem+i+1, 0);
|
||||
sqlite3VdbeAddOp0(v, OP_ToInt);
|
||||
sqlite3VdbeAddOp0(v, OP_Concat);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
|
||||
sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp);
|
||||
sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2);
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, 3, 0, 0, "aaa", 0);
|
||||
sqlite3CodeInsert(pParse, iStatCur, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, regFields, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
}
|
||||
|
26
src/build.c
26
src/build.c
@@ -22,7 +22,7 @@
|
||||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.462 2008/01/09 23:04:12 drh Exp $
|
||||
** $Id: build.c,v 1.463 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -2222,6 +2222,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
int tnum; /* Root page of index */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
KeyInfo *pKey; /* KeyInfo for index */
|
||||
int regIdxKey; /* Registers containing the index key */
|
||||
int regRecord; /* Register holding assemblied index record */
|
||||
sqlite3 *db = pParse->db; /* The database connection */
|
||||
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
|
||||
|
||||
@@ -2252,19 +2254,23 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
}
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
||||
sqlite3GenerateIndexKey(v, pIndex, iTab);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord);
|
||||
if( pIndex->onError!=OE_None ){
|
||||
int curaddr = sqlite3VdbeCurrentAddr(v);
|
||||
int addr2 = curaddr+4;
|
||||
sqlite3VdbeChangeP2(v, curaddr-1, addr2);
|
||||
sqlite3VdbeAddOp1(v, OP_Rowid, iTab);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 0, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, addr2, 0, 0, P4_INT32);
|
||||
int j1, j2;
|
||||
int regRowid;
|
||||
|
||||
regRowid = regIdxKey + pIndex->nColumn;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdxKey, 0, pIndex->nColumn);
|
||||
j2 = sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx,
|
||||
0, regRowid, (char*)regRecord, P4_INT32);
|
||||
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort, 0,
|
||||
"indexed columns are not unique", P4_STATIC);
|
||||
assert( db->mallocFailed || addr2==sqlite3VdbeCurrentAddr(v) );
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iTab);
|
||||
|
47
src/delete.c
47
src/delete.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.155 2008/01/09 23:04:12 drh Exp $
|
||||
** $Id: delete.c,v 1.156 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -390,7 +390,7 @@ void sqlite3DeleteFrom(
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3GenerateRowDelete(db, v, pTab, iCur, iRowid, pParse->nested==0);
|
||||
sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, pParse->nested==0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,16 +455,18 @@ delete_from_cleanup:
|
||||
** entries that point to that record.
|
||||
*/
|
||||
void sqlite3GenerateRowDelete(
|
||||
sqlite3 *db, /* The database containing the index */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Parse *pParse, /* Parsing context */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
int iRowid, /* Memory cell that contains the rowid to delete */
|
||||
int count /* Increment the row change counter */
|
||||
){
|
||||
int addr;
|
||||
Vdbe *v;
|
||||
|
||||
v = pParse->pVdbe;
|
||||
addr = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowid);
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
if( count ){
|
||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
|
||||
@@ -489,7 +491,7 @@ void sqlite3GenerateRowDelete(
|
||||
** deleted.
|
||||
*/
|
||||
void sqlite3GenerateRowIndexDelete(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
|
||||
@@ -499,8 +501,8 @@ void sqlite3GenerateRowIndexDelete(
|
||||
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
|
||||
sqlite3GenerateIndexKey(v, pIdx, iCur);
|
||||
sqlite3VdbeAddOp1(v, OP_IdxDelete, iCur+i);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0);
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_IdxDelete, iCur+i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,25 +511,38 @@ void sqlite3GenerateRowIndexDelete(
|
||||
** of the tack. The key with be for index pIdx which is an index on pTab.
|
||||
** iCur is the index of a cursor open on the pTab table and pointing to
|
||||
** the entry that needs indexing.
|
||||
**
|
||||
** Return a register number which is the first in a block of
|
||||
** registers that holds the elements of the index key. The
|
||||
** block of registers has already been deallocated by the time
|
||||
** this routine returns.
|
||||
*/
|
||||
void sqlite3GenerateIndexKey(
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
int sqlite3GenerateIndexKey(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur /* Cursor number for the pIdx->pTable table */
|
||||
int iCur, /* Cursor number for the pIdx->pTable table */
|
||||
int regOut /* Write the new index key to this register */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int j;
|
||||
Table *pTab = pIdx->pTable;
|
||||
int regBase;
|
||||
int nCol;
|
||||
|
||||
sqlite3VdbeAddOp1(v, OP_Rowid, iCur);
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
nCol = pIdx->nColumn;
|
||||
regBase = sqlite3GetTempRange(pParse, nCol+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
|
||||
for(j=0; j<nCol; j++){
|
||||
int idx = pIdx->aiColumn[j];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp1(v, OP_Copy, -j);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Column, iCur, idx);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
|
||||
sqlite3ColumnDefault(v, pTab, idx);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_MakeIdxRec, pIdx->nColumn);
|
||||
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nCol+1, regOut);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
|
||||
return regBase;
|
||||
}
|
||||
|
50
src/expr.c
50
src/expr.c
@@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.341 2008/01/10 03:46:36 drh Exp $
|
||||
** $Id: expr.c,v 1.342 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -1550,7 +1550,7 @@ struct QueryCoder {
|
||||
** The returned value indicates the structure type, as follows:
|
||||
**
|
||||
** IN_INDEX_ROWID - The cursor was opened on a database table.
|
||||
** IN_INDEX_INDEX - The cursor was opened on a database indec.
|
||||
** IN_INDEX_INDEX - The cursor was opened on a database index.
|
||||
** IN_INDEX_EPH - The cursor was opened on a specially created and
|
||||
** populated epheremal table.
|
||||
**
|
||||
@@ -1765,6 +1765,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
int i;
|
||||
ExprList *pList = pExpr->pList;
|
||||
struct ExprList_item *pItem;
|
||||
int r1, r2;
|
||||
|
||||
if( !affinity ){
|
||||
affinity = SQLITE_AFF_NONE;
|
||||
@@ -1772,6 +1773,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
keyInfo.aColl[0] = pExpr->pLeft->pColl;
|
||||
|
||||
/* Loop through each expression in <exprlist>. */
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
r2 = sqlite3GetTempReg(pParse);
|
||||
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
|
||||
Expr *pE2 = pItem->pExpr;
|
||||
|
||||
@@ -1786,10 +1789,12 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
sqlite3ExprCode(pParse, pE2, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1);
|
||||
sqlite3VdbeAddOp1(v, OP_IdxInsert, pExpr->iTable);
|
||||
sqlite3ExprCode(pParse, pE2, r1);
|
||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, r1, 1, r2, &affinity, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
}
|
||||
sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
|
||||
break;
|
||||
@@ -2230,6 +2235,7 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
int j1, j2, j3, j4, j5;
|
||||
char affinity;
|
||||
int eType;
|
||||
int r1, r2, r3;
|
||||
|
||||
eType = sqlite3FindInIndex(pParse, pExpr, 0);
|
||||
|
||||
@@ -2239,29 +2245,35 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
*/
|
||||
affinity = comparisonAffinity(pExpr);
|
||||
|
||||
sqlite3VdbeAddOp1(v, OP_Integer, 1);
|
||||
if( target ){
|
||||
r1 = target;
|
||||
}else{
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
}
|
||||
inReg = r1;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, r1);
|
||||
|
||||
/* Code the <expr> from "<expr> IN (...)". The temporary table
|
||||
** pExpr->iTable contains the values that make up the (...) set.
|
||||
*/
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft, 0);
|
||||
sqlite3VdbeAddOp0(v, OP_SCopy);
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
|
||||
sqlite3VdbeAddOp1(v, OP_Pop, 2);
|
||||
sqlite3VdbeAddOp0(v, OP_Null);
|
||||
r2 = sqlite3ExprCode(pParse, pExpr->pLeft, -1);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, r2);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, r1);
|
||||
j2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
if( eType==IN_INDEX_ROWID ){
|
||||
j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, 1);
|
||||
j4 = sqlite3VdbeAddOp1(v, OP_NotExists, pExpr->iTable);
|
||||
j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r2, 0, 1);
|
||||
j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r2);
|
||||
j5 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3VdbeJumpHere(v, j4);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &affinity, 1);
|
||||
j5 = sqlite3VdbeAddOp1(v, OP_Found, pExpr->iTable);
|
||||
r3 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, r2, 1, r3, &affinity, 1);
|
||||
j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r3);
|
||||
sqlite3ReleaseTempReg(pParse, r3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 0, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, r1, -1);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
sqlite3VdbeJumpHere(v, j5);
|
||||
break;
|
||||
@@ -2384,19 +2396,19 @@ int sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
||||
** not cached. If the expression is cached, its result is stored in a
|
||||
** memory location.
|
||||
*/
|
||||
void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr){
|
||||
void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
VdbeOp *pOp;
|
||||
int iMem;
|
||||
int addr1, addr2;
|
||||
if( v==0 ) return;
|
||||
addr1 = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3ExprCode(pParse, pExpr, 0);
|
||||
sqlite3ExprCode(pParse, pExpr, target);
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
if( addr2>addr1+1
|
||||
|| ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){
|
||||
iMem = pExpr->iTable = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
|
||||
pExpr->op = TK_REGISTER;
|
||||
}
|
||||
}
|
||||
|
79
src/insert.c
79
src/insert.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.221 2008/01/10 03:46:36 drh Exp $
|
||||
** $Id: insert.c,v 1.222 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
** 'c' NUMERIC
|
||||
** 'd' INTEGER
|
||||
** 'e' REAL
|
||||
**
|
||||
** An extra 'b' is appended to the end of the string to cover the
|
||||
** rowid that appears as the last column in every index.
|
||||
*/
|
||||
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
if( !pIdx->zColAff ){
|
||||
@@ -42,14 +45,15 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
int n;
|
||||
Table *pTab = pIdx->pTable;
|
||||
sqlite3 *db = sqlite3VdbeDb(v);
|
||||
pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1);
|
||||
pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+2);
|
||||
if( !pIdx->zColAff ){
|
||||
return;
|
||||
}
|
||||
for(n=0; n<pIdx->nColumn; n++){
|
||||
pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
|
||||
}
|
||||
pIdx->zColAff[pIdx->nColumn] = '\0';
|
||||
pIdx->zColAff[n++] = SQLITE_AFF_NONE;
|
||||
pIdx->zColAff[n] = 0;
|
||||
}
|
||||
|
||||
sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
|
||||
@@ -679,6 +683,9 @@ void sqlite3Insert(
|
||||
*/
|
||||
endOfLoop = sqlite3VdbeMakeLabel(v);
|
||||
if( triggers_exist & TRIGGER_BEFORE ){
|
||||
int regRowid;
|
||||
int regCols;
|
||||
int regRec;
|
||||
|
||||
/* build the NEW.* reference row. Note that if there is an INTEGER
|
||||
** PRIMARY KEY into which a NULL is being inserted, that NULL will be
|
||||
@@ -686,20 +693,19 @@ void sqlite3Insert(
|
||||
** we do not know what the unique ID will be (because the insert has
|
||||
** not happened yet) so we substitute a rowid of -1
|
||||
*/
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
if( keyColumn<0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
|
||||
}else{
|
||||
int j1;
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
|
||||
sqlite3VdbeAddOp0(v, OP_SCopy);
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
|
||||
sqlite3VdbeAddOp1(v, OP_Pop, 1);
|
||||
sqlite3VdbeAddOp1(v, OP_Integer, -1);
|
||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp0(v, OP_MustBeInt);
|
||||
sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
|
||||
}
|
||||
|
||||
/* Cannot have triggers on a virtual table. If it were possible,
|
||||
@@ -709,6 +715,7 @@ void sqlite3Insert(
|
||||
|
||||
/* Create the new column data
|
||||
*/
|
||||
regCols = sqlite3GetTempRange(pParse, pTab->nCol);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pColumn==0 ){
|
||||
j = i;
|
||||
@@ -718,15 +725,16 @@ void sqlite3Insert(
|
||||
}
|
||||
}
|
||||
if( pColumn && j>=pColumn->nId ){
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
|
||||
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
|
||||
}else if( useTempTable ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, srcTab, j);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i);
|
||||
}else{
|
||||
assert( pSelect==0 ); /* Otherwise useTempTable is true */
|
||||
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
|
||||
sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRec);
|
||||
|
||||
/* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
|
||||
** do not attempt any conversions before assembling the record.
|
||||
@@ -736,7 +744,10 @@ void sqlite3Insert(
|
||||
if( !isView ){
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
}
|
||||
sqlite3CodeInsert(pParse, newIdx, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
|
||||
|
||||
/* Fire BEFORE or INSTEAD OF triggers */
|
||||
if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab,
|
||||
@@ -1123,7 +1134,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
|
||||
if( isUpdate ){
|
||||
sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
|
||||
}
|
||||
@@ -1148,20 +1159,25 @@ void sqlite3GenerateConstraintChecks(
|
||||
** Add the new records to the indices as we go.
|
||||
*/
|
||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
||||
int regIdx;
|
||||
int regR;
|
||||
|
||||
if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
|
||||
|
||||
/* Create a key for accessing the index entry */
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
||||
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int idx = pIdx->aiColumn[i];
|
||||
if( idx==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
|
||||
}
|
||||
}
|
||||
j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
||||
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
|
||||
|
||||
/* Find out what action to take in case there is an indexing conflict */
|
||||
onError = pIdx->onError;
|
||||
@@ -1178,9 +1194,11 @@ void sqlite3GenerateConstraintChecks(
|
||||
|
||||
|
||||
/* Check to see if the new index entry will be unique */
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
||||
j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, 0, 0, P4_INT32);
|
||||
j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn);
|
||||
regR = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR);
|
||||
j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0,
|
||||
regR, (char*)aRegIdx[iCur], P4_INT32);
|
||||
|
||||
/* Generate code that executes if the new index entry is not unique */
|
||||
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
|
||||
@@ -1217,26 +1235,21 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
case OE_Ignore: {
|
||||
assert( seenReplace==0 );
|
||||
sqlite3VdbeAddOp1(v, OP_Pop, 2+hasTwoRowids);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
int iRowid = sqlite3StackToReg(pParse, 1);
|
||||
sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0);
|
||||
sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0);
|
||||
if( isUpdate ){
|
||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
|
||||
sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
|
||||
}
|
||||
seenReplace = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3VdbeAddOp1(v, OP_Pop, 1);
|
||||
#if NULL_DISTINCT_FOR_UNIQUE
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
#endif
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3ReleaseTempReg(pParse, regR);
|
||||
}
|
||||
}
|
||||
|
||||
|
164
src/pragma.c
164
src/pragma.c
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.164 2008/01/09 23:04:12 drh Exp $
|
||||
** $Id: pragma.c,v 1.165 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -252,6 +252,7 @@ void sqlite3Pragma(
|
||||
Db *pDb;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
pParse->nMem = 1;
|
||||
|
||||
/* Interpret the [database.] part of the pragma statement. iDb is the
|
||||
** index of the database this pragma is being applied to in db.aDb[]. */
|
||||
@@ -419,8 +420,8 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P4_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zRet, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
|
||||
|
||||
@@ -495,7 +496,7 @@ void sqlite3Pragma(
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb);
|
||||
sqlite3VdbeAddOp0(v, OP_Callback);
|
||||
sqlite3VdbeAddOp1(v, OP_ResultRow, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
@@ -564,8 +565,8 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME,
|
||||
"temp_store_directory", P4_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, sqlite3_temp_directory, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}
|
||||
}else{
|
||||
if( zRight[0]
|
||||
@@ -643,6 +644,7 @@ void sqlite3Pragma(
|
||||
int nHidden = 0;
|
||||
Column *pCol;
|
||||
sqlite3VdbeSetNumCols(v, 6);
|
||||
pParse->nMem = 6;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", P4_STATIC);
|
||||
@@ -656,18 +658,18 @@ void sqlite3Pragma(
|
||||
nHidden++;
|
||||
continue;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pCol->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
pCol->zType ? pCol->zType : "", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pCol->notNull, 4);
|
||||
if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, (char*)pDflt->z, pDflt->n);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pDflt->z, pDflt->n);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 6, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pCol->isPrimKey, 6);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -681,16 +683,17 @@ void sqlite3Pragma(
|
||||
int i;
|
||||
pTab = pIdx->pTable;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
pParse->nMem = 3;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", P4_STATIC);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int cnum = pIdx->aiColumn[i];
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
|
||||
assert( pTab->nCol>cnum );
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->aCol[cnum].zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
||||
}
|
||||
}
|
||||
}else
|
||||
@@ -706,14 +709,15 @@ void sqlite3Pragma(
|
||||
if( pIdx ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
pParse->nMem = 3;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", P4_STATIC);
|
||||
while(pIdx){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
||||
++i;
|
||||
pIdx = pIdx->pNext;
|
||||
}
|
||||
@@ -725,17 +729,18 @@ void sqlite3Pragma(
|
||||
int i;
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
pParse->nMem = 3;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", P4_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( db->aDb[i].pBt==0 ) continue;
|
||||
assert( db->aDb[i].zName!=0 );
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 3, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
||||
}
|
||||
}else
|
||||
|
||||
@@ -743,13 +748,14 @@ void sqlite3Pragma(
|
||||
int i = 0;
|
||||
HashElem *p;
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
pParse->nMem = 2;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", P4_STATIC);
|
||||
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
|
||||
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i++, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pColl->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 2, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
|
||||
}
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
|
||||
@@ -766,6 +772,7 @@ void sqlite3Pragma(
|
||||
if( pFK ){
|
||||
int i = 0;
|
||||
sqlite3VdbeSetNumCols(v, 5);
|
||||
pParse->nMem = 5;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", P4_STATIC);
|
||||
@@ -775,13 +782,13 @@ void sqlite3Pragma(
|
||||
int j;
|
||||
for(j=0; j<pFK->nCol; j++){
|
||||
char *zCol = pFK->aCol[j].zCol;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, j, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pFK->zTo, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0,
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
|
||||
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
|
||||
sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 0, 0, zCol, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 5, 0);
|
||||
sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
|
||||
}
|
||||
++i;
|
||||
pFK = pFK->pNextFrom;
|
||||
@@ -831,17 +838,17 @@ void sqlite3Pragma(
|
||||
** error message
|
||||
*/
|
||||
static const VdbeOpList endCode[] = {
|
||||
{ OP_SCopy, 1, 0, 0},
|
||||
{ OP_Integer, 0, 0, 0},
|
||||
{ OP_Ne, 0, 0, 0}, /* 2 */
|
||||
{ OP_String8, 0, 0, 0}, /* 3 */
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
{ OP_AddImm, 1, 0, 0}, /* 0 */
|
||||
{ OP_IfNeg, 1, 0, 0}, /* 1 */
|
||||
{ OP_String8, 0, 3, 0}, /* 2 */
|
||||
{ OP_ResultRow, 3, 1, 0},
|
||||
};
|
||||
|
||||
int isQuick = (zLeft[0]=='q');
|
||||
|
||||
/* Initialize the VDBE program */
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pParse->nMem = 6;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P4_STATIC);
|
||||
|
||||
@@ -853,8 +860,7 @@ void sqlite3Pragma(
|
||||
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);
|
||||
pParse->nMem = 1;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
|
||||
|
||||
/* Do an integrity check on each database file */
|
||||
for(i=0; i<db->nDb; i++){
|
||||
@@ -865,11 +871,14 @@ void sqlite3Pragma(
|
||||
if( OMIT_TEMPDB && i==1 ) continue;
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
**
|
||||
** Begin by filling registers 2, 3, ... with the root pages numbers
|
||||
** for all tables and indices in the database.
|
||||
*/
|
||||
pTbls = &db->aDb[i].pSchema->tblHash;
|
||||
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
||||
@@ -883,9 +892,13 @@ void sqlite3Pragma(
|
||||
}
|
||||
}
|
||||
if( cnt==0 ) continue;
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
if( pParse->nMem < cnt+3 ){
|
||||
pParse->nMem = cnt+3;
|
||||
}
|
||||
|
||||
/* Do the b-tree integrity checks */
|
||||
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
||||
sqlite3VdbeChangeP5(v, i);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2);
|
||||
@@ -904,28 +917,28 @@ void sqlite3Pragma(
|
||||
int loopTop;
|
||||
|
||||
if( pTab->pIndex==0 ) continue;
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2;
|
||||
static const VdbeOpList idxErr[] = {
|
||||
{ OP_AddImm, 1, -1, 0},
|
||||
{ OP_String8, 0, 0, 0}, /* 1 */
|
||||
{ OP_Rowid, 1, 0, 0},
|
||||
{ OP_String8, 0, 0, 0}, /* 3 */
|
||||
{ OP_String8, 0, 0, 0}, /* 4 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
{ OP_String8, 0, 3, 0}, /* 1 */
|
||||
{ OP_Rowid, 1, 4, 0},
|
||||
{ OP_String8, 0, 5, 0}, /* 3 */
|
||||
{ OP_String8, 0, 6, 0}, /* 4 */
|
||||
{ OP_Concat, 4, 3, 3},
|
||||
{ OP_Concat, 5, 3, 3},
|
||||
{ OP_Concat, 6, 3, 3},
|
||||
{ OP_ResultRow, 3, 1, 0},
|
||||
};
|
||||
sqlite3GenerateIndexKey(v, pIdx, 1);
|
||||
jmp2 = sqlite3VdbeAddOp2(v, OP_Found, j+2, 0);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, 1, 3);
|
||||
jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+3, " missing from index ", P4_STATIC);
|
||||
@@ -940,14 +953,12 @@ void sqlite3Pragma(
|
||||
{ OP_Rewind, 0, 0, 0}, /* 1 */
|
||||
{ OP_AddImm, 3, 1, 0},
|
||||
{ OP_Next, 0, 0, 0}, /* 3 */
|
||||
{ OP_SCopy, 2, 0, 0},
|
||||
{ OP_SCopy, 3, 0, 0},
|
||||
{ OP_Eq, 0, 0, 0}, /* 6 */
|
||||
{ OP_Eq, 2, 0, 3}, /* 4 */
|
||||
{ OP_AddImm, 1, -1, 0},
|
||||
{ OP_String8, 0, 0, 0}, /* 8 */
|
||||
{ OP_String8, 0, 0, 0}, /* 9 */
|
||||
{ OP_Concat, 0, 0, 0},
|
||||
{ OP_Callback, 1, 0, 0},
|
||||
{ OP_String8, 0, 2, 0}, /* 6 */
|
||||
{ OP_String8, 0, 3, 0}, /* 7 */
|
||||
{ OP_Concat, 3, 2, 2},
|
||||
{ OP_ResultRow, 2, 1, 0},
|
||||
};
|
||||
if( pIdx->tnum==0 ) continue;
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
|
||||
@@ -958,17 +969,17 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeChangeP2(v, addr+1, addr+4);
|
||||
sqlite3VdbeChangeP1(v, addr+3, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+3, addr+2);
|
||||
sqlite3VdbeJumpHere(v, addr+6);
|
||||
sqlite3VdbeChangeP4(v, addr+8,
|
||||
sqlite3VdbeJumpHere(v, addr+4);
|
||||
sqlite3VdbeChangeP4(v, addr+6,
|
||||
"wrong # of entries in index ", P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+9, pIdx->zName, P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_STATIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
sqlite3VdbeChangeP1(v, addr+1, mxErr);
|
||||
sqlite3VdbeChangeP4(v, addr+3, "ok", P4_STATIC);
|
||||
sqlite3VdbeJumpHere(v, addr+2);
|
||||
sqlite3VdbeChangeP2(v, addr, -mxErr);
|
||||
sqlite3VdbeJumpHere(v, addr+1);
|
||||
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
||||
@@ -1015,14 +1026,14 @@ void sqlite3Pragma(
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", P4_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_String8, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
|
||||
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
||||
if( pEnc->enc==ENC(pParse->db) ){
|
||||
sqlite3VdbeChangeP4(v, -1, pEnc->zName, P4_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
|
||||
}else{ /* "PRAGMA encoding = XXX" */
|
||||
/* Only change the value of sqlite.enc if the database handle is not
|
||||
** initialized. If the main database exists, the new sqlite.enc value
|
||||
@@ -1109,8 +1120,8 @@ void sqlite3Pragma(
|
||||
}else{
|
||||
/* Read the specified cookie value */
|
||||
static const VdbeOpList readCookie[] = {
|
||||
{ OP_ReadCookie, 0, 0, 0}, /* 0 */
|
||||
{ OP_Callback, 1, 0, 0}
|
||||
{ OP_ReadCookie, 0, 1, 0}, /* 0 */
|
||||
{ OP_ResultRow, 1, 1, 0}
|
||||
};
|
||||
int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie);
|
||||
sqlite3VdbeChangeP1(v, addr, iDb);
|
||||
@@ -1132,6 +1143,7 @@ void sqlite3Pragma(
|
||||
int i;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
sqlite3VdbeSetNumCols(v, 2);
|
||||
pParse->nMem = 2;
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", P4_STATIC);
|
||||
sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", P4_STATIC);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
@@ -1140,7 +1152,7 @@ void sqlite3Pragma(
|
||||
const char *zState = "unknown";
|
||||
int j;
|
||||
if( db->aDb[i].zName==0 ) continue;
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, db->aDb[i].zName, P4_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
|
||||
pBt = db->aDb[i].pBt;
|
||||
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
||||
zState = "closed";
|
||||
@@ -1148,8 +1160,8 @@ void sqlite3Pragma(
|
||||
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
|
||||
zState = azLockName[j];
|
||||
}
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, zState, P4_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_Callback, 2, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
|
196
src/select.c
196
src/select.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.396 2008/01/10 03:46:36 drh Exp $
|
||||
** $Id: select.c,v 1.397 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -769,6 +769,9 @@ static void generateSortTail(
|
||||
int eDest = pDest->eDest;
|
||||
int iParm = pDest->iParm;
|
||||
|
||||
int regRow;
|
||||
int regRowid;
|
||||
|
||||
iTab = pOrderBy->iECursor;
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
pseudoTab = pParse->nTab++;
|
||||
@@ -777,35 +780,30 @@ static void generateSortTail(
|
||||
}
|
||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
|
||||
codeOffset(v, p, cont, 0);
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Column, iTab, pOrderBy->nExpr + 1);
|
||||
regRow = sqlite3GetTempReg(pParse);
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow);
|
||||
switch( eDest ){
|
||||
case SRT_Table:
|
||||
case SRT_EphemTab: {
|
||||
sqlite3VdbeAddOp1(v, OP_NewRowid, iParm);
|
||||
sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
|
||||
sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case SRT_Set: {
|
||||
int j1, j2;
|
||||
int j1;
|
||||
assert( nColumn==1 );
|
||||
sqlite3VdbeAddOp0(v, OP_SCopy);
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
|
||||
sqlite3VdbeAddOp1(v, OP_Pop, 1);
|
||||
j2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow);
|
||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, regRow, 1, regRow, &p->affinity, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &p->affinity, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
break;
|
||||
}
|
||||
case SRT_Mem: {
|
||||
assert( nColumn==1 );
|
||||
sqlite3VdbeAddOp2(v, OP_Move, 0, iParm);
|
||||
sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm);
|
||||
/* The LIMIT clause will terminate the loop for us */
|
||||
break;
|
||||
}
|
||||
@@ -813,7 +811,8 @@ static void generateSortTail(
|
||||
case SRT_Callback:
|
||||
case SRT_Subroutine: {
|
||||
int i;
|
||||
sqlite3CodeInsert(pParse, pseudoTab, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pseudoTab, regRow, regRowid);
|
||||
for(i=0; i<nColumn; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i);
|
||||
}
|
||||
@@ -829,6 +828,8 @@ static void generateSortTail(
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regRow);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
|
||||
/* Jump to the end of the loop when the LIMIT is reached
|
||||
*/
|
||||
@@ -2651,165 +2652,6 @@ static int minMaxQuery(Parse *pParse, Select *p){
|
||||
return ORDERBY_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Analyze the SELECT statement passed in as an argument to see if it
|
||||
** is a simple min() or max() query. If it is and this query can be
|
||||
** satisfied using a single seek to the beginning or end of an index,
|
||||
** then generate the code for this SELECT and return 1. If this is not a
|
||||
** simple min() or max() query, then return 0;
|
||||
**
|
||||
** A simply min() or max() query looks like this:
|
||||
**
|
||||
** SELECT min(a) FROM table;
|
||||
** SELECT max(a) FROM table;
|
||||
**
|
||||
** The query may have only a single table in its FROM argument. There
|
||||
** can be no GROUP BY or HAVING or WHERE clauses. The result set must
|
||||
** be the min() or max() of a single column of the table. The column
|
||||
** in the min() or max() function must be indexed.
|
||||
**
|
||||
** The parameters to this routine are the same as for sqlite3Select().
|
||||
** See the header comment on that routine for additional information.
|
||||
*/
|
||||
#if 0
|
||||
static int simpleMinMaxQuery(Parse *pParse, Select *p, SelectDest *pDest){
|
||||
Expr *pExpr;
|
||||
int iCol;
|
||||
Table *pTab;
|
||||
Index *pIdx;
|
||||
int base;
|
||||
Vdbe *v;
|
||||
int seekOp;
|
||||
ExprList *pEList, *pList, eList;
|
||||
struct ExprList_item eListItem;
|
||||
SrcList *pSrc;
|
||||
int brk;
|
||||
int iDb;
|
||||
|
||||
/* Check to see if this query is a simple min() or max() query. Return
|
||||
** zero if it is not.
|
||||
*/
|
||||
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
|
||||
pSrc = p->pSrc;
|
||||
if( pSrc->nSrc!=1 ) return 0;
|
||||
pEList = p->pEList;
|
||||
if( pEList->nExpr!=1 ) return 0;
|
||||
pExpr = pEList->a[0].pExpr;
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
||||
pList = pExpr->pList;
|
||||
if( pList==0 || pList->nExpr!=1 ) return 0;
|
||||
if( pExpr->token.n!=3 ) return 0;
|
||||
if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){
|
||||
seekOp = OP_Rewind;
|
||||
}else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){
|
||||
seekOp = OP_Last;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
pExpr = pList->a[0].pExpr;
|
||||
if( pExpr->op!=TK_COLUMN ) return 0;
|
||||
iCol = pExpr->iColumn;
|
||||
pTab = pSrc->a[0].pTab;
|
||||
|
||||
/* This optimization cannot be used with virtual tables. */
|
||||
if( IsVirtual(pTab) ) return 0;
|
||||
|
||||
/* If we get to here, it means the query is of the correct form.
|
||||
** Check to make sure we have an index and make pIdx point to the
|
||||
** appropriate index. If the min() or max() is on an INTEGER PRIMARY
|
||||
** key column, no index is necessary so set pIdx to NULL. If no
|
||||
** usable index is found, return 0.
|
||||
*/
|
||||
if( iCol<0 ){
|
||||
pIdx = 0;
|
||||
}else{
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( pColl==0 ) return 0;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
assert( pIdx->nColumn>=1 );
|
||||
if( pIdx->aiColumn[0]==iCol &&
|
||||
0==sqlite3StrICmp(pIdx->azColl[0], pColl->zName) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pIdx==0 ) return 0;
|
||||
}
|
||||
|
||||
/* Identify column types if we will be using the callback. This
|
||||
** step is skipped if the output is going to a table or a memory cell.
|
||||
** The column names have already been generated in the calling function.
|
||||
*/
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return 0;
|
||||
|
||||
/* If the output is destined for a temporary table, open that table.
|
||||
*/
|
||||
if( pDest->eDest==SRT_EphemTab ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iParm, 1);
|
||||
}
|
||||
|
||||
/* Generating code to find the min or the max. Basically all we have
|
||||
** to do is find the first or the last entry in the chosen index. If
|
||||
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
|
||||
** or last entry in the main table.
|
||||
*/
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
assert( iDb>=0 || pTab->isEphem );
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
base = pSrc->a[0].iCursor;
|
||||
brk = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, brk);
|
||||
if( pSrc->a[0].pSelect==0 ){
|
||||
sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
if( pIdx==0 ){
|
||||
sqlite3VdbeAddOp2(v, seekOp, base, 0);
|
||||
}else{
|
||||
/* Even though the cursor used to open the index here is closed
|
||||
** as soon as a single value has been read from it, allocate it
|
||||
** using (pParse->nTab++) to prevent the cursor id from being
|
||||
** reused. This is important for statements of the form
|
||||
** "INSERT INTO x SELECT max() FROM x".
|
||||
*/
|
||||
int iIdx;
|
||||
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
iIdx = pParse->nTab++;
|
||||
assert( pIdx->pSchema==pTab->pSchema );
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iIdx, pIdx->tnum, iDb,
|
||||
(char*)pKey, P4_KEYINFO_HANDOFF);
|
||||
if( seekOp==OP_Rewind ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_MakeRecord, 1, 0);
|
||||
seekOp = OP_MoveGt;
|
||||
}
|
||||
if( pIdx->aSortOrder[0]==SQLITE_SO_DESC ){
|
||||
/* Ticket #2514: invert the seek operator if we are using
|
||||
** a descending index. */
|
||||
if( seekOp==OP_Last ){
|
||||
seekOp = OP_Rewind;
|
||||
}else{
|
||||
assert( seekOp==OP_MoveGt );
|
||||
seekOp = OP_MoveLt;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, seekOp, iIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iIdx, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0);
|
||||
}
|
||||
eList.nExpr = 1;
|
||||
memset(&eListItem, 0, sizeof(eListItem));
|
||||
eList.a = &eListItem;
|
||||
eList.a[0].pExpr = pExpr;
|
||||
selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, pDest, brk, brk, 0);
|
||||
sqlite3VdbeResolveLabel(v, brk);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, base, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This routine resolves any names used in the result set of the
|
||||
** supplied SELECT statement. If the SELECT statement being resolved
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.646 2008/01/10 03:46:36 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.647 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@@ -1766,7 +1766,7 @@ WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
|
||||
void sqlite3WhereEnd(WhereInfo*);
|
||||
void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int, int);
|
||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*);
|
||||
void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
|
||||
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
@@ -1795,9 +1795,9 @@ int sqlite3ExprIsConstantNotJoin(Expr*);
|
||||
int sqlite3ExprIsConstantOrFunction(Expr*);
|
||||
int sqlite3ExprIsInteger(Expr*, int*);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int, int);
|
||||
void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, int*);
|
||||
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
|
||||
void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
||||
int*,int,int,int,int);
|
||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
|
||||
|
@@ -227,43 +227,20 @@ void sqlite3FinishTrigger(
|
||||
** build the sqlite_master entry
|
||||
*/
|
||||
if( !db->init.busy ){
|
||||
static const VdbeOpList insertTrig[] = {
|
||||
{ OP_NewRowid, 0, 0, 0 },
|
||||
{ OP_String8, 0, 0, 0 }, /* 1: "trigger" */
|
||||
{ OP_String8, 0, 0, 0 }, /* 2: trigger name */
|
||||
{ OP_String8, 0, 0, 0 }, /* 3: table name */
|
||||
{ OP_Integer, 0, 0, 0 },
|
||||
{ OP_String8, 0, 0, 0 }, /* 5: "CREATE TRIGGER " */
|
||||
{ OP_String8, 0, 0, 0 }, /* 6: SQL */
|
||||
{ OP_Concat, 0, 0, 0 },
|
||||
{ OP_MakeRecord, 5, 0, 0 }, /* 8: "aaada" */
|
||||
{ OP_Move, 0, 0, 0 }, /* 9: Store data */
|
||||
{ OP_Move, 0, 0, 0 }, /* 10: Store key */
|
||||
{ OP_Insert, 0, 0, 0 },
|
||||
};
|
||||
int addr;
|
||||
Vdbe *v;
|
||||
int iKey = ++pParse->nMem;
|
||||
int iData = ++pParse->nMem;
|
||||
char *z;
|
||||
|
||||
/* Make an entry in the sqlite_master table */
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) goto triggerfinish_cleanup;
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3OpenMasterTable(pParse, iDb);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
|
||||
sqlite3VdbeChangeP4(v, addr+1, "trigger", P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+2, pTrig->name, 0);
|
||||
sqlite3VdbeChangeP4(v, addr+3, pTrig->table, 0);
|
||||
sqlite3VdbeChangeP4(v, addr+5, "CREATE TRIGGER ", P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+6, (char*)pAll->z, pAll->n);
|
||||
sqlite3VdbeChangeP4(v, addr+8, "aaada", P4_STATIC);
|
||||
sqlite3VdbeChangeP2(v, addr+9, iData);
|
||||
sqlite3VdbeChangeP2(v, addr+10, iKey);
|
||||
sqlite3VdbeChangeP2(v, addr+11, iData);
|
||||
sqlite3VdbeChangeP3(v, addr+11, iKey);
|
||||
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
|
||||
sqlite3NestedParse(pParse,
|
||||
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
|
||||
db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrig->name,
|
||||
pTrig->table, z);
|
||||
sqlite3_free(z);
|
||||
sqlite3ChangeCookie(db, v, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, 0, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf(
|
||||
db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC
|
||||
);
|
||||
|
38
src/update.c
38
src/update.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.166 2008/01/09 23:04:12 drh Exp $
|
||||
** $Id: update.c,v 1.167 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -404,50 +404,60 @@ void sqlite3Update(
|
||||
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
|
||||
|
||||
if( triggers_exist ){
|
||||
int regRowid;
|
||||
int regRow;
|
||||
int regCols;
|
||||
|
||||
/* Make cursor iCur point to the record that is being updated.
|
||||
*/
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);
|
||||
|
||||
/* Generate the OLD table
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0);
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
regRow = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
|
||||
if( !old_col_mask ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regRow);
|
||||
}else{
|
||||
sqlite3VdbeAddOp1(v, OP_RowData, iCur);
|
||||
sqlite3VdbeAddOp2(v, OP_RowData, iCur, regRow);
|
||||
}
|
||||
sqlite3CodeInsert(pParse, oldIdx, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, oldIdx, regRow, regRowid);
|
||||
|
||||
/* Generate the NEW table
|
||||
*/
|
||||
if( chngRowid ){
|
||||
sqlite3ExprCodeAndCache(pParse, pRowidExpr);
|
||||
sqlite3ExprCodeAndCache(pParse, pRowidExpr, regRowid);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regRowid);
|
||||
}
|
||||
regCols = sqlite3GetTempRange(pParse, pTab->nCol);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
|
||||
continue;
|
||||
}
|
||||
j = aXRef[i];
|
||||
if( new_col_mask&((u32)1<<i) || new_col_mask==0xffffffff ){
|
||||
if( j<0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_Column, iCur, i);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regCols+i);
|
||||
sqlite3ColumnDefault(v, pTab, i);
|
||||
}else{
|
||||
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr);
|
||||
sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i);
|
||||
}
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRow);
|
||||
if( !isView ){
|
||||
sqlite3TableAffinityStr(v, pTab);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
|
||||
if( pParse->nErr ) goto update_cleanup;
|
||||
sqlite3CodeInsert(pParse, newIdx, 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
sqlite3ReleaseTempReg(pParse, regRow);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBeginBeforeTrigger);
|
||||
sqlite3VdbeJumpHere(v, iEndBeforeTrigger);
|
||||
@@ -495,7 +505,7 @@ void sqlite3Update(
|
||||
|
||||
/* Delete the old indices for the current record.
|
||||
*/
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, aRegIdx);
|
||||
sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
|
||||
|
||||
/* If changing the record number, delete the old record.
|
||||
*/
|
||||
|
128
src/vdbe.c
128
src/vdbe.c
@@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.691 2008/01/09 23:04:12 drh Exp $
|
||||
** $Id: vdbe.c,v 1.692 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -1121,10 +1121,12 @@ case OP_SCopy: {
|
||||
assert( pOp->p2<=p->nMem );
|
||||
pOut = &p->aMem[pOp->p2];
|
||||
}
|
||||
assert( pOut!=pIn1 );
|
||||
if( pOp->opcode==OP_Move ){
|
||||
rc = sqlite3VdbeMemMove(pOut, pIn1);
|
||||
if( pOp->p1==0 ) pTos--;
|
||||
}else{
|
||||
Release(pOut);
|
||||
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
||||
if( pOp->opcode==OP_Copy ){
|
||||
Deephemeralize(pOut);
|
||||
@@ -1168,56 +1170,6 @@ case OP_Pull: { /* no-push */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Callback P1 * *
|
||||
**
|
||||
** The top P1 values on the stack represent a single result row from
|
||||
** a query. This opcode causes the sqlite3_step() call to terminate
|
||||
** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
|
||||
** structure to provide access to the top P1 values as the result
|
||||
** row. When the sqlite3_step() function is run again, the top P1
|
||||
** values will be automatically popped from the stack before the next
|
||||
** instruction executes.
|
||||
*/
|
||||
case OP_Callback: { /* no-push */
|
||||
Mem *pMem;
|
||||
Mem *pFirstColumn;
|
||||
assert( p->nResColumn==pOp->p1 );
|
||||
|
||||
/* Data in the pager might be moved or changed out from under us
|
||||
** in between the return from this sqlite3_step() call and the
|
||||
** next call to sqlite3_step(). So deephermeralize everything on
|
||||
** the stack. Note that ephemeral data is never stored in memory
|
||||
** cells so we do not have to worry about them.
|
||||
*/
|
||||
pFirstColumn = &pTos[1-pOp->p1];
|
||||
for(pMem = p->aStack; pMem<pFirstColumn; pMem++){
|
||||
Deephemeralize(pMem);
|
||||
}
|
||||
|
||||
/* Invalidate all ephemeral cursor row caches */
|
||||
p->cacheCtr = (p->cacheCtr + 2)|1;
|
||||
|
||||
/* Make sure the results of the current row are \000 terminated
|
||||
** and have an assigned type. The results are deephemeralized as
|
||||
** as side effect.
|
||||
*/
|
||||
for(; pMem<=pTos; pMem++ ){
|
||||
sqlite3VdbeMemNulTerminate(pMem);
|
||||
storeTypeInfo(pMem, encoding);
|
||||
}
|
||||
|
||||
/* Set up the statement structure so that it will pop the current
|
||||
** results from the stack when the statement returns.
|
||||
*/
|
||||
p->pResultSet = pFirstColumn;
|
||||
p->nCallback++;
|
||||
p->popStack = pOp->p1;
|
||||
p->pc = pc + 1;
|
||||
p->pTos = pTos;
|
||||
rc = SQLITE_ROW;
|
||||
goto vdbe_return;
|
||||
}
|
||||
|
||||
/* Opcode: ResultRow P1 P2 *
|
||||
**
|
||||
** The registers P1 throught P1+P2-1 contain a single row of
|
||||
@@ -1988,9 +1940,8 @@ case OP_Not: { /* same as TK_NOT, no-push, in1 */
|
||||
nPop = 0;
|
||||
if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
pIn1->u.i = !pIn1->u.i;
|
||||
pIn1->flags = MEM_Int;
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2004,9 +1955,8 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push, in1 */
|
||||
nPop = 0;
|
||||
if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */
|
||||
sqlite3VdbeMemIntegerify(pIn1);
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
pIn1->u.i = ~pIn1->u.i;
|
||||
pIn1->flags = MEM_Int;
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2078,17 +2028,25 @@ case OP_StackIsNull: { /* no-push, jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IsNull P1 P2 * * *
|
||||
/* Opcode: IsNull P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is NULL.
|
||||
** Jump to P2 if the value in register P1 is NULL. If P3 is greater
|
||||
** than zero, then check all values reg(P1), reg(P1+1),
|
||||
** reg(P1+2), ..., reg(P1+P3-1).
|
||||
**
|
||||
** If P1 is 0 then use the top of the stack instead of a register
|
||||
** and pop the stack regardless of whether or not the jump is taken.
|
||||
*/
|
||||
case OP_IsNull: { /* same as TK_ISNULL, no-push, jump, in1 */
|
||||
if( (pIn1->flags & MEM_Null)!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
int n = pOp->p3;
|
||||
assert( pOp->p3==0 || pOp->p1>0 );
|
||||
do{
|
||||
if( (pIn1->flags & MEM_Null)!=0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
pIn1++;
|
||||
}while( --n > 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2409,15 +2367,6 @@ op_column_out:
|
||||
** macros defined in sqliteInt.h.
|
||||
**
|
||||
** If P4 is NULL then all index fields have the affinity NONE.
|
||||
**
|
||||
** See also OP_MakeIdxRec
|
||||
*/
|
||||
/* Opcode: MakeIdxRec P1 P2 P4
|
||||
**
|
||||
** This opcode works just OP_MakeRecord except that it reads an extra
|
||||
** integer from the stack (thus reading a total of abs(P1+1) entries)
|
||||
** and appends that extra integer to the end of the record as a varint.
|
||||
** This results in an index key.
|
||||
*/
|
||||
/*
|
||||
** Opcode: RegMakeRec P1 P2 P3 P4 *
|
||||
@@ -2428,17 +2377,7 @@ op_column_out:
|
||||
** There is no jump on NULL - that can be done with a separate
|
||||
** OP_AnyNull opcode.
|
||||
*/
|
||||
/*
|
||||
** Opcode: RegMakeIRec P1 P2 P4
|
||||
**
|
||||
** Works like OP_MakeIdxRec except data is taken from registers
|
||||
** rather than from the stack. The P1 register is an integer which
|
||||
** is the number of register to use in building the new record.
|
||||
** Data is taken from P1+1, P1+2, ..., P1+mem[P1].
|
||||
*/
|
||||
case OP_RegMakeRec:
|
||||
case OP_RegMakeIRec:
|
||||
case OP_MakeIdxRec: /* jump */
|
||||
case OP_MakeRecord: { /* jump */
|
||||
/* Assuming the record contains N fields, the record format looks
|
||||
** like this:
|
||||
@@ -2457,7 +2396,6 @@ case OP_MakeRecord: { /* jump */
|
||||
*/
|
||||
u8 *zNewRecord; /* A buffer to hold the data for the new record */
|
||||
Mem *pRec; /* The new record */
|
||||
Mem *pRowid = 0; /* Rowid appended to the new record */
|
||||
u64 nData = 0; /* Number of bytes of data space */
|
||||
int nHdr = 0; /* Number of bytes of header space */
|
||||
u64 nByte = 0; /* Data space required for this record */
|
||||
@@ -2470,24 +2408,22 @@ case OP_MakeRecord: { /* jump */
|
||||
int leaveOnStack; /* If true, leave the entries on the stack */
|
||||
int nField; /* Number of fields in the record */
|
||||
int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */
|
||||
int addRowid; /* True to append a rowid column at the end */
|
||||
char *zAffinity; /* The affinity string for the record */
|
||||
int file_format; /* File format to use for encoding */
|
||||
int i; /* Space used in zNewRecord[] */
|
||||
char zTemp[NBFS]; /* Space to hold small records */
|
||||
|
||||
if( pOp->p1<0 ){
|
||||
assert( pOp->opcode==OP_MakeRecord || pOp->opcode==OP_MakeIdxRec );
|
||||
assert( pOp->opcode==OP_MakeRecord );
|
||||
leaveOnStack = 1;
|
||||
nField = -pOp->p1;
|
||||
}else{
|
||||
leaveOnStack = 0;
|
||||
nField = pOp->p1;
|
||||
}
|
||||
addRowid = pOp->opcode==OP_MakeIdxRec || pOp->opcode==OP_RegMakeIRec;
|
||||
zAffinity = pOp->p4.z;
|
||||
|
||||
if( pOp->opcode==OP_RegMakeRec || pOp->opcode==OP_RegMakeIRec ){
|
||||
if( pOp->opcode==OP_RegMakeRec ){
|
||||
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem );
|
||||
pData0 = &p->aMem[nField];
|
||||
nField = pOp->p2;
|
||||
@@ -2530,20 +2466,6 @@ case OP_MakeRecord: { /* jump */
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have to append a varint rowid to this record, set pRowid
|
||||
** to the value of the rowid and increase nByte by the amount of space
|
||||
** required to store it.
|
||||
*/
|
||||
if( addRowid ){
|
||||
pRowid = &pData0[-1];
|
||||
assert( pRowid>=p->aStack );
|
||||
sqlite3VdbeMemIntegerify(pRowid);
|
||||
serial_type = sqlite3VdbeSerialType(pRowid, 0);
|
||||
nData += sqlite3VdbeSerialTypeLen(serial_type);
|
||||
nHdr += sqlite3VarintLen(serial_type);
|
||||
nZero = 0;
|
||||
}
|
||||
|
||||
/* Add the initial header varint and total the size */
|
||||
nHdr += nVarint = sqlite3VarintLen(nHdr);
|
||||
if( nVarint<sqlite3VarintLen(nHdr) ){
|
||||
@@ -2570,20 +2492,14 @@ case OP_MakeRecord: { /* jump */
|
||||
serial_type = sqlite3VdbeSerialType(pRec, file_format);
|
||||
i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */
|
||||
}
|
||||
if( addRowid ){
|
||||
i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0));
|
||||
}
|
||||
for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */
|
||||
i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
|
||||
}
|
||||
if( addRowid ){
|
||||
i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0);
|
||||
}
|
||||
assert( i==nByte );
|
||||
|
||||
/* Pop entries off the stack if required. Push the new record on. */
|
||||
if( !leaveOnStack ){
|
||||
popStack(&pTos, nField+addRowid);
|
||||
popStack(&pTos, nField);
|
||||
}
|
||||
if( pOp->p3==0 ){
|
||||
pOut = ++pTos;
|
||||
@@ -3434,7 +3350,7 @@ case OP_IsUnique: { /* no-push, jump, in3 */
|
||||
*/
|
||||
nPop = 0;
|
||||
pIn3->u.i = v;
|
||||
pIn3->flags = MEM_Int;
|
||||
assert( pIn3->flags==MEM_Int );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -395,7 +395,6 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
|
||||
** This routine is useful for setting a jump destination.
|
||||
*/
|
||||
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
||||
assert( val>=0 );
|
||||
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
|
||||
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
||||
p->aOp[addr].p2 = val;
|
||||
|
@@ -12,7 +12,7 @@
|
||||
**
|
||||
** This file contains code used to implement incremental BLOB I/O.
|
||||
**
|
||||
** $Id: vdbeblob.c,v 1.17 2008/01/03 07:54:24 danielk1977 Exp $
|
||||
** $Id: vdbeblob.c,v 1.18 2008/01/10 23:50:11 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@@ -54,7 +54,7 @@ int sqlite3_blob_open(
|
||||
** vdbe program will take advantage of the various transaction,
|
||||
** locking and error handling infrastructure built into the vdbe.
|
||||
**
|
||||
** After seeking the cursor, the vdbe executes an OP_Callback.
|
||||
** After seeking the cursor, the vdbe executes an OP_ResultRow.
|
||||
** Code external to the Vdbe then "borrows" the b-tree cursor and
|
||||
** uses it to implement the blob_read(), blob_write() and
|
||||
** blob_bytes() functions.
|
||||
@@ -74,10 +74,10 @@ int sqlite3_blob_open(
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
{OP_SetNumColumns, 0, 0, 0}, /* 4: Num cols for cursor */
|
||||
|
||||
{OP_Variable, 1, 0, 0}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 0}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 0}, /* 7 */
|
||||
{OP_Callback, 0, 0, 0}, /* 8 */
|
||||
{OP_Variable, 1, 1, 0}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
};
|
||||
@@ -181,7 +181,7 @@ int sqlite3_blob_open(
|
||||
*/
|
||||
sqlite3VdbeChangeP2(v, 4, pTab->nCol+1);
|
||||
if( !db->mallocFailed ){
|
||||
sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
|
||||
sqlite3VdbeMakeReady(v, 1, 1, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user