1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Continuing work toward converting the VM into a register machine. (CVS 4707)

FossilOrigin-Name: a6dddebcc5ccbbf3009c9d06163a8b59036331de
This commit is contained in:
drh
2008-01-12 12:48:07 +00:00
parent d8c303fe0a
commit b765411161
13 changed files with 299 additions and 216 deletions

View File

@@ -1,5 +1,5 @@
C Do\sexplicit\srange\stests\sbefore\sattempting\sto\sconvert\sa\s64-bit\sfloat\ninto\sa\s64-bit\sinteger.\s\sSome\ssystems\s(windows)\sseem\sto\sthrow\sexceptions\nif\sthe\sconversion\sis\sout\sof\srange.\s\sTicket\s#2880.\s(CVS\s4706)
D 2008-01-11T15:27:03
C Continuing\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister\smachine.\s(CVS\s4707)
D 2008-01-12T12:48:08
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 52cbc3577c962975445d3e1341cba046f228d21e
F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1
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 e5bb1ddf630d4fbd042bf6a09168fe2feb4f7549
F src/build.c 353cce0f4e773b0889d94663dca6dc99598d6b3d
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
F src/delete.c 44eac0a8a1bad1e62ee64e59e07a5a97a838bd0f
F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c 560fbd4aff7c65e716e0310f85f044141abd9523
F src/expr.c 68bcc07517c763cc7601be45d60084bc11ee0212
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
F src/insert.c 405cf0550252cdd3ba5b14ce1545571c82e35250
F src/insert.c a19d9f51b611943386fcff714e3a0ffb137e463b
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
@@ -131,12 +131,12 @@ F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
F src/select.c ff00897172bad962c7f775f0a1daa19e2a3ed80a
F src/select.c 9e3c65ca3d2508b585b6786dbcbe6cd65560b013
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 ba917f5ed26ab1b47d3814d624e36a73dfe4c5bd
F src/sqliteInt.h b143c53760aeb4feeb4eaf8cb10eb26ad5b6c89e
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
@@ -168,7 +168,7 @@ F src/update.c aad823f97a930e6982264299863837d4c6107d3b
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
F src/vdbe.c 2a62b69e8344f28438ba0a007582be93b33b53ca
F src/vdbe.c 20bd088657280d75b630d299c59cdb3c6a5c9b9e
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
@@ -176,7 +176,7 @@ F src/vdbeaux.c db33a4c2477546da05e772352be43896d24d51d5
F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c
F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -417,10 +417,11 @@ F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
F test/select1.test 871df931cbbc0e78170605628e8b5fc60765e265
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
F test/select3.test 7f99c0d4067064e0865479a56faa7aaa29b9041a
F test/select4.test 69015a6c02c3d8efed01f15e5d025fb4e5256183
F test/select4.test 491193f50799e7fdb375ef04a1a8f40393dd7cfe
F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8
F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
F test/shared.test 9a1e81629efaebaad2247e9e81aa33570fba8f13
F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4
@@ -605,7 +606,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 6de0ee49073c7a47d5e10495b569b33df76d1448
R 72b005345d91bd390788cc14572cdea6
P 4744257d3cd2dd96485fde6d9f60542714383421
R 9fded3f0e818ece501c0ececcbd26a94
U drh
Z f60ae65829aa8eb88bba7196814bec78
Z fe475f28d0df336b5a859493e9293538

View File

@@ -1 +1 @@
4744257d3cd2dd96485fde6d9f60542714383421
a6dddebcc5ccbbf3009c9d06163a8b59036331de

View File

