Merge the latest updates from trunk.
FossilOrigin-Name: 55c00f716dc98b188c91f3a5a010242c9497785f
This commit is contained in:
commit
a05fc913ab
@ -1050,6 +1050,7 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DBUILD_sqlite
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
TESTFIXTURE_SRC1 = sqlite3.c
|
||||
|
@ -1925,6 +1925,7 @@ sqlite3rbu.lo: $(TOP)\ext\rbu\sqlite3rbu.c $(HDR) $(EXTHDR)
|
||||
TESTFIXTURE_FLAGS = -DTCLSH=1 -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERVER=1 -DSQLITE_PRIVATE=""
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CORE $(NO_WARN)
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
|
||||
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
|
||||
|
@ -698,6 +698,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
||||
return pRet;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Release a reference to data record returned by an earlier call to
|
||||
** fts5DataRead().
|
||||
@ -2154,6 +2155,10 @@ static void fts5LeafSeek(
|
||||
iPgidx = szLeaf;
|
||||
iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
|
||||
iOff = iTermOff;
|
||||
if( iOff>n ){
|
||||
p->rc = FTS5_CORRUPT;
|
||||
return;
|
||||
}
|
||||
|
||||
while( 1 ){
|
||||
|
||||
@ -4499,7 +4504,10 @@ int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
||||
if( pLvl->aSeg ){
|
||||
int iLvl, iSeg;
|
||||
int iSegOut = 0;
|
||||
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
||||
/* Iterate through all segments, from oldest to newest. Add them to
|
||||
** the new Fts5Level object so that pLvl->aSeg[0] is the oldest
|
||||
** segment in the data structure. */
|
||||
for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
|
||||
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
||||
pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg];
|
||||
iSegOut++;
|
||||
|
@ -16,8 +16,13 @@ if {![info exists testdir]} {
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
proc return_if_no_fts5 {} {
|
||||
finish_test
|
||||
return -code return
|
||||
}
|
||||
return
|
||||
} else {
|
||||
proc return_if_no_fts5 {} {}
|
||||
}
|
||||
|
||||
catch {
|
||||
@ -25,12 +30,6 @@ catch {
|
||||
reset_db
|
||||
}
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is not defined, skip this test.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc fts5_test_poslist {cmd} {
|
||||
set res [list]
|
||||
for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5bigtok
|
||||
return_if_no_fts5
|
||||
|
||||
proc rndterm {} {
|
||||
set L [list a b c d e f g h i j k l m n o p q r s t u v w x y z]
|
||||
|
@ -13,7 +13,8 @@
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5merge
|
||||
set testprefix fts5merge2
|
||||
return_if_no_fts5
|
||||
|
||||
proc dump_structure {} {
|
||||
db eval {SELECT fts5_decode(id, block) AS t FROM t1_data WHERE id=10} {
|
||||
@ -26,8 +27,6 @@ proc dump_structure {} {
|
||||
|
||||
foreach_detail_mode $testprefix {
|
||||
|
||||
if {[detail_is_none]==0} continue
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
|
||||
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
||||
|
@ -409,5 +409,43 @@ do_catchsql_test 19.2 {
|
||||
SELECT * FROM x1 WHERE x1 MATCH 'c0 AND (c1 AND (c2 AND (c3 AND (c4 AND (c5 AND (c6 AND (c7 AND (c8 AND (c9 AND (c10 AND (c11 AND (c12 AND (c13 AND (c14 AND (c15 AND (c16 AND (c17 AND (c18 AND (c19 AND (c20 AND (c21 AND (c22 AND (c23 AND (c24 AND (c25 AND (c26 AND (c27 AND (c28 AND (c29 AND (c30 AND (c31 AND (c32 AND (c33 AND (c34 AND (c35 AND (c36 AND (c37 AND (c38 AND (c39 AND (c40 AND (c41 AND (c42 AND (c43 AND (c44 AND (c45 AND (c46 AND (c47 AND (c48 AND (c49 AND (c50 AND (c51 AND (c52 AND (c53 AND (c54 AND (c55 AND (c56 AND (c57 AND (c58 AND (c59 AND (c60 AND (c61 AND (c62 AND (c63 AND (c64 AND (c65 AND (c66 AND (c67 AND (c68 AND (c69 AND (c70 AND (c71 AND (c72 AND (c73 AND (c74 AND (c75 AND (c76 AND (c77 AND (c78 AND (c79 AND (c80 AND (c81 AND (c82 AND (c83 AND (c84 AND (c85 AND (c86 AND (c87 AND (c88 AND (c89 AND (c90 AND (c91 AND (c92 AND (c93 AND (c94 AND (c95 AND (c96 AND (c97 AND (c98 AND (c99 AND (c100 AND (c101 AND (c102 AND (c103 AND (c104 AND (c105 AND (c106 AND (c107 AND (c108 AND (c109 AND (c110 AND (c111 AND (c112 AND (c113 AND (c114 AND (c115 AND (c116 AND (c117 AND (c118 AND (c119 AND (c120 AND (c121 AND (c122 AND (c123 AND (c124 AND (c125 AND (c126 AND (c127 AND (c128 AND (c129 AND (c130 AND (c131 AND (c132 AND (c133 AND (c134 AND (c135 AND (c136 AND (c137 AND (c138 AND (c139 AND (c140 AND (c141 AND (c142 AND (c143 AND (c144 AND (c145 AND (c146 AND (c147 AND (c148 AND (c149 AND (c150 AND (c151 AND (c152 AND (c153 AND (c154 AND (c155 AND (c156 AND (c157 AND (c158 AND (c159 AND (c160 AND (c161 AND (c162 AND (c163 AND (c164 AND (c165 AND (c166 AND (c167 AND (c168 AND (c169 AND (c170 AND (c171 AND (c172 AND (c173 AND (c174 AND (c175 AND (c176 AND (c177 AND (c178 AND (c179 AND (c180 AND (c181 AND (c182 AND (c183 AND (c184 AND (c185 AND (c186 AND (c187 AND (c188 AND (c189 AND (c190 AND (c191 AND (c192 AND (c193 AND (c194 AND (c195 AND (c196 AND (c197 AND (c198 AND (c199 AND c200)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))';
|
||||
} {1 {fts5: parser stack overflow}}
|
||||
|
||||
finish_test
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
breakpoint
|
||||
do_execsql_test 20.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x);
|
||||
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO x1(rowid, x) VALUES(11111, 'onetwothree');
|
||||
}
|
||||
do_test 20.1 {
|
||||
for {set i 1} {$i <= 200} {incr i} {
|
||||
execsql { INSERT INTO x1(rowid, x) VALUES($i, 'one two three'); }
|
||||
}
|
||||
execsql { INSERT INTO x1(x1) VALUES('optimize'); }
|
||||
execsql { DELETE FROM x1 WHERE rowid = 4; }
|
||||
} {}
|
||||
do_execsql_test 20.2 {
|
||||
INSERT INTO x1(x1) VALUES('optimize');
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 20.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(x);
|
||||
INSERT INTO x1(x1, rank) VALUES('pgsz', 32);
|
||||
INSERT INTO x1(rowid, x) VALUES(11111, 'onetwothree');
|
||||
}
|
||||
do_test 20.1 {
|
||||
for {set i 1} {$i <= 200} {incr i} {
|
||||
execsql { INSERT INTO x1(rowid, x) VALUES($i, 'one two three'); }
|
||||
}
|
||||
execsql { INSERT INTO x1(x1) VALUES('optimize'); }
|
||||
execsql { DELETE FROM x1 WHERE rowid = 4; }
|
||||
} {}
|
||||
do_execsql_test 20.2 {
|
||||
INSERT INTO x1(x1) VALUES('optimize');
|
||||
INSERT INTO x1(x1) VALUES('integrity-check');
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
@ -217,6 +217,14 @@ static int seriesEof(sqlite3_vtab_cursor *cur){
|
||||
}
|
||||
}
|
||||
|
||||
/* True to cause run-time checking of the start=, stop=, and/or step=
|
||||
** parameters. The only reason to do this is for testing the
|
||||
** constraint checking logic for virtual tables in the SQLite core.
|
||||
*/
|
||||
#ifndef SQLITE_SERIES_CONSTRAINT_VERIFY
|
||||
# define SQLITE_SERIES_CONSTRAINT_VERIFY 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This method is called to "rewind" the series_cursor object back
|
||||
** to the first row of output. This method is always called at least
|
||||
@ -324,20 +332,20 @@ static int seriesBestIndex(
|
||||
}
|
||||
if( startIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[startIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
if( stopIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[stopIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
if( stepIdx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
|
||||
pIdxInfo->aConstraintUsage[stepIdx].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
|
||||
}
|
||||
if( (idxNum & 3)==3 ){
|
||||
/* Both start= and stop= boundaries are available. This is the
|
||||
** the preferred case */
|
||||
pIdxInfo->estimatedCost = (double)1;
|
||||
pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
|
||||
pIdxInfo->estimatedRows = 1000;
|
||||
if( pIdxInfo->nOrderBy==1 ){
|
||||
if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
|
||||
|
@ -1775,7 +1775,7 @@ static void scriptCodeSqlFunc(
|
||||
*/
|
||||
|
||||
/* Maximum length of a phonehash used for querying the shadow table */
|
||||
#define SPELLFIX_MX_HASH 8
|
||||
#define SPELLFIX_MX_HASH 32
|
||||
|
||||
/* Maximum number of hash strings to examine per query */
|
||||
#define SPELLFIX_MX_RUN 1
|
||||
|
4
main.mk
4
main.mk
@ -285,6 +285,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_autoext.c \
|
||||
$(TOP)/src/test_async.c \
|
||||
$(TOP)/src/test_backup.c \
|
||||
$(TOP)/src/test_bestindex.c \
|
||||
$(TOP)/src/test_blob.c \
|
||||
$(TOP)/src/test_btree.c \
|
||||
$(TOP)/src/test_config.c \
|
||||
@ -725,7 +726,8 @@ sqlite3_analyzer$(EXE): sqlite3_analyzer.c
|
||||
# Rules to build the 'testfixture' application.
|
||||
#
|
||||
TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
|
||||
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
$(TCCX) $(TCL_FLAGS) -DTCLSH=1 $(TESTFIXTURE_FLAGS) \
|
||||
|
78
manifest
78
manifest
@ -1,8 +1,8 @@
|
||||
C When\susing\sa\stemporary\sfile\sfor\sa\sstatement\sjournal,\sstore\sthe\sfirst\s64KiB\sin\smemory.\sIf\sthe\sfile\sgrows\slarger\sthan\sthat,\sflush\sit\sto\sdisk\sand\sfree\sthe\smemory.\sHardcoding\sto\s64KiB\sis\sjust\san\sexperiment\sto\scheck\sthat\sthe\smemjournal.c\scode\sworks.
|
||||
D 2016-02-29T20:18:21.986
|
||||
F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142
|
||||
C Merge\sthe\slatest\supdates\sfrom\strunk.
|
||||
D 2016-03-03T21:29:10.682
|
||||
F Makefile.in e335453db0b16da00c884ad51bb56d1c091a74de
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 4f319afb7c049d40aff7af6e8c4e7cc2ba18e079
|
||||
F Makefile.msc dbd4621ecc585c2ef0c2aa0874698c54675754f1
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION c6b1f51809551d60ad001e6d87cf3ab2c7f54b6f
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@ -104,7 +104,7 @@ F ext/fts5/fts5_buffer.c 4c1502d4c956cd092c89ce4480867f9d8bf325cd
|
||||
F ext/fts5/fts5_config.c 35c5173cae4eb17e82164a7f5aeef56a48903079
|
||||
F ext/fts5/fts5_expr.c 8e8e4635f655133eb39018072fc0f0942a2c4337
|
||||
F ext/fts5/fts5_hash.c f3a7217c86eb8f272871be5f6aa1b6798960a337
|
||||
F ext/fts5/fts5_index.c 78069efb54559a17c35906a741362d0b5c899bd0
|
||||
F ext/fts5/fts5_index.c 26a4a6112864feb599a6f6144d06a78bb179736a
|
||||
F ext/fts5/fts5_main.c db24ac714c6c4a1b3c24a1f8c25889f2952148c1
|
||||
F ext/fts5/fts5_storage.c f8343db90d8c95a4d4b52f6676e354b4649ffd6e
|
||||
F ext/fts5/fts5_tcl.c f8731e0508299bd43f1a2eff7dbeaac870768966
|
||||
@ -116,7 +116,7 @@ F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c dba72ca393d71c2588548b51380387f6b44c77a8
|
||||
F ext/fts5/fts5parse.y 86fe6ba094a47e02fe8be2571539e6833d197764
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl 61ff0d1a29d98a91c4553b20b3f410d858834ee9
|
||||
F ext/fts5/test/fts5_common.tcl b9b1fed811c0390511cef8b254826ea15d380f4d
|
||||
F ext/fts5/test/fts5aa.test 7e814df4a0e6c22a6fe2d84f210fdc0b5068a084
|
||||
F ext/fts5/test/fts5ab.test 30325a89453280160106be411bba3acf138e6d1b
|
||||
F ext/fts5/test/fts5ac.test 55cad4275a1f5acabfe14d8442a8046b47e49e5f
|
||||
@ -134,7 +134,7 @@ F ext/fts5/test/fts5auto.test 401c20e89f1114d733b94809be1e6f893e16c09e
|
||||
F ext/fts5/test/fts5aux.test 8c687c948cc98e9a94be014df7d518acc1b3b74f
|
||||
F ext/fts5/test/fts5auxdata.test 141a7cbffcceb1bd2799b4b29c183ff8780d586e
|
||||
F ext/fts5/test/fts5bigpl.test 04ee0d7eebbebf17c31f5a0b5c5f9494eac3a0cb
|
||||
F ext/fts5/test/fts5bigtok.test 981b2790f6fa02773c889bd35d42c6b97f80f0f4
|
||||
F ext/fts5/test/fts5bigtok.test 017a9397b14e7598883a6328ead4a6539b42d59a
|
||||
F ext/fts5/test/fts5columnsize.test a8cfef21ffa1c264b9f670a7d94eeaccb5341c07
|
||||
F ext/fts5/test/fts5config.test 8b2bc6dcc0eb06fa2b7dd65b2ce2db09e829e873
|
||||
F ext/fts5/test/fts5conflict.test 26f4e46c4d31e16221794832a990dc4e30e18de5
|
||||
@ -163,7 +163,7 @@ F ext/fts5/test/fts5hash.test 06f9309ccb4d5050a131594e9e47d0b21456837d
|
||||
F ext/fts5/test/fts5integrity.test f5e4f8d284385875068ad0f3e894ce43e9de835d
|
||||
F ext/fts5/test/fts5matchinfo.test f7dde99697bcb310ea8faa8eb2714d9f4dfc0e1b
|
||||
F ext/fts5/test/fts5merge.test 8f3cdba2ec9c5e7e568246e81b700ad37f764367
|
||||
F ext/fts5/test/fts5merge2.test c0cb66eb38a41c26cc5848fb9e50093e0f59ac93
|
||||
F ext/fts5/test/fts5merge2.test a6da3c16d694235938d1939f503cfa53f0943d75
|
||||
F ext/fts5/test/fts5near.test b214cddb1c1f1bddf45c75af768f20145f7e71cc
|
||||
F ext/fts5/test/fts5onepass.test 7ed9608e258132cb8d55e7c479b08676ad68810c
|
||||
F ext/fts5/test/fts5optimize.test 42741e7c085ee0a1276140a752d4407d97c2c9f5
|
||||
@ -177,7 +177,7 @@ F ext/fts5/test/fts5rank.test 7e9e64eac7245637f6f2033aec4b292aaf611aab
|
||||
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
|
||||
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
|
||||
F ext/fts5/test/fts5rowid.test 16908a99d6efc9ba21081b4f2b86b3fc699839a6
|
||||
F ext/fts5/test/fts5simple.test e6fe2fb10a2b9193648b32bbc2caecabdf8c333d
|
||||
F ext/fts5/test/fts5simple.test ac5006cc3d0d08b3538e1e76c7300de9f24fbed1
|
||||
F ext/fts5/test/fts5simple2.test 98377ae1ff7749a42c21fe1a139c1ed312522c46
|
||||
F ext/fts5/test/fts5simple3.test 8e71733b3d1b0e695011d02c68ebc5ca40b6124e
|
||||
F ext/fts5/test/fts5synonym.test 6475d189c2e20d60795808f83e36bf9318708d48
|
||||
@ -212,9 +212,9 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/series.c b8fb7befd85b3a9b4a10e701b30b2b79ca92b6d4
|
||||
F ext/misc/series.c e11e534ada797d5b816d7e7a93c022306563ca35
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 525190484b7a9dbc6be646c4842274fff4f27d53
|
||||
F ext/misc/spellfix.c 194b5fc3a9a63cb6c5680d8f713800012bddca7c
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
@ -273,7 +273,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 791597b87204f6bd56cdf7b2ab2feeecd608c60d
|
||||
F main.mk 518d93f9f606d515628f99ce03f9e909f4f8a2e3
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@ -285,7 +285,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 7603afbd61f55e7c644b8de4a42f33e58c0b7eaa
|
||||
F src/alter.c 1bb0709b3048e24217b80ec6bd78a3e99a47c01b
|
||||
F src/analyze.c ab57b6763dd4c6170a20673d14882c033affd188
|
||||
F src/attach.c a3724c64de1099d85e30751213d285752aed9505
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
@ -295,14 +295,14 @@ F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 7bb920c473c277380fcb3e8a8ee28ce1a48e0abc
|
||||
F src/btree.h a5008b9afe56e8e54ade6c436a910f112defcca9
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c 6661513c8f90a23d44ed5e5ada7ea40fac6b6b77
|
||||
F src/build.c 43b93fe757bfffe00f97462596418b052eefdccd
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 60e135af364d777a9ab41c97e5e89cd224da6198
|
||||
F src/date.c 0b73e681c11fca867fec554750c07fe0d4e417c1
|
||||
F src/dbstat.c c845548d4346e606e2f2b7d2e714ace2b8a7dd1b
|
||||
F src/delete.c 48802aa3ee6339f576d074336d3ae1b5f40e240f
|
||||
F src/expr.c 9adb58153f6e943b703d43e9a1f67f77b5a75721
|
||||
F src/expr.c c4dad2cd6cec00387b75fef4551aff655430dcd2
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 5cb42d9a59e2a590776fd3fc8ff6f61d40df3c6e
|
||||
F src/func.c 552d300265aed09eea21f68ac742a440550c0062
|
||||
@ -310,11 +310,11 @@ F src/global.c ded7b97efd16efda5062b65e857198e46c40e652
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 9ca97272e9f74ed0efddf3b4350ee12740cebbef
|
||||
F src/insert.c 723d5d708cdb61bdd47c00b9f07c75be45aefc09
|
||||
F src/journal.c 673cbdde5676eb0c55848f561575d45b609c820d
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c 9e2a41adcaff16ebc1ebff1f336cbf33de55396f
|
||||
F src/main.c be9309f442ec291177642d2e48e82290e0951f4b
|
||||
F src/main.c 32c45647866429f34d7a13a717172a8e7d0a1056
|
||||
F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
|
||||
@ -338,27 +338,27 @@ F src/os_win.c f0d7aa603eb6262143d7169a222aea07c4fca91d
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/pager.c 2bc43817697b5a4e88fd6a2cdb2cb25f2223505c
|
||||
F src/pager.h e1d38a2f14849e219df0f91f8323504d134c8a56
|
||||
F src/parse.y c3ce2c4a7cbf0b699239be6b2a945c5cb51875e2
|
||||
F src/parse.y 5ea8c81c5c41b27887f41b4a7e1c58470d7d3821
|
||||
F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
|
||||
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
|
||||
F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
|
||||
F src/pragma.c d6028d23a9495a8b55f2075e3244ec9a0485e03e
|
||||
F src/pragma.c 42b3f1475b483710ba1dd1cc1ecc0c0f8db59a2e
|
||||
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
|
||||
F src/prepare.c 22df6171aec1d86904ed2ad30c2348a5748aa04e
|
||||
F src/printf.c 63e6fb12bbe702dd664dc3703776c090383a5a26
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c b8f7174e5f8c33c44ded3a25a973d0bb89228c20
|
||||
F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
|
||||
F src/select.c 1bacfde7b7cec134d2b354cbcf67bafc67078431
|
||||
F src/select.c 137b31daa84d57d67847bf621bb54f3353e2077b
|
||||
F src/shell.c 5e0ab1e708dc294330ccd8230536e1801f60822e
|
||||
F src/sqlite.h.in 57d2a02b14c9ec4f7cb294153eaf62294dc5aa68
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
||||
F src/sqliteInt.h 3c4ed7e5dcb8b7d4cd4ab258ee7d0e0d0368f014
|
||||
F src/sqliteInt.h 57da6fd6aa35dff72eb946064ff4999eab6bc616
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
F src/tclsqlite.c 13debcc6a5ca1217486f8903768c01114fbe8b58
|
||||
F src/tclsqlite.c 54dca4eaf3a9cb0a4b845ef54ffa99225c30a52e
|
||||
F src/test1.c f14a6f9e2cff6cba4d83e2b0c52857f61886cead
|
||||
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
|
||||
F src/test3.c a8887dabbbee3059af338f20d290084a63ed1b0f
|
||||
@ -371,6 +371,7 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803
|
||||
F src/test_bestindex.c cd36324f05404df5f1a82608a321b91932a549ea
|
||||
F src/test_blob.c b2551a9b5573232db5f66f292307c37067937239
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c 0dee90328e3dedf8ba002ee94b6a7e7ea7726fe4
|
||||
@ -408,11 +409,11 @@ F src/test_windirent.h b12055cab6227f7be10f5c19296f67c60cc5e2a5
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 3d338cdd00d916ce8a05c397001d64ed58e6fe1c
|
||||
F src/treeview.c c525282442111b3f61eb176784567cd6654db5dc
|
||||
F src/treeview.c e4b41a37530a191579d3c53142cc44ee2eb99373
|
||||
F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
|
||||
F src/update.c a7eeeaffad59c6506f01303a071dac11de8269ca
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 6ed9d7bdd3b0a30742027b6d8e8e1a9e2b14f373
|
||||
F src/util.c a64585a74aef6feb16dfe4e090b5de01e26eba3b
|
||||
F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
|
||||
F src/vdbe.c 87ae3a5657fefed7875f3eb30e7ababd48013d71
|
||||
F src/vdbe.h c743791f723049db94f009e3e30958952bc2d512
|
||||
@ -420,17 +421,17 @@ F src/vdbeInt.h 49a74fe5ece206d2d8666ba9afaf1abeda5f123b
|
||||
F src/vdbeapi.c 95b1f8e527240a18a9aea41a655b013bf07a7009
|
||||
F src/vdbeaux.c 2c15cf88de4df97428318c8cfac0dea873dae451
|
||||
F src/vdbeblob.c 3b570b730109e8f653d9d2081649f6e7015113db
|
||||
F src/vdbemem.c be8381ed6de54eb9cb9dfa802823cdeb5166d855
|
||||
F src/vdbemem.c 9b0cb32cc267ef026515f15a3594d5ff91fe4dfc
|
||||
F src/vdbesort.c 307460bfa4de4d1c3901fcd42089159131e34062
|
||||
F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
|
||||
F src/vtab.c 943c23b355f0a8f859f9583e7315d64bebdb0899
|
||||
F src/vtab.c fd69fd398e23e57ea4ea377d8a44b6998fc569c7
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 10deb6b43887662691e5f53d10b3c171c401169b
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c 32051597188dc632bafb32d50a9c3a04fb97ce39
|
||||
F src/where.c 56948ada5aacc3bf2628db3776986e8bf4085383
|
||||
F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34
|
||||
F src/wherecode.c 39c1ef4598bedf1d66249334c74efd23ddd182ac
|
||||
F src/wherecode.c 3ca820435c5b597bb50e63ed11e938786fe5c23e
|
||||
F src/whereexpr.c fb87944b1254234e5bba671aaf6dee476241506a
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -451,11 +452,11 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test f1c552ce39cca4ec922a7e4e0e5d0203d6b3281f
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test c05a461d0a6b05991106467d0c47480f2e709c82
|
||||
F test/analyze9.test 88c1f2aa20b614236f03e1cc38c3619e7e8a38b4
|
||||
F test/analyze9.test b817b8e798315fc65b820a5463f73ad5f48ed8dd
|
||||
F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
|
||||
F test/analyzeB.test a4c1c3048f6d9e090eb76e83eecb18bcf6d31a70
|
||||
F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
|
||||
F test/analyzeD.test f3d77cd0fefe2849d784897d52df13beee19271d
|
||||
F test/analyzeD.test 42af58de25a6436502e43006e9e59e2d71bcb0cf
|
||||
F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
|
||||
F test/analyzeF.test 5d1fe1024ba2dfea3c18bede8c1ccef8aba1ab34
|
||||
F test/analyzer1.test 498e2ff4b62740c2751c3a2f8b744fe26689fae9
|
||||
@ -492,6 +493,7 @@ F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
|
||||
F test/bc_common.tcl 3eda41ef9cda7d5f6c205462c96228b301da4191
|
||||
F test/bestindex1.test e228fe1e3794dbe20271481164e000d695abcd24
|
||||
F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
@ -945,7 +947,7 @@ F test/parser1.test 222b5cbf3e2e659fec1bf7d723488c8b9c94f1d0
|
||||
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
|
||||
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 382a43c49f49bafe6fddffe904ea33d6bb3ff33e
|
||||
F test/permutations.test 64abe58d53cde4adcfb881e37aa5ea1b2a980e58
|
||||
F test/pragma.test 507ac7ef2ea5682241ea0ef041799ca70bb5e0bf
|
||||
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
|
||||
F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c
|
||||
@ -966,7 +968,7 @@ F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8
|
||||
F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
|
||||
F test/regexp2.test aa7ffcc21350007a78361b82bcf3b74d12227144
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.tcl 975449bf742b8bb9025208292208af816a1fcb58
|
||||
F test/releasetest.tcl a246ecb14ed594bf44bf77bd21df873971d779bf
|
||||
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
|
||||
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
|
||||
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
|
||||
@ -1072,7 +1074,7 @@ F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
|
||||
F test/sync.test 2f607e1821aa3af3c5c53b58835c05e511c95899
|
||||
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
|
||||
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
|
||||
F test/tabfunc01.test cc33684f9480fcf1fd5ce287ac28d22971cad1cc
|
||||
F test/tabfunc01.test f977868fa8bb7beb4b2072883190411653473906
|
||||
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
@ -1369,7 +1371,7 @@ F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
|
||||
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
|
||||
F tool/GetTclKit.bat 629d87562e0487c386db630033931d12d62e6372
|
||||
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
|
||||
F tool/addopcodes.tcl 4ca9c3ef196f08da30add5d07ce0c9458dc8c633
|
||||
F tool/addopcodes.tcl 2b089684eb8b7d0db64cf9d8e6d2fe1b6d279e8d
|
||||
F tool/build-all-msvc.bat 55be1cf8545dabd69df2ba6b3de6868da0c26f52 x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/cg_anno.tcl 692ce4b8693d59e3a3de77ca97f4139ecfa641b0 x
|
||||
@ -1451,7 +1453,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 9fd3f7b9c93325a83cdbe7dc9ee312b22a9c2898
|
||||
R 498bd0458994e1419985675b963a5c33
|
||||
U dan
|
||||
Z de04134d7998c131f105dcb3752be845
|
||||
P 44b2dc18e200e87cf062cb8f1659727c53fa36e9 16fbf2e19c22df9441aef5c8b7f5670adc38a6b6
|
||||
R bdaefcabe5bf87c04d8b11c17326d65d
|
||||
U drh
|
||||
Z 002d922341500f2c0dc185f71a114083
|
||||
|
@ -1 +1 @@
|
||||
44b2dc18e200e87cf062cb8f1659727c53fa36e9
|
||||
55c00f716dc98b188c91f3a5a010242c9497785f
|
@ -628,7 +628,8 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
*/
|
||||
if( pDflt && pDflt->op==TK_NULL ){
|
||||
assert( pDflt==0 || pDflt->op==TK_SPAN );
|
||||
if( pDflt && pDflt->pLeft->op==TK_NULL ){
|
||||
pDflt = 0;
|
||||
}
|
||||
|
||||
@ -785,9 +786,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
Column *pCol = &pNew->aCol[i];
|
||||
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
|
||||
pCol->zColl = 0;
|
||||
pCol->zType = 0;
|
||||
pCol->pDflt = 0;
|
||||
pCol->zDflt = 0;
|
||||
}
|
||||
pNew->pSchema = db->aDb[iDb].pSchema;
|
||||
pNew->addColOffset = pTab->addColOffset;
|
||||
|
72
src/build.c
72
src/build.c
@ -571,8 +571,6 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
||||
for(i=0; i<pTable->nCol; i++, pCol++){
|
||||
sqlite3DbFree(db, pCol->zName);
|
||||
sqlite3ExprDelete(db, pCol->pDflt);
|
||||
sqlite3DbFree(db, pCol->zDflt);
|
||||
sqlite3DbFree(db, pCol->zType);
|
||||
sqlite3DbFree(db, pCol->zColl);
|
||||
}
|
||||
sqlite3DbFree(db, pTable->aCol);
|
||||
@ -1039,10 +1037,11 @@ void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
||||
** first to get things going. Then this routine is called for each
|
||||
** column.
|
||||
*/
|
||||
void sqlite3AddColumn(Parse *pParse, Token *pName){
|
||||
void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
Table *p;
|
||||
int i;
|
||||
char *z;
|
||||
char *zType;
|
||||
Column *pCol;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( (p = pParse->pNewTable)==0 ) return;
|
||||
@ -1052,8 +1051,14 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
z = sqlite3NameFromToken(db, pName);
|
||||
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
||||
if( z==0 ) return;
|
||||
memcpy(z, pName->z, pName->n);
|
||||
z[pName->n] = 0;
|
||||
sqlite3Dequote(z);
|
||||
zType = z + sqlite3Strlen30(z) + 1;
|
||||
memcpy(zType, pType->z, pType->n);
|
||||
zType[pType->n] = 0;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
||||
@ -1075,13 +1080,16 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){
|
||||
pCol->zName = z;
|
||||
sqlite3ColumnPropertiesFromName(p, pCol);
|
||||
|
||||
/* If there is no type specified, columns have the default affinity
|
||||
** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
|
||||
** be called next to set pCol->affinity correctly.
|
||||
*/
|
||||
pCol->affinity = SQLITE_AFF_BLOB;
|
||||
pCol->szEst = 1;
|
||||
if( pType->n==0 ){
|
||||
/* If there is no type specified, columns have the default affinity
|
||||
** 'BLOB'. */
|
||||
pCol->affinity = SQLITE_AFF_BLOB;
|
||||
pCol->szEst = 1;
|
||||
}else{
|
||||
pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
|
||||
}
|
||||
p->nCol++;
|
||||
pParse->constraintName.n = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1184,28 +1192,6 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){
|
||||
return aff;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called by the parser while in the middle of
|
||||
** parsing a CREATE TABLE statement. The pFirst token is the first
|
||||
** token in the sequence of tokens that describe the type of the
|
||||
** column currently under construction. pLast is the last token
|
||||
** in the sequence. Use this information to construct a string
|
||||
** that contains the typename of the column and store that string
|
||||
** in zType.
|
||||
*/
|
||||
void sqlite3AddColumnType(Parse *pParse, Token *pType){
|
||||
Table *p;
|
||||
Column *pCol;
|
||||
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || NEVER(p->nCol<1) ) return;
|
||||
pCol = &p->aCol[p->nCol-1];
|
||||
assert( pCol->zType==0 || CORRUPT_DB );
|
||||
sqlite3DbFree(pParse->db, pCol->zType);
|
||||
pCol->zType = sqlite3NameFromToken(pParse->db, pType);
|
||||
pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
|
||||
}
|
||||
|
||||
/*
|
||||
** The expression is the default value for the most recently added column
|
||||
** of the table currently under construction.
|
||||
@ -1231,11 +1217,16 @@ void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
|
||||
** tokens that point to volatile memory. The 'span' of the expression
|
||||
** is required by pragma table_info.
|
||||
*/
|
||||
Expr x;
|
||||
sqlite3ExprDelete(db, pCol->pDflt);
|
||||
pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
|
||||
sqlite3DbFree(db, pCol->zDflt);
|
||||
pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
|
||||
(int)(pSpan->zEnd - pSpan->zStart));
|
||||
memset(&x, 0, sizeof(x));
|
||||
x.op = TK_SPAN;
|
||||
x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
|
||||
(int)(pSpan->zEnd - pSpan->zStart));
|
||||
x.pLeft = pSpan->pExpr;
|
||||
x.flags = EP_Skip;
|
||||
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
|
||||
sqlite3DbFree(db, x.u.zToken);
|
||||
}
|
||||
}
|
||||
sqlite3ExprDelete(db, pSpan->pExpr);
|
||||
@ -1291,7 +1282,7 @@ void sqlite3AddPrimaryKey(
|
||||
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
|
||||
){
|
||||
Table *pTab = pParse->pNewTable;
|
||||
char *zType = 0;
|
||||
const char *zName = 0;
|
||||
int iCol = -1, i;
|
||||
int nTerm;
|
||||
if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
|
||||
@ -1304,7 +1295,7 @@ void sqlite3AddPrimaryKey(
|
||||
if( pList==0 ){
|
||||
iCol = pTab->nCol - 1;
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
zName = pTab->aCol[iCol].zName;
|
||||
nTerm = 1;
|
||||
}else{
|
||||
nTerm = pList->nExpr;
|
||||
@ -1317,7 +1308,7 @@ void sqlite3AddPrimaryKey(
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
||||
pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
zName = pTab->aCol[iCol].zName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1325,7 +1316,8 @@ void sqlite3AddPrimaryKey(
|
||||
}
|
||||
}
|
||||
if( nTerm==1
|
||||
&& zType && sqlite3StrICmp(zType, "INTEGER")==0
|
||||
&& zName
|
||||
&& sqlite3StrICmp(sqlite3StrNext(zName), "INTEGER")==0
|
||||
&& sortOrder!=SQLITE_SO_DESC
|
||||
){
|
||||
pTab->iPKey = iCol;
|
||||
|
@ -3070,6 +3070,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ReleaseTempReg(pParse, r4);
|
||||
break;
|
||||
}
|
||||
case TK_SPAN:
|
||||
case TK_COLLATE:
|
||||
case TK_UPLUS: {
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
|
14
src/insert.c
14
src/insert.c
@ -1999,11 +1999,15 @@ static int xferOptimization(
|
||||
return 0; /* tab2 must be NOT NULL if tab1 is */
|
||||
}
|
||||
/* Default values for second and subsequent columns need to match. */
|
||||
if( i>0
|
||||
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|
||||
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
|
||||
){
|
||||
return 0; /* Default values must be the same for all columns */
|
||||
if( i>0 ){
|
||||
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
|
||||
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
|
||||
if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|
||||
|| (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
|
||||
pSrcCol->pDflt->u.zToken)!=0)
|
||||
){
|
||||
return 0; /* Default values must be the same for all columns */
|
||||
}
|
||||
}
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
|
@ -3335,7 +3335,8 @@ int sqlite3_table_column_metadata(
|
||||
** explicitly declared column. Copy meta information from *pCol.
|
||||
*/
|
||||
if( pCol ){
|
||||
zDataType = pCol->zType;
|
||||
zDataType = sqlite3StrNext(pCol->zName);
|
||||
if( zDataType[0]==0 ) zDataType = 0;
|
||||
zCollSeq = pCol->zColl;
|
||||
notnull = pCol->notNull!=0;
|
||||
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
|
||||
|
30
src/parse.y
30
src/parse.y
@ -190,22 +190,9 @@ table_options(A) ::= WITHOUT nm(X). {
|
||||
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z);
|
||||
}
|
||||
}
|
||||
columnlist ::= columnlist COMMA column.
|
||||
columnlist ::= column.
|
||||
|
||||
// A "column" is a complete description of a single column in a
|
||||
// CREATE TABLE statement. This includes the column name, its
|
||||
// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
|
||||
// NOT NULL and so forth.
|
||||
//
|
||||
column(A) ::= columnid(A) type carglist. {
|
||||
A.n = (int)(pParse->sLastToken.z-A.z) + pParse->sLastToken.n;
|
||||
}
|
||||
columnid(A) ::= nm(A). {
|
||||
sqlite3AddColumn(pParse,&A);
|
||||
pParse->constraintName.n = 0;
|
||||
}
|
||||
|
||||
columnlist ::= columnlist COMMA columnname carglist.
|
||||
columnlist ::= columnname carglist.
|
||||
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
|
||||
// An IDENTIFIER can be a generic identifier, or one of several
|
||||
// keywords. Any non-standard keyword can also be an identifier.
|
||||
@ -264,13 +251,12 @@ nm(A) ::= id(A).
|
||||
nm(A) ::= STRING(A).
|
||||
nm(A) ::= JOIN_KW(A).
|
||||
|
||||
// A typetoken is really one or more tokens that form a type name such
|
||||
// A typetoken is really zero or more tokens that form a type name such
|
||||
// as can be found after the column name in a CREATE TABLE statement.
|
||||
// Multiple tokens are concatenated to form the value of the typetoken.
|
||||
//
|
||||
%type typetoken {Token}
|
||||
type ::= .
|
||||
type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);}
|
||||
typetoken(A) ::= . {A.n = 0; A.z = 0;}
|
||||
typetoken(A) ::= typename(A).
|
||||
typetoken(A) ::= typename(A) LP signed RP(Y). {
|
||||
A.n = (int)(&Y.z[Y.n] - A.z);
|
||||
@ -580,7 +566,7 @@ selcollist(A) ::= sclp(A) nm(X) DOT STAR(Y). {
|
||||
%type as {Token}
|
||||
as(X) ::= AS nm(Y). {X = Y;}
|
||||
as(X) ::= ids(X).
|
||||
as(X) ::= . {X.n = 0;}
|
||||
as(X) ::= . {X.n = 0; X.z = 0;}
|
||||
|
||||
|
||||
%type seltablist {SrcList*}
|
||||
@ -1499,7 +1485,9 @@ cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);}
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
|
||||
sqlite3AlterRenameTable(pParse,X,&Z);
|
||||
}
|
||||
cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
|
||||
cmd ::= ALTER TABLE add_column_fullname
|
||||
ADD kwcolumn_opt columnname(Y) carglist. {
|
||||
Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n;
|
||||
sqlite3AlterFinishAddColumn(pParse, &Y);
|
||||
}
|
||||
add_column_fullname ::= fullname(X). {
|
||||
|
@ -1065,6 +1065,7 @@ void sqlite3Pragma(
|
||||
setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
|
||||
sqlite3ViewGetColumnNames(pParse, pTab);
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
const char *zName;
|
||||
if( IsHiddenColumn(pCol) ){
|
||||
nHidden++;
|
||||
continue;
|
||||
@ -1076,12 +1077,14 @@ void sqlite3Pragma(
|
||||
}else{
|
||||
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
||||
}
|
||||
assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
|
||||
zName = pCol->zName;
|
||||
sqlite3VdbeMultiLoad(v, 1, "issisi",
|
||||
i-nHidden,
|
||||
pCol->zName,
|
||||
pCol->zType ? pCol->zType : "",
|
||||
zName,
|
||||
sqlite3StrNext(zName),
|
||||
pCol->notNull ? 1 : 0,
|
||||
pCol->zDflt,
|
||||
pCol->pDflt ? pCol->pDflt->u.zToken : 0,
|
||||
k);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
|
||||
}
|
||||
|
@ -1429,8 +1429,8 @@ static const char *columnTypeImpl(
|
||||
zType = "INTEGER";
|
||||
zOrigCol = "rowid";
|
||||
}else{
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
zOrigCol = pTab->aCol[iCol].zName;
|
||||
zType = sqlite3StrNext(zOrigCol);
|
||||
estWidth = pTab->aCol[iCol].szEst;
|
||||
}
|
||||
zOrigTab = pTab->zName;
|
||||
@ -1442,7 +1442,7 @@ static const char *columnTypeImpl(
|
||||
if( iCol<0 ){
|
||||
zType = "INTEGER";
|
||||
}else{
|
||||
zType = pTab->aCol[iCol].zType;
|
||||
zType = sqlite3StrNext(pTab->aCol[iCol].zName);
|
||||
estWidth = pTab->aCol[iCol].szEst;
|
||||
}
|
||||
#endif
|
||||
@ -1727,10 +1727,7 @@ static void selectAddColumnTypeAndCollation(
|
||||
a = pSelect->pEList->a;
|
||||
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
||||
p = a[i].pExpr;
|
||||
if( pCol->zType==0 ){
|
||||
pCol->zType = sqlite3DbStrDup(db,
|
||||
columnType(&sNC, p,0,0,0, &pCol->szEst));
|
||||
}
|
||||
columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
|
||||
szAll += pCol->szEst;
|
||||
pCol->affinity = sqlite3ExprAffinity(p);
|
||||
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
|
||||
|
@ -1543,10 +1543,8 @@ struct Module {
|
||||
** of this structure.
|
||||
*/
|
||||
struct Column {
|
||||
char *zName; /* Name of this column */
|
||||
char *zName; /* Name of this column, \000, then the type */
|
||||
Expr *pDflt; /* Default value of this column */
|
||||
char *zDflt; /* Original text of the default value */
|
||||
char *zType; /* Data type for this column */
|
||||
char *zColl; /* Collating sequence. If NULL, use the default */
|
||||
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
|
||||
char affinity; /* One of the SQLITE_AFF_... values */
|
||||
@ -3259,6 +3257,7 @@ int sqlite3IsIdChar(u8);
|
||||
*/
|
||||
int sqlite3StrICmp(const char*,const char*);
|
||||
int sqlite3Strlen30(const char*);
|
||||
const char *sqlite3StrNext(const char*);
|
||||
#define sqlite3StrNICmp sqlite3_strnicmp
|
||||
|
||||
int sqlite3MallocInit(void);
|
||||
@ -3414,11 +3413,10 @@ void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
|
||||
#else
|
||||
# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
|
||||
#endif
|
||||
void sqlite3AddColumn(Parse*,Token*);
|
||||
void sqlite3AddColumn(Parse*,Token*,Token*);
|
||||
void sqlite3AddNotNull(Parse*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
|
||||
void sqlite3AddCheckConstraint(Parse*, Expr*);
|
||||
void sqlite3AddColumnType(Parse*,Token*);
|
||||
void sqlite3AddDefaultValue(Parse*,ExprSpan*);
|
||||
void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
|
||||
|
@ -3774,6 +3774,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int SqlitetestSyscall_Init(Tcl_Interp*);
|
||||
extern int Fts5tcl_Init(Tcl_Interp *);
|
||||
extern int SqliteRbu_Init(Tcl_Interp*);
|
||||
extern int Sqlitetesttcl_Init(Tcl_Interp*);
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
|
||||
#endif
|
||||
@ -3818,6 +3819,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
SqlitetestSyscall_Init(interp);
|
||||
Fts5tcl_Init(interp);
|
||||
SqliteRbu_Init(interp);
|
||||
Sqlitetesttcl_Init(interp);
|
||||
|
||||
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
|
||||
Sqlitetestfts3_Init(interp);
|
||||
|
564
src/test_bestindex.c
Normal file
564
src/test_bestindex.c
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
** 2016-03-01
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
** Code for testing the virtual table xBestIndex method and the query
|
||||
** planner.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** INSTRUCTIONS
|
||||
**
|
||||
** This module exports a single tcl command - [register_tcl_module]. When
|
||||
** invoked, it registers a special virtual table module with a database
|
||||
** connection.
|
||||
**
|
||||
** The virtual table is currently read-only. And always returns zero rows.
|
||||
** It is created with a single argument - the name of a Tcl command - as
|
||||
** follows:
|
||||
**
|
||||
** CREATE VIRTUAL TABLE x1 USING tcl(tcl_command);
|
||||
**
|
||||
** The command [tcl_command] is invoked when the table is first created (or
|
||||
** connected), when the xBestIndex() method is invoked and when the xFilter()
|
||||
** method is called. When it is created (or connected), it is invoked as
|
||||
** follows:
|
||||
**
|
||||
** tcl_command xConnect
|
||||
**
|
||||
** In this case the return value of the script is passed to the
|
||||
** sqlite3_declare_vtab() function to create the virtual table schema.
|
||||
**
|
||||
** When the xBestIndex() method is called by SQLite, the Tcl command is
|
||||
** invoked as:
|
||||
**
|
||||
** tcl_command xBestIndex CONSTRAINTS ORDERBY MASK
|
||||
**
|
||||
** where CONSTRAINTS is a tcl representation of the aConstraints[] array,
|
||||
** ORDERBY is a representation of the contents of the aOrderBy[] array and
|
||||
** MASK is a copy of sqlite3_index_info.colUsed. For example if the virtual
|
||||
** table is declared as:
|
||||
**
|
||||
** CREATE TABLE x1(a, b, c)
|
||||
**
|
||||
** and the query is:
|
||||
**
|
||||
** SELECT * FROM x1 WHERE a=? AND c<? ORDER BY b, c;
|
||||
**
|
||||
** then the Tcl command is:
|
||||
**
|
||||
** tcl_command xBestIndex \
|
||||
** {{op eq column 0 usable 1} {op lt column 2 usable 1}} \
|
||||
** {{column 1 desc 0} {column 2 desc 0}} \
|
||||
** 7
|
||||
**
|
||||
** The return value of the script is a list of key-value pairs used to
|
||||
** populate the output fields of the sqlite3_index_info structure. Possible
|
||||
** keys and the usage of the accompanying values are:
|
||||
**
|
||||
** "orderby" (value of orderByConsumed flag)
|
||||
** "cost" (value of estimatedCost field)
|
||||
** "rows" (value of estimatedRows field)
|
||||
** "use" (index of used constraint in aConstraint[])
|
||||
** "omit" (like "use", but also sets omit flag)
|
||||
** "idxnum" (value of idxNum field)
|
||||
** "idxstr" (value of idxStr field)
|
||||
**
|
||||
** Refer to code below for further details.
|
||||
**
|
||||
** When SQLite calls the xFilter() method, this module invokes the following
|
||||
** Tcl script:
|
||||
**
|
||||
** tcl_command xFilter IDXNUM IDXSTR ARGLIST
|
||||
**
|
||||
** IDXNUM and IDXSTR are the values of the idxNum and idxStr parameters
|
||||
** passed to xFilter. ARGLIST is a Tcl list containing each of the arguments
|
||||
** passed to xFilter in text form.
|
||||
**
|
||||
** As with xBestIndex(), the return value of the script is interpreted as a
|
||||
** list of key-value pairs. There is currently only one key defined - "sql".
|
||||
** The value must be the full text of an SQL statement that returns the data
|
||||
** for the current scan. The leftmost column returned by the SELECT is assumed
|
||||
** to contain the rowid. Other columns must follow, in order from left to
|
||||
** right.
|
||||
*/
|
||||
|
||||
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
typedef struct tcl_vtab tcl_vtab;
|
||||
typedef struct tcl_cursor tcl_cursor;
|
||||
|
||||
/*
|
||||
** A fs virtual-table object
|
||||
*/
|
||||
struct tcl_vtab {
|
||||
sqlite3_vtab base;
|
||||
Tcl_Interp *interp;
|
||||
Tcl_Obj *pCmd;
|
||||
sqlite3 *db;
|
||||
};
|
||||
|
||||
/* A tcl cursor object */
|
||||
struct tcl_cursor {
|
||||
sqlite3_vtab_cursor base;
|
||||
sqlite3_stmt *pStmt; /* Read data from here */
|
||||
};
|
||||
|
||||
/*
|
||||
** This function is the implementation of both the xConnect and xCreate
|
||||
** methods of the fs virtual table.
|
||||
**
|
||||
** The argv[] array contains the following:
|
||||
**
|
||||
** argv[0] -> module name ("fs")
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[...] -> other module argument fields.
|
||||
*/
|
||||
static int tclConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
Tcl_Interp *interp = (Tcl_Interp*)pAux;
|
||||
tcl_vtab *pTab;
|
||||
const char *zCmd;
|
||||
Tcl_Obj *pScript = 0;
|
||||
int rc;
|
||||
|
||||
if( argc!=4 ){
|
||||
*pzErr = sqlite3_mprintf("wrong number of arguments");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
zCmd = argv[3];
|
||||
|
||||
pTab = (tcl_vtab*)sqlite3_malloc(sizeof(tcl_vtab));
|
||||
if( pTab==0 ) return SQLITE_NOMEM;
|
||||
memset(pTab, 0, sizeof(tcl_vtab));
|
||||
|
||||
pTab->pCmd = Tcl_NewStringObj(zCmd, -1);
|
||||
pTab->interp = interp;
|
||||
pTab->db = db;
|
||||
Tcl_IncrRefCount(pTab->pCmd);
|
||||
|
||||
pScript = Tcl_DuplicateObj(pTab->pCmd);
|
||||
Tcl_IncrRefCount(pScript);
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xConnect", -1));
|
||||
|
||||
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", Tcl_GetStringResult(interp));
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
rc = sqlite3_declare_vtab(db, Tcl_GetStringResult(interp));
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(pTab);
|
||||
pTab = 0;
|
||||
}
|
||||
|
||||
*ppVtab = &pTab->base;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* The xDisconnect and xDestroy methods are also the same */
|
||||
static int tclDisconnect(sqlite3_vtab *pVtab){
|
||||
tcl_vtab *pTab = (tcl_vtab*)pVtab;
|
||||
Tcl_DecrRefCount(pTab->pCmd);
|
||||
sqlite3_free(pTab);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new tcl cursor.
|
||||
*/
|
||||
static int tclOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
tcl_cursor *pCur;
|
||||
pCur = sqlite3_malloc(sizeof(tcl_cursor));
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(tcl_cursor));
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a tcl cursor.
|
||||
*/
|
||||
static int tclClose(sqlite3_vtab_cursor *cur){
|
||||
tcl_cursor *pCur = (tcl_cursor *)cur;
|
||||
if( pCur ){
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
sqlite3_free(pCur);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int tclNext(sqlite3_vtab_cursor *pVtabCursor){
|
||||
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
|
||||
if( pCsr->pStmt ){
|
||||
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
|
||||
int rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc!=SQLITE_ROW ){
|
||||
const char *zErr;
|
||||
rc = sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
zErr = sqlite3_errmsg(pTab->db);
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int tclFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
|
||||
tcl_vtab *pTab = (tcl_vtab*)(pVtabCursor->pVtab);
|
||||
Tcl_Interp *interp = pTab->interp;
|
||||
Tcl_Obj *pScript;
|
||||
Tcl_Obj *pArg;
|
||||
int ii;
|
||||
int rc;
|
||||
|
||||
pScript = Tcl_DuplicateObj(pTab->pCmd);
|
||||
Tcl_IncrRefCount(pScript);
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xFilter", -1));
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewIntObj(idxNum));
|
||||
if( idxStr ){
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj(idxStr, -1));
|
||||
}else{
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("", -1));
|
||||
}
|
||||
|
||||
pArg = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pArg);
|
||||
for(ii=0; ii<argc; ii++){
|
||||
const char *zVal = (const char*)sqlite3_value_text(argv[ii]);
|
||||
Tcl_Obj *pVal;
|
||||
if( zVal==0 ){
|
||||
pVal = Tcl_NewObj();
|
||||
}else{
|
||||
pVal = Tcl_NewStringObj(zVal, -1);
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, pArg, pVal);
|
||||
}
|
||||
Tcl_ListObjAppendElement(interp, pScript, pArg);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
|
||||
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
|
||||
if( rc!=TCL_OK ){
|
||||
const char *zErr = Tcl_GetStringResult(interp);
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}else{
|
||||
/* Analyze the scripts return value. The return value should be a tcl
|
||||
** list object with an even number of elements. The first element of each
|
||||
** pair must be one of:
|
||||
**
|
||||
** "sql" (SQL statement to return data)
|
||||
*/
|
||||
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem;
|
||||
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
|
||||
if( rc!=TCL_OK ){
|
||||
const char *zErr = Tcl_GetStringResult(interp);
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}else{
|
||||
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
|
||||
const char *zCmd = Tcl_GetString(apElem[ii]);
|
||||
Tcl_Obj *p = apElem[ii+1];
|
||||
if( sqlite3_stricmp("sql", zCmd)==0 ){
|
||||
const char *zSql = Tcl_GetString(p);
|
||||
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
const char *zErr = sqlite3_errmsg(pTab->db);
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zErr);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = tclNext(pVtabCursor);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tclColumn(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
sqlite3_context *ctx,
|
||||
int i
|
||||
){
|
||||
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
|
||||
sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int tclRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
|
||||
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
|
||||
*pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int tclEof(sqlite3_vtab_cursor *pVtabCursor){
|
||||
tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor;
|
||||
return (pCsr->pStmt==0);
|
||||
}
|
||||
|
||||
static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
tcl_vtab *pTab = (tcl_vtab*)tab;
|
||||
Tcl_Interp *interp = pTab->interp;
|
||||
Tcl_Obj *pArg;
|
||||
Tcl_Obj *pScript;
|
||||
int ii;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
pScript = Tcl_DuplicateObj(pTab->pCmd);
|
||||
Tcl_IncrRefCount(pScript);
|
||||
Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xBestIndex", -1));
|
||||
|
||||
pArg = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pArg);
|
||||
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
|
||||
struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii];
|
||||
Tcl_Obj *pElem = Tcl_NewObj();
|
||||
const char *zOp = "?";
|
||||
|
||||
Tcl_IncrRefCount(pElem);
|
||||
|
||||
switch( pCons->op ){
|
||||
case SQLITE_INDEX_CONSTRAINT_EQ:
|
||||
zOp = "eq"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GT:
|
||||
zOp = "gt"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LE:
|
||||
zOp = "le"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LT:
|
||||
zOp = "lt"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GE:
|
||||
zOp = "ge"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_MATCH:
|
||||
zOp = "match"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_LIKE:
|
||||
zOp = "like"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_GLOB:
|
||||
zOp = "glob"; break;
|
||||
case SQLITE_INDEX_CONSTRAINT_REGEXP:
|
||||
zOp = "regexp"; break;
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->usable));
|
||||
|
||||
Tcl_ListObjAppendElement(0, pArg, pElem);
|
||||
Tcl_DecrRefCount(pElem);
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pScript, pArg);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
|
||||
pArg = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pArg);
|
||||
for(ii=0; ii<pIdxInfo->nOrderBy; ii++){
|
||||
struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[ii];
|
||||
Tcl_Obj *pElem = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pElem);
|
||||
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->iColumn));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("desc", -1));
|
||||
Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->desc));
|
||||
|
||||
Tcl_ListObjAppendElement(0, pArg, pElem);
|
||||
Tcl_DecrRefCount(pElem);
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(0, pScript, pArg);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
|
||||
Tcl_ListObjAppendElement(0, pScript, Tcl_NewWideIntObj(pIdxInfo->colUsed));
|
||||
|
||||
rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL);
|
||||
Tcl_DecrRefCount(pScript);
|
||||
if( rc!=TCL_OK ){
|
||||
const char *zErr = Tcl_GetStringResult(interp);
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}else{
|
||||
/* Analyze the scripts return value. The return value should be a tcl
|
||||
** list object with an even number of elements. The first element of each
|
||||
** pair must be one of:
|
||||
**
|
||||
** "orderby" (value of orderByConsumed flag)
|
||||
** "cost" (value of estimatedCost field)
|
||||
** "rows" (value of estimatedRows field)
|
||||
** "use" (index of used constraint in aConstraint[])
|
||||
** "idxnum" (value of idxNum field)
|
||||
** "idxstr" (value of idxStr field)
|
||||
** "omit" (index of omitted constraint in aConstraint[])
|
||||
*/
|
||||
Tcl_Obj *pRes = Tcl_GetObjResult(interp);
|
||||
Tcl_Obj **apElem = 0;
|
||||
int nElem;
|
||||
rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem);
|
||||
if( rc!=TCL_OK ){
|
||||
const char *zErr = Tcl_GetStringResult(interp);
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}else{
|
||||
int iArgv = 1;
|
||||
for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){
|
||||
const char *zCmd = Tcl_GetString(apElem[ii]);
|
||||
Tcl_Obj *p = apElem[ii+1];
|
||||
if( sqlite3_stricmp("cost", zCmd)==0 ){
|
||||
rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost);
|
||||
}else
|
||||
if( sqlite3_stricmp("orderby", zCmd)==0 ){
|
||||
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->orderByConsumed);
|
||||
}else
|
||||
if( sqlite3_stricmp("idxnum", zCmd)==0 ){
|
||||
rc = Tcl_GetIntFromObj(interp, p, &pIdxInfo->idxNum);
|
||||
}else
|
||||
if( sqlite3_stricmp("idxstr", zCmd)==0 ){
|
||||
sqlite3_free(pIdxInfo->idxStr);
|
||||
pIdxInfo->idxStr = sqlite3_mprintf("%s", Tcl_GetString(p));
|
||||
pIdxInfo->needToFreeIdxStr = 1;
|
||||
}else
|
||||
if( sqlite3_stricmp("rows", zCmd)==0 ){
|
||||
rc = Tcl_GetWideIntFromObj(interp, p, &pIdxInfo->estimatedRows);
|
||||
}else
|
||||
if( sqlite3_stricmp("use", zCmd)==0
|
||||
|| sqlite3_stricmp("omit", zCmd)==0
|
||||
){
|
||||
int iCons;
|
||||
rc = Tcl_GetIntFromObj(interp, p, &iCons);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %d", iCons);
|
||||
}else{
|
||||
int bOmit = (zCmd[0]=='o' || zCmd[0]=='O');
|
||||
pIdxInfo->aConstraintUsage[iCons].argvIndex = iArgv++;
|
||||
pIdxInfo->aConstraintUsage[iCons].omit = bOmit;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("unexpected: %s", zCmd);
|
||||
}
|
||||
if( rc!=SQLITE_OK && pTab->base.zErrMsg==0 ){
|
||||
const char *zErr = Tcl_GetStringResult(interp);
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** A virtual table module that provides read-only access to a
|
||||
** Tcl global variable namespace.
|
||||
*/
|
||||
static sqlite3_module tclModule = {
|
||||
0, /* iVersion */
|
||||
tclConnect,
|
||||
tclConnect,
|
||||
tclBestIndex,
|
||||
tclDisconnect,
|
||||
tclDisconnect,
|
||||
tclOpen, /* xOpen - open a cursor */
|
||||
tclClose, /* xClose - close a cursor */
|
||||
tclFilter, /* xFilter - configure scan constraints */
|
||||
tclNext, /* xNext - advance a cursor */
|
||||
tclEof, /* xEof - check for end of scan */
|
||||
tclColumn, /* xColumn - read data */
|
||||
tclRowid, /* xRowid - read data */
|
||||
0, /* xUpdate */
|
||||
0, /* xBegin */
|
||||
0, /* xSync */
|
||||
0, /* xCommit */
|
||||
0, /* xRollback */
|
||||
0, /* xFindMethod */
|
||||
0, /* xRename */
|
||||
};
|
||||
|
||||
/*
|
||||
** Decode a pointer to an sqlite3 object.
|
||||
*/
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
|
||||
/*
|
||||
** Register the echo virtual table module.
|
||||
*/
|
||||
static int register_tcl_module(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3_create_module(db, "tcl", &tclModule, (void *)interp);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetesttcl_Init(Tcl_Interp *interp){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
void *clientData;
|
||||
} aObjCmd[] = {
|
||||
{ "register_tcl_module", register_tcl_module, 0 },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
|
||||
aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
|
||||
}
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
@ -339,6 +339,12 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
||||
case TK_ISNULL: zUniOp = "ISNULL"; break;
|
||||
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
|
||||
|
||||
case TK_SPAN: {
|
||||
sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_COLLATE: {
|
||||
sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
|
||||
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
||||
|
@ -109,6 +109,14 @@ int sqlite3Strlen30(const char *z){
|
||||
return 0x3fffffff & (int)strlen(z);
|
||||
}
|
||||
|
||||
/*
|
||||
** The string z[] is followed immediately by another string. Return
|
||||
** a poiner to that other string.
|
||||
*/
|
||||
const char *sqlite3StrNext(const char *z){
|
||||
return z + strlen(z) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the current error code to err_code and clear any prior error message.
|
||||
*/
|
||||
|
@ -1285,7 +1285,7 @@ static int valueFromExpr(
|
||||
*ppVal = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
|
||||
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
|
||||
/* Compressed expressions only appear when parsing the DEFAULT clause
|
||||
|
@ -564,10 +564,10 @@ static int vtabCallConstructor(
|
||||
pTab->pVTable = pVTable;
|
||||
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
char *zType = pTab->aCol[iCol].zType;
|
||||
char *zType = (char*)sqlite3StrNext(pTab->aCol[iCol].zName);
|
||||
int nType;
|
||||
int i = 0;
|
||||
if( !zType ){
|
||||
if( !zType[0] ){
|
||||
pTab->tabFlags |= oooHidden;
|
||||
continue;
|
||||
}
|
||||
|
10
src/where.c
10
src/where.c
@ -1561,7 +1561,8 @@ static int whereEqualScanEst(
|
||||
pBuilder->nRecValid = nEq;
|
||||
|
||||
whereKeyStats(pParse, p, pRec, 0, a);
|
||||
WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1]));
|
||||
WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
|
||||
p->zName, nEq-1, (int)a[1]));
|
||||
*pnRow = a[1];
|
||||
|
||||
return rc;
|
||||
@ -2897,13 +2898,6 @@ static int whereLoopAddVirtual(
|
||||
testcase( iTerm==16 );
|
||||
if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
|
||||
if( (pTerm->eOperator & WO_IN)!=0 ){
|
||||
if( pUsage[i].omit==0 ){
|
||||
/* Do not attempt to use an IN constraint if the virtual table
|
||||
** says that the equivalent EQ constraint cannot be safely omitted.
|
||||
** If we do attempt to use such a constraint, some rows might be
|
||||
** repeated in the output. */
|
||||
break;
|
||||
}
|
||||
/* A virtual table that is constrained by an IN clause may not
|
||||
** consume the ORDER BY clause because (1) the order of IN terms
|
||||
** is not necessarily related to the order of output terms and
|
||||
|
@ -874,6 +874,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
int iReg; /* P3 Value for OP_VFilter */
|
||||
int addrNotFound;
|
||||
int nConstraint = pLoop->nLTerm;
|
||||
int iIn; /* Counter for IN constraints */
|
||||
|
||||
sqlite3ExprCachePush(pParse);
|
||||
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
||||
@ -896,14 +897,48 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
|
||||
VdbeCoverage(v);
|
||||
pLoop->u.vtab.needFree = 0;
|
||||
for(j=0; j<nConstraint && j<16; j++){
|
||||
if( (pLoop->u.vtab.omitMask>>j)&1 ){
|
||||
disableTerm(pLevel, pLoop->aLTerm[j]);
|
||||
}
|
||||
}
|
||||
pLevel->p1 = iCur;
|
||||
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
iIn = pLevel->u.in.nIn;
|
||||
for(j=nConstraint-1; j>=0; j--){
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
|
||||
disableTerm(pLevel, pTerm);
|
||||
}else if( (pTerm->eOperator & WO_IN)!=0 ){
|
||||
Expr *pCompare; /* The comparison operator */
|
||||
Expr *pRight; /* RHS of the comparison */
|
||||
VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
|
||||
|
||||
/* Reload the constraint value into reg[iReg+j+2]. The same value
|
||||
** was loaded into the same register prior to the OP_VFilter, but
|
||||
** the xFilter implementation might have changed the datatype or
|
||||
** encoding of the value in the register, so it *must* be reloaded. */
|
||||
assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
|
||||
if( pLevel->u.in.aInLoop!=0 ){
|
||||
assert( iIn>0 );
|
||||
pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
|
||||
assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
|
||||
assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
|
||||
assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
|
||||
testcase( pOp->opcode==OP_Rowid );
|
||||
sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
|
||||
}
|
||||
|
||||
/* Generate code that will continue to the next row if
|
||||
** the IN constraint is not satisfied */
|
||||
pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0, 0);
|
||||
assert( pCompare!=0 || db->mallocFailed );
|
||||
if( pCompare ){
|
||||
pCompare->pLeft = pTerm->pExpr->pLeft;
|
||||
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
|
||||
if( pRight ) pRight->iTable = iReg+j+2;
|
||||
sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
|
||||
pCompare->pLeft = 0;
|
||||
sqlite3ExprDelete(db, pCompare);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
|
||||
sqlite3ExprCachePop(pParse);
|
||||
}else
|
||||
|
@ -1180,7 +1180,7 @@ do_execsql_test 26.1.3 {
|
||||
#
|
||||
# There should be no other samples that start with (x=10000). So it knows
|
||||
# that (x=10000 AND y<50) must match somewhere between 0 and 99 rows, but
|
||||
# know more than that. Guessing less than 20 is therefore unreasonable.
|
||||
# no more than that. Guessing less than 20 is therefore unreasonable.
|
||||
#
|
||||
# At one point though, due to a problem in whereKeyStats(), the planner was
|
||||
# estimating that (x=10000 AND y<50) would match only 2 rows.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# 2005 July 22
|
||||
# 2014-10-04
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
@ -11,7 +11,6 @@
|
||||
# This file implements regression tests for SQLite library.
|
||||
# This file implements tests for the ANALYZE command.
|
||||
#
|
||||
# $Id: analyze.test,v 1.9 2008/08/11 18:44:58 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -75,7 +74,7 @@ do_test 1.3 {
|
||||
} {}
|
||||
|
||||
# Without stat1, because 3001 is larger than all samples in the stat4
|
||||
# table, SQLite things that a=3001 matches just 1 row. So it (incorrectly)
|
||||
# table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly)
|
||||
# chooses it over the c=150 index (5 rows). Even with stat1 data, things
|
||||
# worked this way before commit [e6f7f97dbc].
|
||||
#
|
||||
|
165
test/bestindex1.test
Normal file
165
test/bestindex1.test
Normal file
@ -0,0 +1,165 @@
|
||||
# 2016-03-01
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bestindex1
|
||||
|
||||
register_tcl_module db
|
||||
|
||||
proc vtab_command {method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1(a, b, c)"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
set clist [lindex $args 0]
|
||||
if {[llength $clist]!=1} { error "unexpected constraint list" }
|
||||
catch { array unset C }
|
||||
array set C [lindex $clist 0]
|
||||
if {$C(usable)} {
|
||||
return "omit 0 cost 0 rows 1 idxnum 555 idxstr eq!"
|
||||
} else {
|
||||
return "cost 1000000 rows 0 idxnum 0 idxstr scan..."
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
|
||||
} {}
|
||||
|
||||
do_eqp_test 1.1 {
|
||||
SELECT * FROM x1 WHERE a = 'abc'
|
||||
} {
|
||||
0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
|
||||
}
|
||||
|
||||
do_eqp_test 1.2 {
|
||||
SELECT * FROM x1 WHERE a IN ('abc', 'def');
|
||||
} {
|
||||
0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!}
|
||||
0 0 0 {EXECUTE LIST SUBQUERY 1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
register_tcl_module db
|
||||
|
||||
# Parameter $mode may be one of:
|
||||
#
|
||||
# "omit" - Implement filtering. Set the omit flag.
|
||||
# "use" - Implement filtering. Use the constraint, but do not set omit.
|
||||
# "use2" - Do not implement filtering. Use the constraint anyway.
|
||||
#
|
||||
#
|
||||
proc t1_vtab {mode method args} {
|
||||
switch -- $method {
|
||||
xConnect {
|
||||
return "CREATE TABLE t1(a, b)"
|
||||
}
|
||||
|
||||
xBestIndex {
|
||||
set SQL_FILTER {SELECT * FROM t1x WHERE a='%1%'}
|
||||
set SQL_SCAN {SELECT * FROM t1x}
|
||||
|
||||
set clist [lindex $args 0]
|
||||
set idx 0
|
||||
for {set idx 0} {$idx < [llength $clist]} {incr idx} {
|
||||
array unset C
|
||||
array set C [lindex $clist $idx]
|
||||
if {$C(column)==0 && $C(op)=="eq" && $C(usable)} {
|
||||
switch -- $mode {
|
||||
"omit" {
|
||||
return [list omit $idx rows 10 cost 10 idxstr $SQL_FILTER]
|
||||
}
|
||||
"use" {
|
||||
return [list use $idx rows 10 cost 10 idxstr $SQL_FILTER]
|
||||
}
|
||||
"use2" {
|
||||
return [list use $idx rows 10 cost 10 idxstr $SQL_SCAN]
|
||||
}
|
||||
default {
|
||||
error "Bad mode - $mode"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [list idxstr {SELECT * FROM t1x}]
|
||||
}
|
||||
|
||||
xFilter {
|
||||
set map [list %1% [lindex $args 2 0]]
|
||||
set sql [string map $map [lindex $args 1]]
|
||||
return [list sql $sql]
|
||||
}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE t1x(i INTEGER PRIMARY KEY, a, b);
|
||||
INSERT INTO t1x VALUES(1, 'one', 1);
|
||||
INSERT INTO t1x VALUES(2, 'two', 2);
|
||||
INSERT INTO t1x VALUES(3, 'three', 3);
|
||||
INSERT INTO t1x VALUES(4, 'four', 4);
|
||||
}
|
||||
|
||||
foreach {tn mode} {
|
||||
1 use 2 omit 3 use2
|
||||
} {
|
||||
do_execsql_test 2.2.$mode.1 "
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE VIRTUAL TABLE t1 USING tcl(t1_vtab $mode);
|
||||
"
|
||||
|
||||
do_execsql_test 2.2.$mode.2 {SELECT * FROM t1} {one 1 two 2 three 3 four 4}
|
||||
do_execsql_test 2.2.$mode.3 {SELECT rowid FROM t1} {1 2 3 4}
|
||||
do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2}
|
||||
|
||||
do_execsql_test 2.2.$mode.5 {
|
||||
SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
|
||||
} {1 4}
|
||||
|
||||
set plan(use) {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
|
||||
0 0 0 {EXECUTE LIST SUBQUERY 1}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
set plan(omit) {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'}
|
||||
0 0 0 {EXECUTE LIST SUBQUERY 1}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
set plan(use2) {
|
||||
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x}
|
||||
0 0 0 {EXECUTE LIST SUBQUERY 1}
|
||||
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
|
||||
}
|
||||
|
||||
do_eqp_test 2.2.$mode.6 {
|
||||
SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid
|
||||
} $plan($mode)
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -86,7 +86,10 @@ proc test_set {args} {
|
||||
#
|
||||
set alltests [list]
|
||||
foreach f [glob $testdir/*.test] { lappend alltests [file tail $f] }
|
||||
foreach f [glob -nocomplain $testdir/../ext/rtree/*.test] {
|
||||
foreach f [glob -nocomplain \
|
||||
$testdir/../ext/rtree/*.test \
|
||||
$testdir/../ext/fts5/test/*.test \
|
||||
] {
|
||||
lappend alltests $f
|
||||
}
|
||||
|
||||
@ -157,7 +160,8 @@ test_suite "veryquick" -prefix "" -description {
|
||||
This test suite is the same as the "quick" tests, except that some files
|
||||
that test malloc and IO errors are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err*
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \
|
||||
*fts5corrupt* *fts5big* *fts5aj*
|
||||
]
|
||||
|
||||
test_suite "extraquick" -prefix "" -description {
|
||||
@ -612,6 +616,7 @@ test_suite "utf16" -description {
|
||||
trace.test trigger1.test trigger2.test trigger3.test
|
||||
trigger4.test types2.test types.test unique.test update.test
|
||||
vacuum.test view.test where.test
|
||||
bestindex1.test
|
||||
}
|
||||
|
||||
# Run some tests in exclusive locking mode.
|
||||
|
@ -203,6 +203,7 @@ array set ::Configs [strip_comments {
|
||||
-DSQLITE_MAX_ATTACHED=30
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA
|
||||
-DSQLITE_ENABLE_FTS4
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
-DSQLITE_ENABLE_FTS4_PARENTHESIS
|
||||
-DSQLITE_DISABLE_FTS4_DEFERRED
|
||||
-DSQLITE_ENABLE_RTREE
|
||||
|
@ -120,4 +120,19 @@ do_catchsql_test tabfunc01-4.3 {
|
||||
SELECT * FROM aux1.generate_series(1,4)
|
||||
} {1 {no such table: aux1.generate_series}}
|
||||
|
||||
# The next series of tests is verifying that virtual table are able
|
||||
# to optimize the IN operator, even on terms that are not marked "omit".
|
||||
# When the generate_series virtual table is compiled for the testfixture,
|
||||
# the special -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 option is used, which
|
||||
# causes the xBestIndex method of generate_series to leave the
|
||||
# sqlite3_index_constraint_usage.omit flag set to 0, which should cause
|
||||
# the SQLite core to verify the start=, stop=, and step= constraints on
|
||||
# each step of output. At one point, the IN operator could not be used
|
||||
# by virtual tables unless omit was set.
|
||||
#
|
||||
do_execsql_test tabfunc01-500 {
|
||||
SELECT * FROM generate_series WHERE start IN (1,7) AND stop=20 AND step=10
|
||||
ORDER BY +1;
|
||||
} {1 7 11 17}
|
||||
|
||||
finish_test
|
||||
|
@ -38,6 +38,7 @@ set extras {
|
||||
UPLUS
|
||||
REGISTER
|
||||
ASTERISK
|
||||
SPAN
|
||||
SPACE
|
||||
ILLEGAL
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user