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:
31
manifest
31
manifest
@@ -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)
|
C Continuing\swork\stoward\sconverting\sthe\sVM\sinto\sa\sregister\smachine.\s(CVS\s4707)
|
||||||
D 2008-01-11T15:27:03
|
D 2008-01-12T12:48:08
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -79,24 +79,24 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
|||||||
F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
|
F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4
|
||||||
F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc
|
F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc
|
||||||
F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04
|
F src/alter.c 5a54f58d9481ac14c4e58b702f3f8758dee84d04
|
||||||
F src/analyze.c 52cbc3577c962975445d3e1341cba046f228d21e
|
F src/analyze.c 5aa93f191b365ea308795f62ca6f2e8caa9de3e1
|
||||||
F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2
|
F src/attach.c 61f0cae7b1a0e7c3b5f5286be5dc1a7c4d7112d2
|
||||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||||
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff
|
||||||
F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
|
F src/btree.c 5164b32950cfd41f2c5c31e8ff82c4a499918aef
|
||||||
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
F src/btree.h 19dcf5ad23c17b98855da548e9a8e3eb4429d5eb
|
||||||
F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76
|
F src/btreeInt.h 1c5a9da165718ef7de81e35ce9ab5d9ba9283f76
|
||||||
F src/build.c e5bb1ddf630d4fbd042bf6a09168fe2feb4f7549
|
F src/build.c 353cce0f4e773b0889d94663dca6dc99598d6b3d
|
||||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||||
F src/delete.c 44eac0a8a1bad1e62ee64e59e07a5a97a838bd0f
|
F src/delete.c 00e536847b8eedc5d35f89f7f38a8a7c1d2a22f9
|
||||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||||
F src/expr.c 560fbd4aff7c65e716e0310f85f044141abd9523
|
F src/expr.c 68bcc07517c763cc7601be45d60084bc11ee0212
|
||||||
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d
|
||||||
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c
|
||||||
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53
|
||||||
F src/insert.c 405cf0550252cdd3ba5b14ce1545571c82e35250
|
F src/insert.c a19d9f51b611943386fcff714e3a0ffb137e463b
|
||||||
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
F src/journal.c 807bed7a158979ac8d63953e1774e8d85bff65e2
|
||||||
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
F src/legacy.c 4ac53191fad2e3c4d59bde1228879b2dc5a96d66
|
||||||
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
|
||||||
@@ -131,12 +131,12 @@ F src/pragma.c 1d3d9deefcf325e14a99b94f9f506f1a90a9232b
|
|||||||
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
|
F src/prepare.c c31a879d6795f4765fd0b113675c6debbc96b7fd
|
||||||
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910
|
||||||
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da
|
||||||
F src/select.c ff00897172bad962c7f775f0a1daa19e2a3ed80a
|
F src/select.c 9e3c65ca3d2508b585b6786dbcbe6cd65560b013
|
||||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||||
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
F src/shell.c 5391e889384d2062249f668110d64ed16f601c4b
|
||||||
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f
|
||||||
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
F src/sqlite3ext.h a93f59cdee3638dc0c9c086f80df743a4e68c3cb
|
||||||
F src/sqliteInt.h ba917f5ed26ab1b47d3814d624e36a73dfe4c5bd
|
F src/sqliteInt.h b143c53760aeb4feeb4eaf8cb10eb26ad5b6c89e
|
||||||
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
F src/sqliteLimit.h ee4430f88f69bf63527967bb35ca52af7b0ccb1e
|
||||||
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
F src/table.c 1aeb9eab57b4235db86fe15a35dec76fb445a9c4
|
||||||
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
F src/tclsqlite.c 9923abeffc9b3d7dad58e92b319661521f60debf
|
||||||
@@ -168,7 +168,7 @@ F src/update.c aad823f97a930e6982264299863837d4c6107d3b
|
|||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
F src/vacuum.c 3f34f278809bf3eb0b62ec46ff779e9c385b28f0
|
||||||
F src/vdbe.c 2a62b69e8344f28438ba0a007582be93b33b53ca
|
F src/vdbe.c 20bd088657280d75b630d299c59cdb3c6a5c9b9e
|
||||||
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
|
F src/vdbe.h a9166e1601f5b74c20516a74182773a20baee43e
|
||||||
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
|
F src/vdbeInt.h 31bd686595356284d5484592e2dc6e58025aa346
|
||||||
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
|
F src/vdbeapi.c f14174843bf4be2c9afdf2ef48b61e7c3ac62d7c
|
||||||
@@ -176,7 +176,7 @@ F src/vdbeaux.c db33a4c2477546da05e772352be43896d24d51d5
|
|||||||
F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
|
F src/vdbeblob.c e386d49d8354aa5a58f0a7f2794303442c149120
|
||||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||||
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
|
F src/vdbemem.c a86119b5ccc41ab8653e4746f83d591ff0ae892e
|
||||||
F src/vtab.c 03014b2bfa8096ecac5fcdc80d34cd76e06af52a
|
F src/vtab.c 7f206d148f6e76f427f008f589610c72a4b9336c
|
||||||
F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e
|
F src/where.c 9705df3c2b78ea8e02a768be8ac5d3f7a2902f1e
|
||||||
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
@@ -417,10 +417,11 @@ F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
|
|||||||
F test/select1.test 871df931cbbc0e78170605628e8b5fc60765e265
|
F test/select1.test 871df931cbbc0e78170605628e8b5fc60765e265
|
||||||
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
|
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
|
||||||
F test/select3.test 7f99c0d4067064e0865479a56faa7aaa29b9041a
|
F test/select3.test 7f99c0d4067064e0865479a56faa7aaa29b9041a
|
||||||
F test/select4.test 69015a6c02c3d8efed01f15e5d025fb4e5256183
|
F test/select4.test 491193f50799e7fdb375ef04a1a8f40393dd7cfe
|
||||||
F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
|
F test/select5.test 0b47058d3e916c1fc9fe81f44b438e02bade21ce
|
||||||
F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8
|
F test/select6.test 399f14b9ba37b768afe5d2cd8c12e4f340a69db8
|
||||||
F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f
|
F test/select7.test 7906735805cfbee4dddc0bed4c14e68d7f5f9c5f
|
||||||
|
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||||
F test/shared.test 9a1e81629efaebaad2247e9e81aa33570fba8f13
|
F test/shared.test 9a1e81629efaebaad2247e9e81aa33570fba8f13
|
||||||
F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4
|
F test/shared2.test 0ee9de8964d70e451936a48c41cb161d9134ccf4
|
||||||
@@ -605,7 +606,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 6de0ee49073c7a47d5e10495b569b33df76d1448
|
P 4744257d3cd2dd96485fde6d9f60542714383421
|
||||||
R 72b005345d91bd390788cc14572cdea6
|
R 9fded3f0e818ece501c0ececcbd26a94
|
||||||
U drh
|
U drh
|
||||||
Z f60ae65829aa8eb88bba7196814bec78
|
Z fe475f28d0df336b5a859493e9293538
|
||||||
|
@@ -1 +1 @@
|
|||||||
4744257d3cd2dd96485fde6d9f60542714383421
|
a6dddebcc5ccbbf3009c9d06163a8b59036331de
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code associated with the ANALYZE command.
|
** 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
|
#ifndef SQLITE_OMIT_ANALYZE
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@@ -33,6 +33,7 @@ static void openStatTable(
|
|||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
Db *pDb;
|
Db *pDb;
|
||||||
int iRootPage;
|
int iRootPage;
|
||||||
|
int createStat1 = 0;
|
||||||
Table *pStat;
|
Table *pStat;
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
|
|
||||||
@@ -43,13 +44,14 @@ static void openStatTable(
|
|||||||
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
|
if( (pStat = sqlite3FindTable(db, "sqlite_stat1", pDb->zName))==0 ){
|
||||||
/* The sqlite_stat1 tables does not exist. Create it.
|
/* The sqlite_stat1 tables does not exist. Create it.
|
||||||
** Note that a side-effect of the CREATE TABLE statement is to leave
|
** 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. */
|
** important because the OpenWrite opcode below will be needing it. */
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
|
"CREATE TABLE %Q.sqlite_stat1(tbl,idx,stat)",
|
||||||
pDb->zName
|
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 ){
|
}else if( zWhere ){
|
||||||
/* The sqlite_stat1 table exists. Delete all entries associated with
|
/* The sqlite_stat1 table exists. Delete all entries associated with
|
||||||
** the table zWhere. */
|
** the table zWhere. */
|
||||||
@@ -69,13 +71,11 @@ static void openStatTable(
|
|||||||
** If this vdbe did create the sqlite_stat1 table, then it must have
|
** If this vdbe did create the sqlite_stat1 table, then it must have
|
||||||
** already obtained a schema-lock, making the write-lock redundant.
|
** already obtained a schema-lock, making the write-lock redundant.
|
||||||
*/
|
*/
|
||||||
if( iRootPage>0 ){
|
if( !createStat1 ){
|
||||||
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
|
sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1");
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
|
sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur, iRootPage, iDb);
|
||||||
if( iRootPage==0 ){
|
sqlite3VdbeChangeP5(v, createStat1);
|
||||||
sqlite3VdbeChangeP5(v, 1);
|
|
||||||
}
|
|
||||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iStatCur, 3);
|
sqlite3VdbeAddOp2(v, OP_SetNumColumns, iStatCur, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
src/build.c
66
src/build.c
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -838,8 +838,9 @@ void sqlite3StartTable(
|
|||||||
** now.
|
** now.
|
||||||
*/
|
*/
|
||||||
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
|
if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||||
int lbl;
|
int j1;
|
||||||
int fileFormat;
|
int fileFormat;
|
||||||
|
int reg1, reg2, reg3;
|
||||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
@@ -851,17 +852,19 @@ void sqlite3StartTable(
|
|||||||
/* If the file format and encoding in the database have not been set,
|
/* If the file format and encoding in the database have not been set,
|
||||||
** set them now.
|
** 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);
|
sqlite3VdbeUsesBtree(v, iDb);
|
||||||
lbl = sqlite3VdbeMakeLabel(v);
|
j1 = sqlite3VdbeAddOp1(v, OP_If, reg3);
|
||||||
sqlite3VdbeAddOp2(v, OP_If, 0, lbl);
|
|
||||||
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
|
fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
|
||||||
1 : SQLITE_MAX_FILE_FORMAT;
|
1 : SQLITE_MAX_FILE_FORMAT;
|
||||||
sqlite3VdbeAddOp1(v, OP_Integer, fileFormat);
|
sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
|
||||||
sqlite3VdbeAddOp2(v, OP_SetCookie, iDb, 1);
|
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, reg3);
|
||||||
sqlite3VdbeAddOp1(v, OP_Integer, ENC(db));
|
sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
|
||||||
sqlite3VdbeAddOp2(v, OP_SetCookie, iDb, 4);
|
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 4, reg3);
|
||||||
sqlite3VdbeResolveLabel(v, lbl);
|
sqlite3VdbeJumpHere(v, j1);
|
||||||
|
|
||||||
/* This just creates a place-holder record in the sqlite_master table.
|
/* This just creates a place-holder record in the sqlite_master table.
|
||||||
** The record created does not contain anything yet. It will be replaced
|
** 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 !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||||
if( isView || isVirtual ){
|
if( isView || isVirtual ){
|
||||||
sqlite3VdbeAddOp0(v, OP_Integer);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, reg2);
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
sqlite3VdbeAddOp1(v, OP_CreateTable, iDb);
|
sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
|
||||||
}
|
}
|
||||||
sqlite3OpenMasterTable(pParse, iDb);
|
sqlite3OpenMasterTable(pParse, iDb);
|
||||||
sqlite3VdbeAddOp0(v, OP_NewRowid);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
|
||||||
sqlite3VdbeAddOp0(v, OP_Copy);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, reg3);
|
||||||
sqlite3VdbeAddOp0(v, OP_Null);
|
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
|
||||||
sqlite3CodeInsert(pParse, 0, OPFLAG_APPEND);
|
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||||
sqlite3VdbeAddOp0(v, OP_Close);
|
sqlite3VdbeAddOp0(v, OP_Close);
|
||||||
sqlite3VdbeAddOp1(v, OP_Pull, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Normal (non-error) return. */
|
/* Normal (non-error) return. */
|
||||||
@@ -1494,8 +1496,7 @@ void sqlite3EndTable(
|
|||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
Table *pSelTab;
|
Table *pSelTab;
|
||||||
|
|
||||||
sqlite3VdbeAddOp0(v, OP_Copy);
|
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse->regRoot, iDb);
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb);
|
|
||||||
sqlite3VdbeChangeP5(v, 1);
|
sqlite3VdbeChangeP5(v, 1);
|
||||||
pParse->nTab = 2;
|
pParse->nTab = 2;
|
||||||
sqlite3SelectDestInit(&dest, SRT_Table, 1);
|
sqlite3SelectDestInit(&dest, SRT_Table, 1);
|
||||||
@@ -1531,13 +1532,15 @@ void sqlite3EndTable(
|
|||||||
*/
|
*/
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"UPDATE %Q.%s "
|
"UPDATE %Q.%s "
|
||||||
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q "
|
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
|
||||||
"WHERE rowid=#1",
|
"WHERE rowid=#%d",
|
||||||
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
||||||
zType,
|
zType,
|
||||||
p->zName,
|
p->zName,
|
||||||
p->zName,
|
p->zName,
|
||||||
zStmt
|
pParse->regRoot,
|
||||||
|
zStmt,
|
||||||
|
pParse->regRowid
|
||||||
);
|
);
|
||||||
sqlite3_free(zStmt);
|
sqlite3_free(zStmt);
|
||||||
sqlite3ChangeCookie(db, v, iDb);
|
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){
|
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
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
|
#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
|
** 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
|
** location iTable. The following code modifies the sqlite_master table to
|
||||||
** reflect this.
|
** 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().
|
** is on the top of the stack. See sqlite3RegisterExpr().
|
||||||
*/
|
*/
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"UPDATE %Q.%s SET rootpage=%d WHERE #0 AND rootpage=#0",
|
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
||||||
pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable);
|
pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
|
||||||
#endif
|
#endif
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2649,8 +2654,7 @@ void sqlite3CreateIndex(
|
|||||||
/* Create the rootpage for the index
|
/* Create the rootpage for the index
|
||||||
*/
|
*/
|
||||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||||
sqlite3VdbeAddOp1(v, OP_CreateIndex, iDb);
|
sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem);
|
|
||||||
|
|
||||||
/* Gather the complete text of the CREATE INDEX statement into
|
/* Gather the complete text of the CREATE INDEX statement into
|
||||||
** the zStmt variable
|
** the zStmt variable
|
||||||
@@ -2670,13 +2674,13 @@ void sqlite3CreateIndex(
|
|||||||
/* Add an entry in sqlite_master for this index
|
/* Add an entry in sqlite_master for this index
|
||||||
*/
|
*/
|
||||||
sqlite3NestedParse(pParse,
|
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),
|
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
||||||
pIndex->zName,
|
pIndex->zName,
|
||||||
pTab->zName,
|
pTab->zName,
|
||||||
|
iMem,
|
||||||
zStmt
|
zStmt
|
||||||
);
|
);
|
||||||
sqlite3VdbeAddOp1(v, OP_Pop, 1);
|
|
||||||
sqlite3_free(zStmt);
|
sqlite3_free(zStmt);
|
||||||
|
|
||||||
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
||||||
|
24
src/delete.c
24
src/delete.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -60,20 +60,6 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
|||||||
return 0;
|
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
|
** Allocate nVal contiguous memory cells and return the index of the
|
||||||
** first. Also pop nVal elements from the stack and store them in 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;
|
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.
|
** Generate code that will open a table for reading.
|
||||||
|
12
src/expr.c
12
src/expr.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -289,9 +289,8 @@ Expr *sqlite3PExpr(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** When doing a nested parse, you can include terms in an expression
|
** When doing a nested parse, you can include terms in an expression
|
||||||
** that look like this: #0 #1 #2 ... These terms refer to elements
|
** that look like this: #1 #2 ... These terms refer to registers
|
||||||
** on the stack. "#0" means the top of the stack.
|
** in the virtual machine. #N is the N-th register.
|
||||||
** "#1" means the next down on the stack. And so forth.
|
|
||||||
**
|
**
|
||||||
** This routine is called by the parser to deal with on of those terms.
|
** 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.
|
** It immediately generates code to store the value in a memory location.
|
||||||
@@ -301,7 +300,6 @@ Expr *sqlite3PExpr(
|
|||||||
Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
|
Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
Expr *p;
|
Expr *p;
|
||||||
int depth;
|
|
||||||
if( pParse->nested==0 ){
|
if( pParse->nested==0 ){
|
||||||
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken);
|
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", pToken);
|
||||||
return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
|
return sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
|
||||||
@@ -311,9 +309,7 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){
|
|||||||
if( p==0 ){
|
if( p==0 ){
|
||||||
return 0; /* Malloc failed */
|
return 0; /* Malloc failed */
|
||||||
}
|
}
|
||||||
depth = atoi((char*)&pToken->z[1]);
|
p->iTable = atoi((char*)&pToken->z[1]);
|
||||||
p->iTable = ++pParse->nMem;
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Copy, -depth, p->iTable);
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
src/insert.c
58
src/insert.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -519,13 +519,18 @@ void sqlite3Insert(
|
|||||||
/* Generate the subroutine that SELECT calls to process each row of
|
/* Generate the subroutine that SELECT calls to process each row of
|
||||||
** the result. Store the result in a temporary table
|
** the result. Store the result in a temporary table
|
||||||
*/
|
*/
|
||||||
|
int regRec, regRowid;
|
||||||
|
|
||||||
srcTab = pParse->nTab++;
|
srcTab = pParse->nTab++;
|
||||||
|
regRec = sqlite3GetTempReg(pParse);
|
||||||
|
regRowid = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
||||||
sqlite3VdbeAddOp2(v, OP_RegMakeRec, regFromSelect, nColumn);
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regFromSelect, nColumn, regRec);
|
||||||
sqlite3VdbeAddOp1(v, OP_NewRowid, srcTab);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid);
|
||||||
sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
|
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid);
|
||||||
sqlite3CodeInsert(pParse, srcTab, OPFLAG_APPEND);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regRec);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||||
|
|
||||||
/* The following code runs first because the GOTO at the very top
|
/* The following code runs first because the GOTO at the very top
|
||||||
** of the program jumps to it. Create the temporary table, then jump
|
** of the program jumps to it. Create the temporary table, then jump
|
||||||
@@ -663,7 +668,6 @@ void sqlite3Insert(
|
|||||||
}else if( pSelect ){
|
}else if( pSelect ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, iSelectLoop);
|
||||||
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
sqlite3VdbeResolveLabel(v, iInsertBlock);
|
||||||
sqlite3RegToStack(pParse, regFromSelect, nColumn);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
|
sqlite3VdbeAddOp2(v, OP_StackDepth, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,7 +774,7 @@ void sqlite3Insert(
|
|||||||
if( useTempTable ){
|
if( useTempTable ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
|
sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
|
||||||
}else if( pSelect ){
|
}else if( pSelect ){
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn - keyColumn - 1), regRowid);
|
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid);
|
||||||
}else{
|
}else{
|
||||||
VdbeOp *pOp;
|
VdbeOp *pOp;
|
||||||
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
|
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
|
||||||
@@ -835,7 +839,7 @@ void sqlite3Insert(
|
|||||||
}else if( useTempTable ){
|
}else if( useTempTable ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
|
||||||
}else if( pSelect ){
|
}else if( pSelect ){
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn-j-1), iRegStore);
|
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
|
||||||
}else{
|
}else{
|
||||||
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
|
||||||
}
|
}
|
||||||
@@ -899,7 +903,6 @@ void sqlite3Insert(
|
|||||||
sqlite3VdbeResolveLabel(v, iBreak);
|
sqlite3VdbeResolveLabel(v, iBreak);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, srcTab, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, srcTab, 0);
|
||||||
}else if( pSelect ){
|
}else if( pSelect ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, nColumn, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
|
sqlite3VdbeAddOp2(v, OP_Return, 0, 0);
|
||||||
sqlite3VdbeResolveLabel(v, iCleanup);
|
sqlite3VdbeResolveLabel(v, iCleanup);
|
||||||
}
|
}
|
||||||
@@ -1279,6 +1282,7 @@ void sqlite3CompleteInsertion(
|
|||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
int pik_flags;
|
int pik_flags;
|
||||||
int regData;
|
int regData;
|
||||||
|
int regRec;
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
assert( v!=0 );
|
assert( v!=0 );
|
||||||
@@ -1289,14 +1293,12 @@ void sqlite3CompleteInsertion(
|
|||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
|
||||||
}
|
}
|
||||||
regData = regRowid + 1;
|
regData = regRowid + 1;
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
regRec = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_RegMakeRec, regData, pTab->nCol);
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regData, pTab->nCol, regRec);
|
||||||
sqlite3TableAffinityStr(v, pTab);
|
sqlite3TableAffinityStr(v, pTab);
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
if( newIdx>=0 ){
|
if( newIdx>=0 ){
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
|
sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
|
||||||
sqlite3VdbeAddOp1(v, OP_SCopy, -1);
|
|
||||||
sqlite3CodeInsert(pParse, newIdx, 0);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if( pParse->nested ){
|
if( pParse->nested ){
|
||||||
@@ -1308,10 +1310,11 @@ void sqlite3CompleteInsertion(
|
|||||||
if( appendBias ){
|
if( appendBias ){
|
||||||
pik_flags |= OPFLAG_APPEND;
|
pik_flags |= OPFLAG_APPEND;
|
||||||
}
|
}
|
||||||
sqlite3CodeInsert(pParse, baseCur, pik_flags);
|
sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
|
||||||
if( !pParse->nested ){
|
if( !pParse->nested ){
|
||||||
sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC);
|
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 */
|
KeyInfo *pKey; /* Key information for an index */
|
||||||
int regAutoinc; /* Memory register used by AUTOINC */
|
int regAutoinc; /* Memory register used by AUTOINC */
|
||||||
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
|
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
|
||||||
|
int regData, regRowid; /* Registers holding data and rowid */
|
||||||
|
|
||||||
if( pSelect==0 ){
|
if( pSelect==0 ){
|
||||||
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
||||||
@@ -1612,22 +1616,24 @@ static int xferOptimization(
|
|||||||
}
|
}
|
||||||
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
|
||||||
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
||||||
|
regData = sqlite3GetTempReg(pParse);
|
||||||
|
regRowid = sqlite3GetTempReg(pParse);
|
||||||
if( pDest->iPKey>=0 ){
|
if( pDest->iPKey>=0 ){
|
||||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||||
sqlite3VdbeAddOp0(v, OP_Copy);
|
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||||
addr2 = sqlite3VdbeAddOp2(v, OP_NotExists, iDest, 0);
|
|
||||||
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
|
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
|
||||||
"PRIMARY KEY must be unique", P4_STATIC);
|
"PRIMARY KEY must be unique", P4_STATIC);
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
autoIncStep(pParse, regAutoinc, 0);
|
autoIncStep(pParse, regAutoinc, regRowid);
|
||||||
}else if( pDest->pIndex==0 ){
|
}else if( pDest->pIndex==0 ){
|
||||||
addr1 = sqlite3VdbeAddOp1(v, OP_NewRowid, iDest);
|
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
|
||||||
}else{
|
}else{
|
||||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0);
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||||
assert( pDest->autoInc==0 );
|
assert( pDest->autoInc==0 );
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp1(v, OP_RowData, iSrc);
|
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
|
||||||
sqlite3CodeInsert(pParse,iDest,OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
|
sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
||||||
|
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
|
||||||
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
|
sqlite3VdbeChangeP4(v, -1, pDest->zName, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
|
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1);
|
||||||
autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
|
autoIncEnd(pParse, iDbDest, pDest, regAutoinc);
|
||||||
@@ -1647,12 +1653,14 @@ static int xferOptimization(
|
|||||||
(char*)pKey, P4_KEYINFO_HANDOFF);
|
(char*)pKey, P4_KEYINFO_HANDOFF);
|
||||||
VdbeComment((v, "%s", pDestIdx->zName));
|
VdbeComment((v, "%s", pDestIdx->zName));
|
||||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0);
|
||||||
sqlite3VdbeAddOp1(v, OP_RowKey, iSrc);
|
sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
|
||||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, 0, 1);
|
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
|
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1);
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, emptySrcTest);
|
sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||||
|
sqlite3ReleaseTempReg(pParse, regData);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||||
if( emptyDestTest ){
|
if( emptyDestTest ){
|
||||||
|
99
src/select.c
99
src/select.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** 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"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -394,7 +394,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|||||||
static void pushOntoSorter(
|
static void pushOntoSorter(
|
||||||
Parse *pParse, /* Parser context */
|
Parse *pParse, /* Parser context */
|
||||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
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;
|
Vdbe *v = pParse->pVdbe;
|
||||||
int nExpr = pOrderBy->nExpr;
|
int nExpr = pOrderBy->nExpr;
|
||||||
@@ -402,15 +403,21 @@ static void pushOntoSorter(
|
|||||||
int regRecord = sqlite3GetTempReg(pParse);
|
int regRecord = sqlite3GetTempReg(pParse);
|
||||||
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase);
|
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase);
|
||||||
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
|
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);
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, regBase, nExpr + 2, regRecord);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord);
|
||||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||||
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
|
||||||
if( pSelect->iLimit>=0 ){
|
if( pSelect->iLimit>=0 ){
|
||||||
int addr1, addr2;
|
int addr1, addr2;
|
||||||
addr1 = sqlite3VdbeAddOp1(v, OP_IfZero, pSelect->iLimit+1);
|
int iLimit;
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, pSelect->iLimit+1, -1);
|
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);
|
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
|
||||||
@@ -426,16 +433,12 @@ static void pushOntoSorter(
|
|||||||
static void codeOffset(
|
static void codeOffset(
|
||||||
Vdbe *v, /* Generate code into this VM */
|
Vdbe *v, /* Generate code into this VM */
|
||||||
Select *p, /* The SELECT statement being coded */
|
Select *p, /* The SELECT statement being coded */
|
||||||
int iContinue, /* Jump here to skip the current record */
|
int iContinue /* Jump here to skip the current record */
|
||||||
int nPop /* Number of times to pop stack when jumping */
|
|
||||||
){
|
){
|
||||||
if( p->iOffset>=0 && iContinue!=0 ){
|
if( p->iOffset>=0 && iContinue!=0 ){
|
||||||
int addr;
|
int addr;
|
||||||
sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
|
sqlite3VdbeAddOp2(v, OP_AddImm, p->iOffset, -1);
|
||||||
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
|
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, p->iOffset);
|
||||||
if( nPop>0 ){
|
|
||||||
sqlite3VdbeAddOp1(v, OP_Pop, nPop);
|
|
||||||
}
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
|
||||||
VdbeComment((v, "skip OFFSET records"));
|
VdbeComment((v, "skip OFFSET records"));
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
@@ -524,7 +527,7 @@ static int selectInnerLoop(
|
|||||||
*/
|
*/
|
||||||
hasDistinct = distinct>=0 && pEList->nExpr>0;
|
hasDistinct = distinct>=0 && pEList->nExpr>0;
|
||||||
if( pOrderBy==0 && !hasDistinct ){
|
if( pOrderBy==0 && !hasDistinct ){
|
||||||
codeOffset(v, p, iContinue, 0);
|
codeOffset(v, p, iContinue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pull the requested columns.
|
/* Pull the requested columns.
|
||||||
@@ -563,7 +566,7 @@ static int selectInnerLoop(
|
|||||||
assert( pEList->nExpr==nColumn );
|
assert( pEList->nExpr==nColumn );
|
||||||
codeDistinct(v, distinct, iContinue, nColumn, iMem);
|
codeDistinct(v, distinct, iContinue, nColumn, iMem);
|
||||||
if( pOrderBy==0 ){
|
if( pOrderBy==0 ){
|
||||||
codeOffset(v, p, iContinue, nColumn);
|
codeOffset(v, p, iContinue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,14 +606,18 @@ static int selectInnerLoop(
|
|||||||
*/
|
*/
|
||||||
case SRT_Table:
|
case SRT_Table:
|
||||||
case SRT_EphemTab: {
|
case SRT_EphemTab: {
|
||||||
sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1);
|
||||||
if( pOrderBy ){
|
if( pOrderBy ){
|
||||||
pushOntoSorter(pParse, pOrderBy, p);
|
pushOntoSorter(pParse, pOrderBy, p, r1);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp1(v, OP_NewRowid, iParm);
|
int r2 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_Pull, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
|
||||||
sqlite3CodeInsert(pParse, iParm, OPFLAG_APPEND);
|
sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2);
|
||||||
|
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r2);
|
||||||
}
|
}
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,11 +637,12 @@ static int selectInnerLoop(
|
|||||||
** ORDER BY in this case since the order of entries in the set
|
** 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
|
** does not matter. But there might be a LIMIT clause, in which
|
||||||
** case the order does matter */
|
** case the order does matter */
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
|
pushOntoSorter(pParse, pOrderBy, p, iMem);
|
||||||
pushOntoSorter(pParse, pOrderBy, p);
|
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, 0, &p->affinity, 1);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0);
|
sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 1, r1, &p->affinity, 1);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, addr2);
|
sqlite3VdbeJumpHere(v, addr2);
|
||||||
break;
|
break;
|
||||||
@@ -654,11 +662,10 @@ static int selectInnerLoop(
|
|||||||
*/
|
*/
|
||||||
case SRT_Mem: {
|
case SRT_Mem: {
|
||||||
assert( nColumn==1 );
|
assert( nColumn==1 );
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, 0);
|
|
||||||
if( pOrderBy ){
|
if( pOrderBy ){
|
||||||
pushOntoSorter(pParse, pOrderBy, p);
|
pushOntoSorter(pParse, pOrderBy, p, iMem);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Move, 0, iParm);
|
sqlite3VdbeAddOp2(v, OP_Move, iMem, iParm);
|
||||||
/* The LIMIT clause will jump out of the loop for us */
|
/* The LIMIT clause will jump out of the loop for us */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -672,8 +679,10 @@ static int selectInnerLoop(
|
|||||||
case SRT_Subroutine:
|
case SRT_Subroutine:
|
||||||
case SRT_Callback: {
|
case SRT_Callback: {
|
||||||
if( pOrderBy ){
|
if( pOrderBy ){
|
||||||
sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, nColumn);
|
int r1 = sqlite3GetTempReg(pParse);
|
||||||
pushOntoSorter(pParse, pOrderBy, p);
|
sqlite3VdbeAddOp3(v, OP_RegMakeRec, iMem, nColumn, r1);
|
||||||
|
pushOntoSorter(pParse, pOrderBy, p, r1);
|
||||||
|
sqlite3ReleaseTempReg(pParse, r1);
|
||||||
}else if( eDest==SRT_Subroutine ){
|
}else if( eDest==SRT_Subroutine ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
|
sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm);
|
||||||
}else{
|
}else{
|
||||||
@@ -779,7 +788,7 @@ static void generateSortTail(
|
|||||||
sqlite3VdbeAddOp2(v, OP_SetNumColumns, pseudoTab, nColumn);
|
sqlite3VdbeAddOp2(v, OP_SetNumColumns, pseudoTab, nColumn);
|
||||||
}
|
}
|
||||||
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
|
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, brk);
|
||||||
codeOffset(v, p, cont, 0);
|
codeOffset(v, p, cont);
|
||||||
regRow = sqlite3GetTempReg(pParse);
|
regRow = sqlite3GetTempReg(pParse);
|
||||||
regRowid = sqlite3GetTempReg(pParse);
|
regRowid = sqlite3GetTempReg(pParse);
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow);
|
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;
|
Vdbe *v = 0;
|
||||||
int iLimit = 0;
|
int iLimit = 0;
|
||||||
int iOffset;
|
int iOffset;
|
||||||
int addr1, addr2;
|
int addr1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** "LIMIT -1" always shows all rows. There is some
|
** "LIMIT -1" always shows all rows. There is some
|
||||||
@@ -1747,42 +1756,34 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
|||||||
*/
|
*/
|
||||||
if( p->pLimit ){
|
if( p->pLimit ){
|
||||||
p->iLimit = iLimit = ++pParse->nMem;
|
p->iLimit = iLimit = ++pParse->nMem;
|
||||||
pParse->nMem++;
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
if( v==0 ) return;
|
if( v==0 ) return;
|
||||||
sqlite3ExprCode(pParse, p->pLimit, 0);
|
sqlite3ExprCode(pParse, p->pLimit, iLimit);
|
||||||
sqlite3VdbeAddOp0(v, OP_MustBeInt);
|
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit);
|
||||||
sqlite3VdbeAddOp2(v, OP_Move, 0, iLimit);
|
|
||||||
VdbeComment((v, "LIMIT counter"));
|
VdbeComment((v, "LIMIT counter"));
|
||||||
sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak);
|
sqlite3VdbeAddOp2(v, OP_IfZero, iLimit, iBreak);
|
||||||
sqlite3VdbeAddOp2(v, OP_SCopy, iLimit, 0);
|
|
||||||
}
|
}
|
||||||
if( p->pOffset ){
|
if( p->pOffset ){
|
||||||
p->iOffset = iOffset = ++pParse->nMem;
|
p->iOffset = iOffset = ++pParse->nMem;
|
||||||
|
if( p->pLimit ){
|
||||||
|
pParse->nMem++; /* Allocate an extra register for limit+offset */
|
||||||
|
}
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
if( v==0 ) return;
|
if( v==0 ) return;
|
||||||
sqlite3ExprCode(pParse, p->pOffset, 0);
|
sqlite3ExprCode(pParse, p->pOffset, iOffset);
|
||||||
sqlite3VdbeAddOp0(v, OP_MustBeInt);
|
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset);
|
||||||
sqlite3VdbeAddOp2(v, p->pLimit==0 ? OP_Move : OP_Copy, 0, iOffset);
|
|
||||||
VdbeComment((v, "OFFSET counter"));
|
VdbeComment((v, "OFFSET counter"));
|
||||||
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
|
addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset);
|
||||||
sqlite3VdbeAddOp2(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
|
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
if( p->pLimit ){
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** 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_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1420,6 +1420,8 @@ struct Parse {
|
|||||||
/* Above is constant between recursions. Below is reset before and after
|
/* Above is constant between recursions. Below is reset before and after
|
||||||
** each recursion */
|
** 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 nVar; /* Number of '?' variables seen in the SQL so far */
|
||||||
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
int nVarExpr; /* Number of used slots in apVarExpr[] */
|
||||||
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
|
||||||
@@ -1945,9 +1947,7 @@ int sqlite3OpenTempDatabase(Parse *);
|
|||||||
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
|
void sqlite3StrAccumAppend(StrAccum*,const char*,int);
|
||||||
char *sqlite3StrAccumFinish(StrAccum*);
|
char *sqlite3StrAccumFinish(StrAccum*);
|
||||||
void sqlite3StrAccumReset(StrAccum*);
|
void sqlite3StrAccumReset(StrAccum*);
|
||||||
void sqlite3CodeInsert(Parse *, int, u8);
|
|
||||||
int sqlite3StackToReg(Parse *, int);
|
int sqlite3StackToReg(Parse *, int);
|
||||||
void sqlite3RegToStack(Parse *, int, int);
|
|
||||||
void sqlite3SelectDestInit(SelectDest*,int,int);
|
void sqlite3SelectDestInit(SelectDest*,int,int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
74
src/vdbe.c
74
src/vdbe.c
@@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** 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 "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -94,6 +94,18 @@ int sqlite3_sort_count = 0;
|
|||||||
int sqlite3_max_blobsize = 0;
|
int sqlite3_max_blobsize = 0;
|
||||||
#endif
|
#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
|
** Release the memory associated with the given stack level. This
|
||||||
** leaves the Mem.flags field in an inconsistent state.
|
** 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 ){
|
if( pOp->p1>SQLITE_MAX_LENGTH ){
|
||||||
goto too_big;
|
goto too_big;
|
||||||
}
|
}
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -959,6 +972,7 @@ case OP_String: { /* out2-prerelease */
|
|||||||
pOut->z = pOp->p4.z;
|
pOut->z = pOp->p4.z;
|
||||||
pOut->n = pOp->p1;
|
pOut->n = pOp->p1;
|
||||||
pOut->enc = encoding;
|
pOut->enc = encoding;
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,6 +1033,7 @@ case OP_Blob: { /* out2-prerelease */
|
|||||||
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
|
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
|
||||||
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
|
sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
|
||||||
pOut->enc = encoding;
|
pOut->enc = encoding;
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_BLOB_LITERAL */
|
#endif /* SQLITE_OMIT_BLOB_LITERAL */
|
||||||
@@ -1043,6 +1058,7 @@ case OP_Variable: { /* out2-prerelease */
|
|||||||
goto too_big;
|
goto too_big;
|
||||||
}
|
}
|
||||||
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
|
sqlite3VdbeMemShallowCopy(pOut, &p->aVar[j], MEM_Static);
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1136,40 +1152,6 @@ case OP_SCopy: {
|
|||||||
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 *
|
/* Opcode: ResultRow P1 P2 *
|
||||||
**
|
**
|
||||||
** The registers P1 throught P1+P2-1 contain a single row of
|
** 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->xDel = 0;
|
||||||
pOut->enc = encoding;
|
pOut->enc = encoding;
|
||||||
pOut->z = zNew;
|
pOut->z = zNew;
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1489,6 +1472,7 @@ case OP_Function: {
|
|||||||
if( sqlite3VdbeMemTooBig(pOut) ){
|
if( sqlite3VdbeMemTooBig(pOut) ){
|
||||||
goto too_big;
|
goto too_big;
|
||||||
}
|
}
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1658,6 +1642,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, no-push, in1 */
|
|||||||
rc = ExpandBlob(pIn1);
|
rc = ExpandBlob(pIn1);
|
||||||
assert( pIn1->flags & MEM_Str );
|
assert( pIn1->flags & MEM_Str );
|
||||||
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
|
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
|
||||||
|
UPDATE_MAX_BLOBSIZE(pIn1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1679,6 +1664,7 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, no-push, in1 */
|
|||||||
pIn1->flags |= MEM_Blob;
|
pIn1->flags |= MEM_Blob;
|
||||||
}
|
}
|
||||||
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
|
pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
|
||||||
|
UPDATE_MAX_BLOBSIZE(pIn1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2337,6 +2323,7 @@ case OP_Column: {
|
|||||||
rc = sqlite3VdbeMemMakeWriteable(pDest);
|
rc = sqlite3VdbeMemMakeWriteable(pDest);
|
||||||
|
|
||||||
op_column_out:
|
op_column_out:
|
||||||
|
UPDATE_MAX_BLOBSIZE(pDest);
|
||||||
REGISTER_TRACE(pOp->p3, pDest);
|
REGISTER_TRACE(pOp->p3, pDest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2525,6 +2512,7 @@ case OP_MakeRecord: { /* jump */
|
|||||||
}
|
}
|
||||||
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
|
pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
|
||||||
REGISTER_TRACE(pOp->p3, pOut);
|
REGISTER_TRACE(pOp->p3, pOut);
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
|
|
||||||
/* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
|
/* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
|
||||||
if( jumpIfNull && containsNull ){
|
if( jumpIfNull && containsNull ){
|
||||||
@@ -2683,7 +2671,7 @@ case OP_ReadCookie: { /* out2-prerelease */
|
|||||||
int iDb = pOp->p1;
|
int iDb = pOp->p1;
|
||||||
int iCookie = pOp->p3;
|
int iCookie = pOp->p3;
|
||||||
|
|
||||||
assert( pOp->p2<SQLITE_N_BTREE_META );
|
assert( pOp->p3<SQLITE_N_BTREE_META );
|
||||||
if( iDb<0 ){
|
if( iDb<0 ){
|
||||||
iDb = (-1*(iDb+1));
|
iDb = (-1*(iDb+1));
|
||||||
iCookie *= -1;
|
iCookie *= -1;
|
||||||
@@ -3819,6 +3807,7 @@ case OP_RowData: { /* out2-prerelease */
|
|||||||
pOut->flags = MEM_Null;
|
pOut->flags = MEM_Null;
|
||||||
}
|
}
|
||||||
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
|
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
|
||||||
|
UPDATE_MAX_BLOBSIZE(pOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4440,6 +4429,7 @@ case OP_IntegrityCk: {
|
|||||||
pIn1->xDel = 0;
|
pIn1->xDel = 0;
|
||||||
}
|
}
|
||||||
pIn1->enc = SQLITE_UTF8;
|
pIn1->enc = SQLITE_UTF8;
|
||||||
|
UPDATE_MAX_BLOBSIZE(pIn1);
|
||||||
sqlite3VdbeChangeEncoding(pIn1, encoding);
|
sqlite3VdbeChangeEncoding(pIn1, encoding);
|
||||||
sqlite3_free(aRoot);
|
sqlite3_free(aRoot);
|
||||||
break;
|
break;
|
||||||
@@ -4656,6 +4646,7 @@ case OP_AggFinal: { /* no-push */
|
|||||||
if( rc==SQLITE_ERROR ){
|
if( rc==SQLITE_ERROR ){
|
||||||
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
|
sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pMem), (char*)0);
|
||||||
}
|
}
|
||||||
|
UPDATE_MAX_BLOBSIZE(pMem);
|
||||||
if( sqlite3VdbeMemTooBig(pMem) ){
|
if( sqlite3VdbeMemTooBig(pMem) ){
|
||||||
goto too_big;
|
goto too_big;
|
||||||
}
|
}
|
||||||
@@ -4961,6 +4952,7 @@ case OP_VColumn: {
|
|||||||
pDest->flags = 0;
|
pDest->flags = 0;
|
||||||
}
|
}
|
||||||
sqlite3VdbeMemMove(pDest, &sContext.s);
|
sqlite3VdbeMemMove(pDest, &sContext.s);
|
||||||
|
UPDATE_MAX_BLOBSIZE(pDest);
|
||||||
|
|
||||||
if( sqlite3SafetyOn(db) ){
|
if( sqlite3SafetyOn(db) ){
|
||||||
goto abort_due_to_misuse;
|
goto abort_due_to_misuse;
|
||||||
@@ -5134,16 +5126,6 @@ default: {
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
/* The following code adds nothing to the actual functionality
|
||||||
** of the program. It is only here for testing and debugging.
|
** of the program. It is only here for testing and debugging.
|
||||||
** On the other hand, it does burn CPU cycles every time through
|
** On the other hand, it does burn CPU cycles every time through
|
||||||
|
14
src/vtab.c
14
src/vtab.c
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to help implement virtual tables.
|
** 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
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
#include "sqliteInt.h"
|
#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
|
** SQLITE_MASTER table. We just need to update that slot with all
|
||||||
** the information we've collected.
|
** the information we've collected.
|
||||||
**
|
**
|
||||||
** The top of the stack is the rootpage allocated by sqlite3StartTable().
|
** The VM register number pParse->regRowid holds the rowid of an
|
||||||
** This value is always 0 and is ignored, a virtual table does not have a
|
** entry in the sqlite_master table tht was created for this vtab
|
||||||
** rootpage. The next entry on the stack is the rowid of the record
|
** by sqlite3StartTable().
|
||||||
** in the sqlite_master table.
|
|
||||||
*/
|
*/
|
||||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"UPDATE %Q.%s "
|
"UPDATE %Q.%s "
|
||||||
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
|
"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),
|
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
||||||
pTab->zName,
|
pTab->zName,
|
||||||
pTab->zName,
|
pTab->zName,
|
||||||
zStmt
|
zStmt,
|
||||||
|
pParse->regRowid
|
||||||
);
|
);
|
||||||
sqlite3_free(zStmt);
|
sqlite3_free(zStmt);
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
# focus of this file is testing UNION, INTERSECT and EXCEPT operators
|
# focus of this file is testing UNION, INTERSECT and EXCEPT operators
|
||||||
# in SELECT statements.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -618,4 +618,55 @@ do_test select4-9.12 {
|
|||||||
|
|
||||||
} ;# ifcapable compound
|
} ;# 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
|
finish_test
|
||||||
|
62
test/select8.test
Normal file
62
test/select8.test
Normal 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
|
Reference in New Issue
Block a user