-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
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
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
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
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
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
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
-4744257d3cd2dd96485fde6d9f60542714383421
\ No newline at end of file
+a6dddebcc5ccbbf3009c9d06163a8b59036331de
\ No newline at end of file
*************************************************************************
** 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"
sqlite3 *db = pParse->db;
Db *pDb;
int iRootPage;
+ int createStat1 = 0;
Table *pStat;
Vdbe *v = sqlite3GetVdbe(pParse);
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. */
** 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);
}
** 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>
** 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
/* 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
*/
#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. */
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);
*/
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);
*/
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);
}
/*
/* 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
/* 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
** 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"
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
}
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.
** 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>
/*
** 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.
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);
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;
}
** 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"
/* 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
}else if( pSelect ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
sqlite3VdbeResolveLabel(v, iInsertBlock);
- sqlite3RegToStack(pParse, regFromSelect, nColumn);
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
}
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);
}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);
}
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);
}
Index *pIdx;
int pik_flags;
int regData;
+ int regRec;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
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 ){
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);
}
/*
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 ... */
}
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);
(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 ){
** 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"
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;
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);
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);
*/
hasDistinct = distinct>=0 && pEList->nExpr>0;
if( pOrderBy==0 && !hasDistinct ){
- codeOffset(v, p, iContinue, 0);
+ codeOffset(v, p, iContinue);
}
/* Pull the requested columns.
assert( pEList->nExpr==nColumn );
codeDistinct(v, distinct, iContinue, nColumn, iMem);
if( pOrderBy==0 ){
- codeOffset(v, p, iContinue, nColumn);
+ codeOffset(v, p, iContinue);
}
}
*/
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;
}
** 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;
*/
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;
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{
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);
Vdbe *v = 0;
int iLimit = 0;
int iOffset;
- int addr1, addr2;
+ int addr1;
/*
** "LIMIT -1" always shows all rows. There is some
*/
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);
+ sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
+ VdbeComment((v, "LIMIT+OFFSET"));
+ addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit);
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
+ sqlite3VdbeJumpHere(v, addr1);
}
}
- 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);
- VdbeComment((v, "LIMIT+OFFSET"));
- sqlite3VdbeJumpHere(v, addr2);
- }
}
/*
*************************************************************************
** 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_
/* 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[] */
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);
/*
** 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>
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.
if( pOp->p1>SQLITE_MAX_LENGTH ){
goto too_big;
}
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
#endif
pOut->z = pOp->p4.z;
pOut->n = pOp->p1;
pOut->enc = encoding;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
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 */
goto too_big;
}
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
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
pOut->xDel = 0;
pOut->enc = encoding;
pOut->z = zNew;
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
rc = ExpandBlob(pIn1);
assert( pIn1->flags & MEM_Str );
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
+ UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
pIn1->flags |= MEM_Blob;
}
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
+ UPDATE_MAX_BLOBSIZE(pIn1);
break;
}
rc = sqlite3VdbeMemMakeWriteable(pDest);
op_column_out:
+ UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
}
}
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 ){
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;
pOut->flags = MEM_Null;
}
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
+ UPDATE_MAX_BLOBSIZE(pOut);
break;
}
pIn1->xDel = 0;
}
pIn1->enc = SQLITE_UTF8;
+ UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
sqlite3_free(aRoot);
break;
if( rc==SQLITE_ERROR ){
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
}
+ UPDATE_MAX_BLOBSIZE(pMem);
if( sqlite3VdbeMemTooBig(pMem) ){
goto too_big;
}
pDest->flags = 0;
}
sqlite3VdbeMemMove(pDest, &sContext.s);
+ UPDATE_MAX_BLOBSIZE(pDest);
if( sqlite3SafetyOn(db) ){
goto abort_due_to_misuse;
}
#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
*************************************************************************
** 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"
** 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);
# 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
} ;# 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
--- /dev/null
+# 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