@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
** @(#) $Id: analyze.c,v 1.37 2008/01/10 23:50:11 drh Exp $
** @(#) $Id: analyze.c,v 1.38 2008/01/12 12:48:08 drh Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@@ -33,6 +33,7 @@ static void openStatTable(
sqlite3 *db = pParse->db;
Db *pDb;
int iRootPage;
int createStat1 = 0;
Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse);
@@ -43,13 +44,14 @@ static void openStatTable(
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
/* The sqlite_stat1 tables does not exist. Create it.
** Note that a side-effect of the CREATE TABLE statement is to leave
** the rootpage of the new table on the top of the stack. This is
** the rootpage of the new table in register pParse->regRoot. This is
** important because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
pDb->zName
);
iRootPage = 0; /* Cause rootpage to be taken from top of stack */
iRootPage = pParse->regRoot;
createStat1 = 1; /* Cause rootpage to be taken from top of stack */
}else if( zWhere ){
/* The sqlite_stat1 table exists. Delete all entries associated with
** the table zWhere. */
@@ -69,13 +71,11 @@ static void openStatTable(
** If this vdbe did create the sqlite_stat1 table, then it must have
** already obtained a schema-lock, making the write-lock redundant.
*/
if( iRootPage>0 ){
if( !createStat1 ){
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
}
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
if( iRootPage==0 ){
sqlite3VdbeChangeP5(v, 1);
}
sqlite3VdbeChangeP5(v, createStat1);
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iStatCur, 3);
}

View File

@@ -22,7 +22,7 @@
** COMMIT
** ROLLBACK
**
** $Id: build.c,v 1.463 2008/01/10 23:50:11 drh Exp $
** $Id: build.c,v 1.464 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -838,8 +838,9 @@ void sqlite3StartTable(
** now.
*/
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
int lbl;
int j1;
int fileFormat;
int reg1, reg2, reg3;
sqlite3BeginWriteOperation(pParse, 0, iDb);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -851,17 +852,19 @@ void sqlite3StartTable(
/* If the file format and encoding in the database have not been set,
** set them now.
*/
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 0, 1); /* file_format */
reg1 = pParse->regRowid = ++pParse->nMem;
reg2 = pParse->regRoot = ++pParse->nMem;
reg3 = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, 1); /* file_format */
sqlite3VdbeUsesBtree(v, iDb);
lbl = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_If, 0, lbl);
j1 = sqlite3VdbeAddOp1(v, OP_If, reg3);
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
1 : SQLITE_MAX_FILE_FORMAT;
sqlite3VdbeAddOp1(v, OP_Integer, fileFormat);
sqlite3VdbeAddOp2(v, OP_SetCookie, iDb, 1);
sqlite3VdbeAddOp1(v, OP_Integer, ENC(db));
sqlite3VdbeAddOp2(v, OP_SetCookie, iDb, 4);
sqlite3VdbeResolveLabel(v, lbl);
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, reg3);
sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 4, reg3);
sqlite3VdbeJumpHere(v, j1);
/* This just creates a place-holder record in the sqlite_master table.
** The record created does not contain anything yet. It will be replaced
@@ -873,19 +876,18 @@ void sqlite3StartTable(
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( isView || isVirtual ){
sqlite3VdbeAddOp0(v, OP_Integer);
sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2);
}else
#endif
{
sqlite3VdbeAddOp1(v, OP_CreateTable, iDb);
sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
}
sqlite3OpenMasterTable(pParse, iDb);
sqlite3VdbeAddOp0(v, OP_NewRowid);
sqlite3VdbeAddOp0(v, OP_Copy);
sqlite3VdbeAddOp0(v, OP_Null);
sqlite3CodeInsert(pParse, 0, OPFLAG_APPEND);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
sqlite3VdbeAddOp2(v, OP_Null, 0, reg3);
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3VdbeAddOp0(v, OP_Close);
sqlite3VdbeAddOp1(v, OP_Pull, 1);
}
/* Normal (non-error) return. */
@@ -1494,8 +1496,7 @@ void sqlite3EndTable(
SelectDest dest;
Table *pSelTab;
sqlite3VdbeAddOp0(v, OP_Copy);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb);
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
sqlite3VdbeChangeP5(v, 1);
pParse->nTab = 2;
sqlite3SelectDestInit(&dest, SRT_Table, 1);
@@ -1531,13 +1532,15 @@ void sqlite3EndTable(
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
"WHERE rowid=#1",
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
"WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
zType,
p->zName,
p->zName,
zStmt
pParse->regRoot,
zStmt,
pParse->regRowid
);
sqlite3_free(zStmt);
sqlite3ChangeCookie(db, v, iDb);
@@ -1835,20 +1838,22 @@ void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
*/
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, 0, iDb);
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* OP_Destroy pushes an integer onto the stack. If this integer
/* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
** location iTable. The following code modifies the sqlite_master table to
** reflect this.
**
** The "#0" in the SQL is a special constant that means whatever value
** The "#%d" in the SQL is a special constant that means whatever value
** is on the top of the stack. See sqlite3RegisterExpr().
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0",
pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable);
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
/*
@@ -2649,8 +2654,7 @@ void sqlite3CreateIndex(
/* Create the rootpage for the index
*/
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3VdbeAddOp1(v, OP_CreateIndex, iDb);
sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem);
sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
/* Gather the complete text of the CREATE INDEX statement into
** the zStmt variable
@@ -2670,13 +2674,13 @@ void sqlite3CreateIndex(
/* Add an entry in sqlite_master for this index
*/
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#0,%Q);",
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pIndex->zName,
pTab->zName,
iMem,
zStmt
);
sqlite3VdbeAddOp1(v, OP_Pop, 1);
sqlite3_free(zStmt);
/* Fill the index with data and reparse the schema. Code an OP_Expire

View File

@@ -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.156 2008/01/10 23:50:11 drh Exp $
** $Id: delete.c,v 1.157 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -60,20 +60,6 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
return 0;
}
/*
** This function is a temporary measure required because OP_Insert now
** reads the key and data to insert from memory cells.
*/
void sqlite3CodeInsert(Parse *p, int iCur, u8 flags){
int iData = ++p->nMem;
int iKey = ++p->nMem;
Vdbe *v = sqlite3GetVdbe(p);
sqlite3VdbeAddOp2(v, OP_Move, 0, iData);
sqlite3VdbeAddOp2(v, OP_Move, 0, iKey);
sqlite3VdbeAddOp3(v, OP_Insert, iCur, iData, iKey);
sqlite3VdbeChangeP5(v, flags);
}
/*
** Allocate nVal contiguous memory cells and return the index of the
** first. Also pop nVal elements from the stack and store them in the
@@ -91,14 +77,6 @@ int sqlite3StackToReg(Parse *p, int nVal){
}
return iRet;
}
void sqlite3RegToStack(Parse *p, int iReg, int nVal){
int i;
Vdbe *v = sqlite3GetVdbe(p);
assert(v);
for(i=0; i<nVal; i++){
sqlite3VdbeAddOp2(v, OP_SCopy, iReg+i, 0);
}
}
/*
** Generate code that will open a table for reading.

View File

@@ -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.342 2008/01/10 23:50:11 drh Exp $
** $Id: expr.c,v 1.343 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -289,9 +289,8 @@ Expr *sqlite3PExpr(
/*
** When doing a nested parse, you can include terms in an expression
** that look like this: #0 #1 #2 ... These terms refer to elements
** on the stack. "#0" means the top of the stack.
** "#1" means the next down on the stack. And so forth.
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register.
**
** This routine is called by the parser to deal with on of those terms.
** It immediately generates code to store the value in a memory location.
@@ -301,7 +300,6 @@ Expr *sqlite3PExpr(
Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
Vdbe *v = pParse->pVdbe;
Expr *p;
int depth;
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken);
return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
@@ -311,9 +309,7 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
if( p==0 ){
return 0; /* Malloc failed */
}
depth = atoi((char*)&pToken->z[1]);
p->iTable = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Copy, -depth, p->iTable);
p->iTable = atoi((char*)&pToken->z[1]);
return p;
}

View File

@@ -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.222 2008/01/10 23:50:11 drh Exp $
** $Id: insert.c,v 1.223 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -519,13 +519,18 @@ void sqlite3Insert(
/* Generate the subroutine that SELECT calls to process each row of
** the result. Store the result in a temporary table
*/
int regRec, regRowid;
srcTab = pParse->nTab++;
regRec = sqlite3GetTempReg(pParse);
regRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeResolveLabel(v, iInsertBlock);
sqlite3VdbeAddOp2(v, OP_RegMakeRec, regFromSelect, nColumn);
sqlite3VdbeAddOp1(v, OP_NewRowid, srcTab);
sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
sqlite3CodeInsert(pParse, srcTab, OPFLAG_APPEND);
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regFromSelect, nColumn, regRec);
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid);
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempReg(pParse, regRowid);
/* The following code runs first because the GOTO at the very top
** of the program jumps to it. Create the temporary table, then jump
@@ -663,7 +668,6 @@ void sqlite3Insert(
}else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iInsertBlock);
sqlite3RegToStack(pParse, regFromSelect, nColumn);
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
}
@@ -770,7 +774,7 @@ void sqlite3Insert(
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
}else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn - keyColumn - 1), regRowid);
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
}else{
VdbeOp *pOp;
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
@@ -835,7 +839,7 @@ void sqlite3Insert(
}else if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
}else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn-j-1), iRegStore);
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
}else{
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
}
@@ -899,7 +903,6 @@ void sqlite3Insert(
sqlite3VdbeResolveLabel(v, iBreak);
sqlite3VdbeAddOp2(v, OP_Close, srcTab, 0);
}else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_Pop, nColumn, 0);
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
sqlite3VdbeResolveLabel(v, iCleanup);
}
@@ -1279,6 +1282,7 @@ void sqlite3CompleteInsertion(
Index *pIdx;
int pik_flags;
int regData;
int regRec;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
@@ -1289,14 +1293,12 @@ void sqlite3CompleteInsertion(
sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
}
regData = regRowid + 1;
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
sqlite3VdbeAddOp2(v, OP_RegMakeRec, regData, pTab->nCol);
regRec = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regData, pTab->nCol, regRec);
sqlite3TableAffinityStr(v, pTab);
#ifndef SQLITE_OMIT_TRIGGER
if( newIdx>=0 ){
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
sqlite3VdbeAddOp1(v, OP_SCopy, -1);
sqlite3CodeInsert(pParse, newIdx, 0);
sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
}
#endif
if( pParse->nested ){
@@ -1308,10 +1310,11 @@ void sqlite3CompleteInsertion(
if( appendBias ){
pik_flags |= OPFLAG_APPEND;
}
sqlite3CodeInsert(pParse, baseCur, pik_flags);
sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
if( !pParse->nested ){
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
/*
@@ -1465,6 +1468,7 @@ static int xferOptimization(
KeyInfo *pKey; /* Key information for an index */
int regAutoinc; /* Memory register used by AUTOINC */
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
int regData, regRowid; /* Registers holding data and rowid */
if( pSelect==0 ){
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
@@ -1612,22 +1616,24 @@ static int xferOptimization(
}
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
regData = sqlite3GetTempReg(pParse);
regRowid = sqlite3GetTempReg(pParse);
if( pDest->iPKey>=0 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
sqlite3VdbeAddOp0(v, OP_Copy);
addr2 = sqlite3VdbeAddOp2(v, OP_NotExists, iDest, 0);
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
"PRIMARY KEY must be unique", P4_STATIC);
sqlite3VdbeJumpHere(v, addr2);
autoIncStep(pParse, regAutoinc, 0);
autoIncStep(pParse, regAutoinc, regRowid);
}else if( pDest->pIndex==0 ){
addr1 = sqlite3VdbeAddOp1(v, OP_NewRowid, iDest);
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
}else{
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
assert( pDest->autoInc==0 );
}
sqlite3VdbeAddOp1(v, OP_RowData, iSrc);
sqlite3CodeInsert(pParse,iDest,OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
@@ -1647,12 +1653,14 @@ static int xferOptimization(
(char*)pKey, P4_KEYINFO_HANDOFF);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
sqlite3VdbeAddOp1(v, OP_RowKey, iSrc);
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, 0, 1);
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
sqlite3VdbeJumpHere(v, addr1);
}
sqlite3VdbeJumpHere(v, emptySrcTest);
sqlite3ReleaseTempReg(pParse, regRowid);
sqlite3ReleaseTempReg(pParse, regData);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
if( emptyDestTest ){

View File

@@ -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.397 2008/01/10 23:50:11 drh Exp $
** $Id: select.c,v 1.398 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
@@ -394,7 +394,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
static void pushOntoSorter(
Parse *pParse, /* Parser context */
ExprList *pOrderBy, /* The ORDER BY clause */
Select *pSelect /* The whole SELECT statement */
Select *pSelect, /* The whole SELECT statement */
int regData /* Register holding data to be sorted */
){
Vdbe *v = pParse->pVdbe;
int nExpr = pOrderBy->nExpr;
@@ -402,15 +403,21 @@ static void pushOntoSorter(
int regRecord = sqlite3GetTempReg(pParse);
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3VdbeAddOp2(v, OP_Move, 0, regBase+nExpr+1);
sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1);
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nExpr + 2, regRecord);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
if( pSelect->iLimit>=0 ){
int addr1, addr2;
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, pSelect->iLimit+1);
sqlite3VdbeAddOp2(v, OP_AddImm, pSelect->iLimit+1, -1);
int iLimit;
if( pSelect->pOffset ){
iLimit = pSelect->iOffset+1;
}else{
iLimit = pSelect->iLimit;
}
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, iLimit);
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
@@ -426,16 +433,12 @@ static void pushOntoSorter(
static void codeOffset(
Vdbe *v, /* Generate code into this VM */
Select *p, /* The SELECT statement being coded */
int iContinue, /* Jump here to skip the current record */
int nPop /* Number of times to pop stack when jumping */
int iContinue /* Jump here to skip the current record */
){
if( p->iOffset>=0 && iContinue!=0 ){
int addr;
sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
if( nPop>0 ){
sqlite3VdbeAddOp1(v, OP_Pop, nPop);
}
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr);
@@ -524,7 +527,7 @@ static int selectInnerLoop(
*/
hasDistinct = distinct>=0 && pEList->nExpr>0;
if( pOrderBy==0 && !hasDistinct ){
codeOffset(v, p, iContinue, 0);
codeOffset(v, p, iContinue);
}
/* Pull the requested columns.
@@ -563,7 +566,7 @@ static int selectInnerLoop(
assert( pEList->nExpr==nColumn );
codeDistinct(v, distinct, iContinue, nColumn, iMem);
if( pOrderBy==0 ){
codeOffset(v, p, iContinue, nColumn);
codeOffset(v, p, iContinue);
}
}
@@ -603,14 +606,18 @@ static int selectInnerLoop(
*/
case SRT_Table:
case SRT_EphemTab: {
sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1);
if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p);
pushOntoSorter(pParse, pOrderBy, p, r1);
}else{
sqlite3VdbeAddOp1(v, OP_NewRowid, iParm);
sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND);
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -630,11 +637,12 @@ static int selectInnerLoop(
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
pushOntoSorter(pParse, pOrderBy, p);
pushOntoSorter(pParse, pOrderBy, p, iMem);
}else{
sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, 0, &p->affinity, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, r1, &p->affinity, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
sqlite3ReleaseTempReg(pParse, r1);
}
sqlite3VdbeJumpHere(v, addr2);
break;
@@ -654,11 +662,10 @@ static int selectInnerLoop(
*/
case SRT_Mem: {
assert( nColumn==1 );
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p);
pushOntoSorter(pParse, pOrderBy, p, iMem);
}else{
sqlite3VdbeAddOp2(v, OP_Move, 0, iParm);
sqlite3VdbeAddOp2(v, OP_Move, iMem, iParm);
/* The LIMIT clause will jump out of the loop for us */
}
break;
@@ -672,8 +679,10 @@ static int selectInnerLoop(
case SRT_Subroutine:
case SRT_Callback: {
if( pOrderBy ){
sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
pushOntoSorter(pParse, pOrderBy, p);
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1);
pushOntoSorter(pParse, pOrderBy, p, r1);
sqlite3ReleaseTempReg(pParse, r1);
}else if( eDest==SRT_Subroutine ){
sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
}else{
@@ -779,7 +788,7 @@ static void generateSortTail(
sqlite3VdbeAddOp2(v, OP_SetNumColumns, pseudoTab, nColumn);
}
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
codeOffset(v, p, cont, 0);
codeOffset(v, p, cont);
regRow = sqlite3GetTempReg(pParse);
regRowid = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow);
@@ -1737,7 +1746,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
Vdbe *v = 0;
int iLimit = 0;
int iOffset;
int addr1, addr2;
int addr1;
/*
** "LIMIT -1" always shows all rows. There is some
@@ -1747,41 +1756,33 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
*/
if( p->pLimit ){
p->iLimit = iLimit = ++pParse->nMem;
pParse->nMem++;
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3ExprCode(pParse, p->pLimit, 0);
sqlite3VdbeAddOp0(v, OP_MustBeInt);
sqlite3VdbeAddOp2(v, OP_Move, 0, iLimit);
sqlite3ExprCode(pParse, p->pLimit, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit);
VdbeComment((v, "LIMIT counter"));
sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak);
sqlite3VdbeAddOp2(v, OP_SCopy, iLimit, 0);
}
if( p->pOffset ){
p->iOffset = iOffset = ++pParse->nMem;
if( p->pLimit ){
pParse->nMem++; /* Allocate an extra register for limit+offset */
}
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3ExprCode(pParse, p->pOffset, 0);
sqlite3VdbeAddOp0(v, OP_MustBeInt);
sqlite3VdbeAddOp2(v, p->pLimit==0 ? OP_Move : OP_Copy, 0, iOffset);
sqlite3ExprCode(pParse, p->pOffset, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset);
VdbeComment((v, "OFFSET counter"));
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
sqlite3VdbeJumpHere(v, addr1);
if( p->pLimit ){
sqlite3VdbeAddOp2(v, OP_Add, 0, 0);
}
}
if( p->pLimit ){
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit);
sqlite3VdbeAddOp1(v, OP_Pop, 1);
sqlite3VdbeAddOp2(v, OP_Integer, -1, iLimit+1);
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Move, 0, iLimit+1);
sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
VdbeComment((v, "LIMIT+OFFSET"));
sqlite3VdbeJumpHere(v, addr2);
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit);
sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
sqlite3VdbeJumpHere(v, addr1);
}
}
}

View File

@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.647 2008/01/10 23:50:11 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.648 2008/01/12 12:48:08 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1420,6 +1420,8 @@ struct Parse {
/* Above is constant between recursions. Below is reset before and after
** each recursion */
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nVar; /* Number of '?' variables seen in the SQL so far */
int nVarExpr; /* Number of used slots in apVarExpr[] */
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
@@ -1945,9 +1947,7 @@ int sqlite3OpenTempDatabase(Parse *);
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
char *sqlite3StrAccumFinish(StrAccum*);
void sqlite3StrAccumReset(StrAccum*);
void sqlite3CodeInsert(Parse *, int, u8);
int sqlite3StackToReg(Parse *, int);
void sqlite3RegToStack(Parse *, int, int);
void sqlite3SelectDestInit(SelectDest*,int,int);
/*

View File

@@ -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.692 2008/01/10 23:50:11 drh Exp $
** $Id: vdbe.c,v 1.693 2008/01/12 12:48:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -94,6 +94,18 @@ int sqlite3_sort_count = 0;
int sqlite3_max_blobsize = 0;
#endif
/*
** Test a register to see if it exceeds the current maximum blob size.
** If it does, record the new maximum blob size.
*/
#ifdef SQLITE_TEST
# define UPDATE_MAX_BLOBSIZE(P) if( ((P)->flags&(MEM_Str|MEM_Blob))!=0 \
&& (P)->n>sqlite3_max_blobsize ) \
{sqlite3_max_blobsize = (P)->n;}
#else
# define UPDATE_MAX_BLOBSIZE(P)
#endif
/*
** Release the memory associated with the given stack level. This
** leaves the Mem.flags field in an inconsistent state.
@@ -939,6 +951,7 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
if( pOp->p1>SQLITE_MAX_LENGTH ){
goto too_big;
}
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
#endif
@@ -959,6 +972,7 @@ case OP_String: { /* out2-prerelease */
pOut->z = pOp->p4.z;
pOut->n = pOp->p1;
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -1019,6 +1033,7 @@ case OP_Blob: { /* out2-prerelease */
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
#endif /* SQLITE_OMIT_BLOB_LITERAL */
@@ -1043,6 +1058,7 @@ case OP_Variable: { /* out2-prerelease */
goto too_big;
}
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -1136,40 +1152,6 @@ case OP_SCopy: {
break;
}
/* Opcode: Pull P1 * *
**
** The P1-th element is removed from its current location on
** the stack and pushed back on top of the stack. The
** top of the stack is element 0, so "Pull 0 0 0" is
** a no-op. "Pull 1 0 0" swaps the top two elements of
** the stack.
*/
case OP_Pull: { /* no-push */
Mem *pFrom = &pTos[-pOp->p1];
int i;
Mem ts;
ts = *pFrom;
Deephemeralize(pTos);
for(i=0; i<pOp->p1; i++, pFrom++){
Deephemeralize(&pFrom[1]);
assert( (pFrom[1].flags & MEM_Ephem)==0 );
*pFrom = pFrom[1];
if( pFrom->flags & MEM_Short ){
assert( pFrom->flags & (MEM_Str|MEM_Blob) );
assert( pFrom->z==pFrom[1].zShort );
pFrom->z = pFrom->zShort;
}
}
*pTos = ts;
if( pTos->flags & MEM_Short ){
assert( pTos->flags & (MEM_Str|MEM_Blob) );
assert( pTos->z==pTos[-pOp->p1].zShort );
pTos->z = pTos->zShort;
}
break;
}
/* Opcode: ResultRow P1 P2 *
**
** The registers P1 throught P1+P2-1 contain a single row of
@@ -1257,6 +1239,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
pOut->xDel = 0;
pOut->enc = encoding;
pOut->z = zNew;
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -1489,6 +1472,7 @@ case OP_Function: {
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -1658,6 +1642,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, no-push, in1 */
rc = ExpandBlob(pIn1);
assert( pIn1->flags & MEM_Str );
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
@@ -1679,6 +1664,7 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, no-push, in1 */
pIn1->flags |= MEM_Blob;
}
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
@@ -2337,6 +2323,7 @@ case OP_Column: {
rc = sqlite3VdbeMemMakeWriteable(pDest);
op_column_out:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
}
@@ -2525,6 +2512,7 @@ case OP_MakeRecord: { /* jump */
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
REGISTER_TRACE(pOp->p3, pOut);
UPDATE_MAX_BLOBSIZE(pOut);
/* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
if( jumpIfNull && containsNull ){
@@ -2683,7 +2671,7 @@ case OP_ReadCookie: { /* out2-prerelease */
int iDb = pOp->p1;
int iCookie = pOp->p3;
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p3<SQLITE_N_BTREE_META );
if( iDb<0 ){
iDb = (-1*(iDb+1));
iCookie *= -1;
@@ -3819,6 +3807,7 @@ case OP_RowData: { /* out2-prerelease */
pOut->flags = MEM_Null;
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -4440,6 +4429,7 @@ case OP_IntegrityCk: {
pIn1->xDel = 0;
}
pIn1->enc = SQLITE_UTF8;
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
sqlite3_free(aRoot);
break;
@@ -4656,6 +4646,7 @@ case OP_AggFinal: { /* no-push */
if( rc==SQLITE_ERROR ){
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
}
UPDATE_MAX_BLOBSIZE(pMem);
if( sqlite3VdbeMemTooBig(pMem) ){
goto too_big;
}
@@ -4961,6 +4952,7 @@ case OP_VColumn: {
pDest->flags = 0;
}
sqlite3VdbeMemMove(pDest, &sContext.s);
UPDATE_MAX_BLOBSIZE(pDest);
if( sqlite3SafetyOn(db) ){
goto abort_due_to_misuse;
@@ -5134,16 +5126,6 @@ default: {
}
#endif
#ifdef SQLITE_TEST
/* Keep track of the size of the largest BLOB or STR that has appeared
** on the top of the VDBE stack.
*/
if( pTos>=p->aStack && (pTos->flags & (MEM_Blob|MEM_Str))!=0
&& pTos->n>sqlite3_max_blobsize ){
sqlite3_max_blobsize = pTos->n;
}
#endif
/* The following code adds nothing to the actual functionality
** of the program. It is only here for testing and debugging.
** On the other hand, it does burn CPU cycles every time through

View File

@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
** $Id: vtab.c,v 1.60 2008/01/03 00:01:25 drh Exp $
** $Id: vtab.c,v 1.61 2008/01/12 12:48:08 drh Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@@ -259,20 +259,20 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** SQLITE_MASTER table. We just need to update that slot with all
** the information we've collected.
**
** The top of the stack is the rootpage allocated by sqlite3StartTable().
** This value is always 0 and is ignored, a virtual table does not have a
** rootpage. The next entry on the stack is the rowid of the record
** in the sqlite_master table.
** The VM register number pParse->regRowid holds the rowid of an
** entry in the sqlite_master table tht was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#1",
"WHERE rowid=#%d",
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
pTab->zName,
pTab->zName,
zStmt
zStmt,
pParse->regRowid
);
sqlite3_free(zStmt);
v = sqlite3GetVdbe(pParse);

View File

@@ -12,7 +12,7 @@
# focus of this file is testing UNION, INTERSECT and EXCEPT operators
# in SELECT statements.
#
# $Id: select4.test,v 1.24 2007/12/13 07:58:51 danielk1977 Exp $
# $Id: select4.test,v 1.25 2008/01/12 12:48:09 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -618,4 +618,55 @@ do_test select4-9.12 {
} ;# ifcapable compound
# Try combining DISTINCT, LIMIT, and OFFSET. Make sure they all work
# together.
#
do_test select4-10.1 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log
}
} {0 1 2 3 4 5}
do_test select4-10.2 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT 4
}
} {0 1 2 3}
do_test select4-10.3 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT 0
}
} {}
do_test select4-10.4 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT -1
}
} {0 1 2 3 4 5}
do_test select4-10.5 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT -1 OFFSET 2
}
} {2 3 4 5}
do_test select4-10.6 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT 3 OFFSET 2
}
} {2 3 4}
do_test select4-10.7 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY +log LIMIT 3 OFFSET 20
}
} {}
do_test select4-10.8 {
execsql {
SELECT DISTINCT log FROM t1 ORDER BY log LIMIT 0 OFFSET 3
}
} {}
do_test select4-10.9 {
breakpoint
execsql {
SELECT DISTINCT max(n), log FROM t1 ORDER BY +log; -- LIMIT 2 OFFSET 1
}
} {31 5}
finish_test

62
test/select8.test Normal file
View File

@@ -0,0 +1,62 @@
# 2001 September 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# The focus of this file is testing that LIMIT and OFFSET work for
# unusual combinations SELECT statements.
#
# $Id: select8.test,v 1.1 2008/01/12 12:48:09 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
execsql {
CREATE TABLE songs(songid, artist, timesplayed);
INSERT INTO songs VALUES(1,'one',1);
INSERT INTO songs VALUES(2,'one',2);
INSERT INTO songs VALUES(3,'two',3);
INSERT INTO songs VALUES(4,'three',5);
INSERT INTO songs VALUES(5,'one',7);
INSERT INTO songs VALUES(6,'two',11);
}
set result [execsql {
SELECT DISTINCT artist,sum(timesplayed) AS total
FROM songs
GROUP BY LOWER(artist)
}]
puts result=$result
do_test select8-1.1 {
execsql {
SELECT DISTINCT artist,sum(timesplayed) AS total
FROM songs
GROUP BY LOWER(artist)
LIMIT 1 OFFSET 1
}
} [lrange $result 2 3]
do_test select8-1.2 {
execsql {
SELECT DISTINCT artist,sum(timesplayed) AS total
FROM songs
GROUP BY LOWER(artist)
LIMIT 2 OFFSET 1
}
} [lrange $result 2 5]
do_test select8-1.3 {
execsql {
SELECT DISTINCT artist,sum(timesplayed) AS total
FROM songs
GROUP BY LOWER(artist)
LIMIT -1 OFFSET 2
}
} [lrange $result 4 end]
finish_test