Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed71a839fd | |||
| 81cf13ec7b | |||
| a5750cfe01 | |||
| 21a919f630 | |||
| 0fd613542c | |||
| b22f7c831f | |||
| 0211d8bca4 | |||
| 4bbcf10617 | |||
| e31ae90100 | |||
| 3350ce95f7 | |||
| 5dfd3d9080 | |||
| e08ecad58a | |||
| ee06c99b49 | |||
| 7df89c8c8a | |||
| fe21a796f7 | |||
| e39a732ce2 | |||
| 6645370e5b | |||
| dd31490e02 | |||
| d49c545968 | |||
| a3fdec7172 | |||
| bb44b3de39 | |||
| 9a2555f538 | |||
| a88aca5442 | |||
| b8e59bcb86 | |||
| 81a034b62b | |||
| b04275121c | |||
| ec2da85412 | |||
| db718d8a3b | |||
| 4d06798e56 | |||
| 9c2552f2e8 | |||
| 705a48758a | |||
| a820c05aa0 | |||
| d0879bad42 | |||
| 729677720d | |||
| abfe034692 | |||
| b68b97789e | |||
| 693e671936 | |||
| 53bed45ecb | |||
| 6ef5e12e1f | |||
| 05d3dc29c5 | |||
| dc3bb0deb2 | |||
| 9e2c7ae1b0 | |||
| 3c2aeae16e | |||
| b090352b5a | |||
| afcf9bd806 | |||
| cfe24586a8 | |||
| edf83d1e3d | |||
| 953dfa4e60 | |||
| a8a0617e06 |
+21
-10
@@ -270,6 +270,17 @@ TCC = $(TCC) -I$(TOP)\ext\rtree
|
||||
RCC = $(RCC) -I$(TOP)\ext\rtree
|
||||
!ENDIF
|
||||
|
||||
# The mksqlite3c.tcl script accepts some options on the command
|
||||
# line. When compiling with debugging enabled, some of these
|
||||
# options are necessary in order to allow debugging symbols to
|
||||
# work correctly with Visual Studio when using the amalgamation.
|
||||
#
|
||||
!IF $(DEBUG)>0
|
||||
MKSQLITE3C_ARGS = --linemacros
|
||||
!ELSE
|
||||
MKSQLITE3C_ARGS =
|
||||
!ENDIF
|
||||
|
||||
# Define -DNDEBUG to compile without debugging (i.e., for production usage)
|
||||
# Omitting the define will cause extra debugging code to be inserted and
|
||||
# includes extra comments when "EXPLAIN stmt" is used.
|
||||
@@ -916,7 +927,7 @@ mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h
|
||||
echo > .target_source
|
||||
|
||||
sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl $(MKSQLITE3C_ARGS)
|
||||
copy tsrc\shell.c .
|
||||
copy tsrc\sqlite3ext.h .
|
||||
|
||||
@@ -1334,17 +1345,17 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) -DBUILD_sqlite -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
showdb.exe: $(TOP)\tool\showdb.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)\tool\showdb.c sqlite3.c
|
||||
showdb.exe: $(TOP)\tool\showdb.c $(SQLITE3C)
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \
|
||||
$(TOP)\tool\showdb.c $(SQLITE3C)
|
||||
|
||||
wordcount.exe: $(TOP)\test\wordcount.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)\test\wordcount.c sqlite3.c
|
||||
wordcount.exe: $(TOP)\test\wordcount.c $(SQLITE3C)
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \
|
||||
$(TOP)\test\wordcount.c $(SQLITE3C)
|
||||
|
||||
speedtest1.exe: $(TOP)\test\speedtest1.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)\test\speedtest1.c sqlite3.c
|
||||
speedtest1.exe: $(TOP)\test\speedtest1.c $(SQLITE3C)
|
||||
$(LTLINK) -DSQLITE_OMIT_LOAD_EXTENSION -Fe$@ \
|
||||
$(TOP)\test\speedtest1.c $(SQLITE3C)
|
||||
|
||||
clean:
|
||||
del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib
|
||||
|
||||
@@ -11,5 +11,5 @@ SQLite3 is a self-contains, zero-configuration, transactional SQL database
|
||||
engine. This extension provides an easy to use interface for accessing
|
||||
SQLite database files from Tcl.
|
||||
.PP
|
||||
For full documentation see http://www.sqlite.org/ and
|
||||
in particular http://www.sqlite.org/tclsqlite.html.
|
||||
For full documentation see \fIhttp://www.sqlite.org/\fR and
|
||||
in particular \fIhttp://www.sqlite.org/tclsqlite.html\fR.
|
||||
|
||||
@@ -96,13 +96,13 @@ void sqlite3Fts3HashClear(Fts3Hash *pH){
|
||||
*/
|
||||
static int fts3StrHash(const void *pKey, int nKey){
|
||||
const char *z = (const char *)pKey;
|
||||
int h = 0;
|
||||
unsigned h = 0;
|
||||
if( nKey<=0 ) nKey = (int) strlen(z);
|
||||
while( nKey > 0 ){
|
||||
h = (h<<3) ^ h ^ *z++;
|
||||
nKey--;
|
||||
}
|
||||
return h & 0x7fffffff;
|
||||
return (int)(h & 0x7fffffff);
|
||||
}
|
||||
static int fts3StrCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
||||
if( n1!=n2 ) return 1;
|
||||
|
||||
+30
-8
@@ -1933,7 +1933,6 @@ static int spellfix1Init(
|
||||
#define SPELLFIX_COL_COMMAND 11
|
||||
}
|
||||
if( rc==SQLITE_OK && isCreate ){
|
||||
sqlite3_uint64 r;
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE TABLE IF NOT EXISTS \"%w\".\"%w_vocab\"(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
@@ -1945,11 +1944,10 @@ static int spellfix1Init(
|
||||
");\n",
|
||||
zDbName, zTableName
|
||||
);
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" "
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" "
|
||||
"ON \"%w_vocab\"(langid,k2);",
|
||||
zDbName, zModule, r, zTableName
|
||||
zDbName, zModule, zTableName
|
||||
);
|
||||
}
|
||||
for(i=3; rc==SQLITE_OK && i<argc; i++){
|
||||
@@ -2051,6 +2049,7 @@ static int spellfix1Close(sqlite3_vtab_cursor *cur){
|
||||
** (D) scope = $scope
|
||||
** (E) distance < $distance
|
||||
** (F) distance <= $distance
|
||||
** (G) rowid = $rowid
|
||||
**
|
||||
** The plan number is a bit mask formed with these bits:
|
||||
**
|
||||
@@ -2060,8 +2059,9 @@ static int spellfix1Close(sqlite3_vtab_cursor *cur){
|
||||
** 0x08 (D) is found
|
||||
** 0x10 (E) is found
|
||||
** 0x20 (F) is found
|
||||
** 0x40 (G) is found
|
||||
**
|
||||
** filter.argv[*] values contains $str, $langid, $top, and $scope,
|
||||
** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid
|
||||
** if specified and in that order.
|
||||
*/
|
||||
static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
@@ -2070,6 +2070,7 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
int iTopTerm = -1;
|
||||
int iScopeTerm = -1;
|
||||
int iDistTerm = -1;
|
||||
int iRowidTerm = -1;
|
||||
int i;
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
@@ -2122,6 +2123,15 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
iPlan |= pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ? 16 : 32;
|
||||
iDistTerm = i;
|
||||
}
|
||||
|
||||
/* Terms of the form: distance < $dist or distance <= $dist */
|
||||
if( (iPlan & 64)==0
|
||||
&& pConstraint->iColumn<0
|
||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||
){
|
||||
iPlan |= 64;
|
||||
iRowidTerm = i;
|
||||
}
|
||||
}
|
||||
if( iPlan&1 ){
|
||||
int idx = 2;
|
||||
@@ -2149,6 +2159,11 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
pIdxInfo->aConstraintUsage[iDistTerm].omit = 1;
|
||||
}
|
||||
pIdxInfo->estimatedCost = 1e5;
|
||||
}else if( (iPlan & 64) ){
|
||||
pIdxInfo->idxNum = 64;
|
||||
pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
|
||||
pIdxInfo->estimatedCost = 5;
|
||||
}else{
|
||||
pIdxInfo->idxNum = 0;
|
||||
pIdxInfo->estimatedCost = 1e50;
|
||||
@@ -2465,16 +2480,23 @@ static int spellfix1FilterForFullScan(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int rc;
|
||||
int rc = SQLITE_OK;
|
||||
char *zSql;
|
||||
spellfix1_vtab *pVTab = pCur->pVTab;
|
||||
spellfix1ResetCursor(pCur);
|
||||
assert( idxNum==0 || idxNum==64 );
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT word, rank, NULL, langid, id FROM \"%w\".\"%w_vocab\"",
|
||||
pVTab->zDbName, pVTab->zTableName);
|
||||
"SELECT word, rank, NULL, langid, id FROM \"%w\".\"%w_vocab\"%s",
|
||||
pVTab->zDbName, pVTab->zTableName,
|
||||
((idxNum & 64) ? " WHERE rowid=?" : "")
|
||||
);
|
||||
if( zSql==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pFullScan, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc==SQLITE_OK && (idxNum & 64) ){
|
||||
assert( argc==1 );
|
||||
rc = sqlite3_bind_value(pCur->pFullScan, 1, argv[0]);
|
||||
}
|
||||
pCur->nRow = pCur->iRow = 0;
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_step(pCur->pFullScan);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
C Add\ssupport\sfor\sLIMIT\sand\sOFFSET\sin\sa\srecursive\squery.
|
||||
D 2014-01-22T18:07:04.473
|
||||
C Change\sthe\sOP_InitCoroutine\sinstruction\sto\sjump\sover\sthe\sco-routine\nimplementation.
|
||||
D 2014-02-07T19:18:10.928
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 4d4ead6b71d1bf03028fbd61da0ba0ec5e1556e1
|
||||
F Makefile.msc 6ff3ff2eef45c7dd309a8626ff7947b20bd387e7
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 8ed548d87d0a27fd7d7620476f9e25f9fa742d73
|
||||
@@ -27,7 +27,7 @@ F autoconf/tea/Makefile.in 5c3b0bdfb66c20d55ebff59d1718864461570ca9
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
F autoconf/tea/configure.in e0466b881b53f31f5a4a69e7a91ad130902fb359
|
||||
F autoconf/tea/doc/sqlite3.n e268faa1691c33663d3a7faf9fa30673d14bd879
|
||||
F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb
|
||||
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
|
||||
F autoconf/tea/pkgIndex.tcl.in 3ef61715cf1c7bdcff56947ffadb26bc991ca39d
|
||||
F autoconf/tea/tclconfig/install-sh b087e5c4b92820c60bffb74acc1d9c2d40d80b8f
|
||||
@@ -83,7 +83,7 @@ F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac
|
||||
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_porter.c 7f8b4bf5af7c0f20f73b8e87e14fa9298f52e290
|
||||
@@ -114,7 +114,7 @@ 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/spellfix.c 76578f2c56ceaa23d22032338d90db79c68490fb
|
||||
F ext/misc/spellfix.c 3548c433f473c2054e080b6382771636fcaa2c4c
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
@@ -157,38 +157,38 @@ F mptest/mptest.c 499a74af4be293b7c1c7c3d40f332b67227dd739
|
||||
F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e
|
||||
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/alter.c d5348d0f86a5fc8fb3987727402f023953c021cf
|
||||
F src/analyze.c 581d5c18ce89c6f45d4dca65914d0de5b4dad41f
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 02e1a4e71d8fc37e9fd5216c15d989d148a77c87
|
||||
F src/btree.c 7b2c3cd16deedff7f4904f2e871e7b77328b9872
|
||||
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 7e6c275ab1731510d6f793d0f88373ab3e858e69
|
||||
F src/build.c 40c38ec8f10835cf68879cb12e7c00e32b8edf78
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 91e1321021db5dc266360531b8b6550009d771ff
|
||||
F src/expr.c 8c7e482bc8f7982333f046851a610ccdb8a1ba94
|
||||
F src/delete.c 6765a421f08adbedc5d52d21760ec6dbe5123fd3
|
||||
F src/expr.c fabda9e9320e3284c2a35cdc558313d9e80ce92a
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c 6325ac2ec10833ccf4d5c36d323709221d37ea19
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a4450f0c46a9f221622e6551ab0953b03c4f8ee8
|
||||
F src/insert.c b50cb5a51edb0d6e1a99e04b232b8632a54e522a
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c 4a05a9706579c7649d7eebb0094586728eb53fcb
|
||||
F src/main.c 07225af6a00be0b7f34ac52e60f99cf5cbb2a475
|
||||
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
@@ -205,38 +205,38 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 3a4dcb554d3c915075766162f28c3fd4cdb75968
|
||||
F src/os_win.c 1b21af72c5fa6f9e519a5fcab33e80d182b1aedb
|
||||
F src/os_unix.c f3ed0e406cbf9c820565b2118232d0796346130f
|
||||
F src/os_win.c d4284f003445054a26689f1264b1b9bf7261bd1b
|
||||
F src/pager.c efa923693e958696eee69b205a20bfbc402c8480
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y 475896cb883bbf4782e98abda42efbbdcbdb75f5
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/parse.y bd51bc17cbfe7549adb4ca3747b1c3d384645065
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c ed409ce4104cf4d9de6ead40ace70974f124853b
|
||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||
F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c f6d84f3a109d3e43d38089da6a4f131a5ce4c6ef
|
||||
F src/shell.c 24722d24d4ea8ca93db35e44db7308de786767ca
|
||||
F src/select.c 47d93e6f0b58000e2093e7b489bdca778884f82a
|
||||
F src/shell.c 7dedf7367ee49050b0366bf8dbc8ec2bd15b42c7
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 87a90ad4818ac5d68d3463eb7fe3ed96e5209b25
|
||||
F src/sqliteInt.h fdab572b3567d587cf3096e3ca5dabcedda3fa66
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 46073db71011b6542fde1f234c56a076d5ff23f9
|
||||
F src/test1.c db16ba651453b15001c7f2838c446284dde4ecaf
|
||||
F src/tclsqlite.c 21ca0043d7c48cde5dabed5c1116eee1be692f62
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723
|
||||
F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2
|
||||
F src/test8.c c7aab1d9fbbf54fc33d43b73aa24aa55f9eaf534
|
||||
F src/test8.c 54ccd7b1df5062f0ecbf50a8f7b618f8b1f13b20
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
@@ -276,25 +276,25 @@ F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98
|
||||
F src/update.c c2706a6eb232a96345c35b7e1e75a188e26812bb
|
||||
F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c e71f19b272f05c8695cf747b4bac1732685f9e5c
|
||||
F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c dede894c2990329f8bc5a70da7de44ce8c3c6bf5
|
||||
F src/vdbe.c e7bb0587ad4866c0db5fe3b83104c4df8f93d19f
|
||||
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
||||
F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56
|
||||
F src/vdbeInt.h b5d62957a408c4bea649484008e5f98335b09e97
|
||||
F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad
|
||||
F src/vdbeaux.c 9f4bfc52672acbb0bb4493d6a03603dc5a595ac1
|
||||
F src/vdbeblob.c bc40f98f256f0b34116d6a44b114da4a81a15d33
|
||||
F src/vdbemem.c 0e69351b2c6ff7d8b638688c0ae336a26befa6b2
|
||||
F src/vdbeaux.c 3fd95b226330e1d50aedb40d750effe726ebb3fb
|
||||
F src/vdbeblob.c 9542e116c1db5ed813977581d506c176e117c0ec
|
||||
F src/vdbemem.c c0bcc02d6816ab4218ac0f94b63c8ee78a0f739f
|
||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 67ae3b5e97ecff36c70cb61ccc7d74cf228f1596
|
||||
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
|
||||
F src/where.c 8c2aada8b44140382406cf07b84ff2f6127cb39e
|
||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@@ -364,15 +364,15 @@ F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test 56ab450125ead38846cbae7e5b6a216686c3cffa
|
||||
F test/capi3.test 6cdd49656bd62a296924f4d2fcfd05cd2a298369
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 93d24621c9ff84da9da060f30431e0453db1cdb0
|
||||
F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32
|
||||
F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
|
||||
F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763
|
||||
F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7
|
||||
F test/closure01.test b1703ba40639cfc9b295cf478d70739415eec6a4
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test 73b91005f264b7c403e2d63a6708d150679ac99a
|
||||
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
|
||||
@@ -406,7 +406,7 @@ F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test c150f156dace653c00a121ad0f5772a0568c41ba
|
||||
F test/corruptH.test 0a247f3dc8a8f3578db5f639d86c6bb4d520207f
|
||||
F test/corruptH.test 9d8186f6f8751efdfd445d8546fd98f073499039
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -439,13 +439,13 @@ F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
|
||||
F test/e_fkey.test d83a04478bb9c02d2c513518548a69f818869f41
|
||||
F test/e_fkey.test 630597377549af579d34faaf64c6959a5a68ef76
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
|
||||
F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589
|
||||
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
|
||||
F test/e_select.test d3226cb94fae4af3f198e68e71f655e106d0be47
|
||||
F test/e_select2.test 22c660a7becf0712c95e1ca1b2d9e716a1261460
|
||||
F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
|
||||
F test/e_uri.test a2c92d80093a7efdcfbb11093651cbea87097b6b
|
||||
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
|
||||
@@ -700,8 +700,8 @@ F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test 1265eb98c2e22a446a13fdef754118b272716684
|
||||
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
|
||||
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
|
||||
F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912
|
||||
F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b
|
||||
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
|
||||
F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e
|
||||
@@ -728,8 +728,8 @@ F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pager4.test b40ecb4cc7dff957ee7916e41ab21d1ed702a642
|
||||
F test/pagerfault.test 7285379906ab2f1108b8e82bbdf2d386cc8ff3ff
|
||||
F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e
|
||||
F test/pagerfault.test ae9ee0db5a30aecda9db8290ce3dd12e5f7bbaa1
|
||||
F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f
|
||||
F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8
|
||||
F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
|
||||
@@ -737,11 +737,11 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test af3278cbea3a19e025d5169be8193ff48dc3f862
|
||||
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
|
||||
F test/pragma.test e882183ecd21d064cec5c7aaea174fbd36293429
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/printf2.test 414fcba6d6c10e0a5e58efd213811e5ead4635a0
|
||||
F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1
|
||||
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
@@ -783,7 +783,7 @@ F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||
F test/select4.test 00179be44e531fe04c1c3f15df216439dff2519d
|
||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
||||
F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
||||
F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 99cf21df033b93033ea4f34aba14a500f48f04fe
|
||||
@@ -825,7 +825,7 @@ F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 7130d2cb6db45baa553a4ab2f715116c71c2d9f4
|
||||
F test/spellfix.test 8c40b169b104086d8795781f670ba3c786d6d8be
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
@@ -844,7 +844,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 08e9f317afe60d398fa900993503ecaef3295bad
|
||||
F test/tester.tcl 9bd04481b8b0ef1f2049ad01f28e175ee9a14f7b
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -1092,7 +1092,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test 97166cc72de5327bbae782aece707c45ee40e41b
|
||||
F test/with1.test ce15d69d34a2576b0e47d78c244d1ba2a31679d1
|
||||
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
@@ -1127,12 +1127,12 @@ F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
|
||||
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
|
||||
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
|
||||
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
|
||||
F tool/omittest.tcl 4665982e95a6e5c1bd806cf7bc3dea95be422d77
|
||||
F tool/omittest.tcl 34d7ac01fe4fd18e3637f64abe12c40eca0f6b97
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
F tool/showdb.c 525ecc443578647703051308ad50a93de6ba2c4b
|
||||
F tool/showdb.c 1f3fe634d6f690b8d39ab1b9fd34583d468921e1
|
||||
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
|
||||
F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
@@ -1152,7 +1152,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 37b343b01841b338954ddfa9b76d92aa50037aec
|
||||
R f6fa1b44c6431db29f11962241b14895
|
||||
P 1ec0e9dd4b26d9f597adc8e062317d4866c5a6a6
|
||||
R dbad771d6a0c64046f81724e16a6d61c
|
||||
U drh
|
||||
Z a802989c6813792648a40d2b5db727ef
|
||||
Z bb5cd7d324cd2ad57b192424d498539f
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1945484e6b9769c1943f750f5b09860417fb190a
|
||||
a522f364a6b8ca6f69c353b30609a2166f6e94cf
|
||||
@@ -2,7 +2,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH SQLITE3 1 "Mon Apr 15 23:49:17 2002"
|
||||
.TH SQLITE3 1 "Mon Jan 31 11:14:00 2014"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
@@ -49,7 +49,7 @@ a table named "memos" and insert a couple of records into that table:
|
||||
$
|
||||
.B sqlite3 mydata.db
|
||||
.br
|
||||
SQLite version 3.1.3
|
||||
SQLite version 3.8.3
|
||||
.br
|
||||
Enter ".help" for instructions
|
||||
.br
|
||||
@@ -108,15 +108,24 @@ sqlite>
|
||||
.B .help
|
||||
.nf
|
||||
.cc |
|
||||
.backup ?DB? FILE Backup DB (default "main") to FILE
|
||||
.bail ON|OFF Stop after hitting an error. Default OFF
|
||||
.databases List names and files of attached databases
|
||||
.dump ?TABLE? ... Dump the database in an SQL text format
|
||||
If TABLE specified, only dump tables matching
|
||||
LIKE pattern TABLE.
|
||||
.echo ON|OFF Turn command echo on or off
|
||||
.exit Exit this program
|
||||
.explain ON|OFF Turn output mode suitable for EXPLAIN on or off.
|
||||
.explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.
|
||||
With no args, it turns EXPLAIN on.
|
||||
.header(s) ON|OFF Turn display of headers on or off
|
||||
.help Show this message
|
||||
.import FILE TABLE Import data from FILE into TABLE
|
||||
.indices TABLE Show names of all indices on TABLE
|
||||
.indices ?TABLE? Show names of all indices
|
||||
If TABLE specified, only show indices for tables
|
||||
matching LIKE pattern TABLE.
|
||||
.load FILE ?ENTRY? Load an extension library
|
||||
.log FILE|off Turn logging on or off. FILE can be stderr/stdout
|
||||
.mode MODE ?TABLE? Set output mode where MODE is one of:
|
||||
csv Comma-separated values
|
||||
column Left-aligned columns. (See .width)
|
||||
@@ -126,46 +135,76 @@ sqlite>
|
||||
list Values delimited by .separator string
|
||||
tabs Tab-separated values
|
||||
tcl TCL list elements
|
||||
.nullvalue STRING Print STRING in place of NULL values
|
||||
.nullvalue STRING Use STRING in place of NULL values
|
||||
.open ?FILENAME? Close existing database and reopen FILENAME
|
||||
.output FILENAME Send output to FILENAME
|
||||
.output stdout Send output to the screen
|
||||
.print STRING... Print literal STRING
|
||||
.prompt MAIN CONTINUE Replace the standard prompts
|
||||
.quit Exit this program
|
||||
.read FILENAME Execute SQL in FILENAME
|
||||
.restore ?DB? FILE Restore content of DB (default "main") from FILE
|
||||
.schema ?TABLE? Show the CREATE statements
|
||||
If TABLE specified, only show tables matching
|
||||
LIKE pattern TABLE.
|
||||
.separator STRING Change separator used by output mode and .import
|
||||
.show Show the current values for various settings
|
||||
.tables ?PATTERN? List names of tables matching a LIKE pattern
|
||||
.stats ON|OFF Turn stats on or off
|
||||
.tables ?TABLE? List names of tables
|
||||
If TABLE specified, only list tables matching
|
||||
LIKE pattern TABLE.
|
||||
.timeout MS Try opening locked tables for MS milliseconds
|
||||
.width NUM NUM ... Set column widths for "column" mode
|
||||
.trace FILE|off Output each SQL statement as it is run
|
||||
.vfsname ?AUX? Print the name of the VFS stack
|
||||
.width NUM1 NUM2 ... Set column widths for "column" mode
|
||||
.timer ON|OFF Turn the CPU timer measurement on or off
|
||||
sqlite>
|
||||
|cc .
|
||||
.sp
|
||||
.fi
|
||||
|
||||
.SH OPTIONS
|
||||
.B sqlite3
|
||||
has the following options:
|
||||
.TP
|
||||
.BI \-init\ file
|
||||
Read and execute commands from
|
||||
.I file
|
||||
, which can contain a mix of SQL statements and meta-commands.
|
||||
.B \-bail
|
||||
Stop after hitting an error.
|
||||
.TP
|
||||
.B \-echo
|
||||
Print commands before execution.
|
||||
.TP
|
||||
.B \-[no]header
|
||||
Turn headers on or off.
|
||||
.B \-batch
|
||||
Force batch I/O.
|
||||
.TP
|
||||
.B \-column
|
||||
Query results will be displayed in a table like form, using
|
||||
whitespace characters to separate the columns and align the
|
||||
output.
|
||||
.TP
|
||||
.BI \-cmd\ command
|
||||
run
|
||||
.I command
|
||||
before reading stdin
|
||||
.TP
|
||||
.B \-csv
|
||||
Set output mode to CSV (comma separated values).
|
||||
.TP
|
||||
.B \-echo
|
||||
Print commands before execution.
|
||||
.TP
|
||||
.BI \-init\ file
|
||||
Read and execute commands from
|
||||
.I file
|
||||
, which can contain a mix of SQL statements and meta-commands.
|
||||
.TP
|
||||
.B \-[no]header
|
||||
Turn headers on or off.
|
||||
.TP
|
||||
.B \-help
|
||||
Show help on options and exit.
|
||||
.TP
|
||||
.B \-html
|
||||
Query results will be output as simple HTML tables.
|
||||
.TP
|
||||
.B \-interactive
|
||||
Force interactive I/O.
|
||||
.TP
|
||||
.B \-line
|
||||
Query results will be displayed with one value per line, rows
|
||||
separated by a blank line. Designed to be easily parsed by
|
||||
@@ -175,18 +214,28 @@ scripts or other programs
|
||||
Query results will be displayed with the separator (|, by default)
|
||||
character between each field value. The default.
|
||||
.TP
|
||||
.BI \-separator\ separator
|
||||
Set output field separator. Default is '|'.
|
||||
.BI \-mmap\ N
|
||||
Set default mmap size to
|
||||
.I N
|
||||
\.
|
||||
.TP
|
||||
.BI \-nullvalue\ string
|
||||
Set string used to represent NULL values. Default is ''
|
||||
(empty string).
|
||||
.TP
|
||||
.BI \-separator\ separator
|
||||
Set output field separator. Default is '|'.
|
||||
.TP
|
||||
.B \-stats
|
||||
Print memory stats before each finalize.
|
||||
.TP
|
||||
.B \-version
|
||||
Show SQLite version.
|
||||
.TP
|
||||
.B \-help
|
||||
Show help on options and exit.
|
||||
.BI \-vfs\ name
|
||||
Use
|
||||
.I name
|
||||
as the default VFS.
|
||||
|
||||
|
||||
.SH INIT FILE
|
||||
@@ -222,8 +271,9 @@ o All other command line options are processed.
|
||||
.SH SEE ALSO
|
||||
http://www.sqlite.org/
|
||||
.br
|
||||
The sqlite-doc package
|
||||
The sqlite3-doc package.
|
||||
.SH AUTHOR
|
||||
This manual page was originally written by Andreas Rottmann
|
||||
<rotty@debian.org>, for the Debian GNU/Linux system (but may be used
|
||||
by others). It was subsequently revised by Bill Bumgarner <bbum@mac.com>.
|
||||
by others). It was subsequently revised by Bill Bumgarner <bbum@mac.com> and
|
||||
further updated by Laszlo Boszormenyi <gcs@debian.hu> .
|
||||
|
||||
+1
-1
@@ -469,7 +469,7 @@ void sqlite3AlterRenameTable(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
/* Begin a transaction for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema). Open a statement transaction if the table is a virtual
|
||||
** table.
|
||||
|
||||
+21
-1
@@ -4777,6 +4777,15 @@ int sqlite3BtreeEof(BtCursor *pCur){
|
||||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the last entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
@@ -4785,6 +4794,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
rc = restoreCursorPosition(pCur);
|
||||
@@ -4863,6 +4873,15 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the first entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
@@ -4870,6 +4889,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->atLast = 0;
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
@@ -7096,7 +7116,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||
** sub-tree headed by the child page of the cell being deleted. This makes
|
||||
** balancing the tree following the delete operation easier. */
|
||||
if( !pPage->leaf ){
|
||||
int notUsed;
|
||||
int notUsed = 0;
|
||||
rc = sqlite3BtreePrevious(pCur, ¬Used);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
||||
+8
-7
@@ -156,13 +156,14 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||
if( db->init.busy==0 ){
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
sqlite3VdbeAddOp3(v, OP_VerifyCookie,
|
||||
iDb, pParse->cookieValue[iDb],
|
||||
db->aDb[iDb].pSchema->iGeneration);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v,
|
||||
OP_Transaction, /* Opcode */
|
||||
iDb, /* P1 */
|
||||
(mask & pParse->writeMask)!=0, /* P2 */
|
||||
pParse->cookieValue[iDb], /* P3 */
|
||||
db->aDb[iDb].pSchema->iGeneration /* P4 */
|
||||
);
|
||||
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=0; i<pParse->nVtabLock; i++){
|
||||
|
||||
+3
-6
@@ -97,10 +97,8 @@ void sqlite3MaterializeView(
|
||||
SrcList *pFrom;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
|
||||
|
||||
pWhere = sqlite3ExprDup(db, pWhere, 0);
|
||||
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
||||
|
||||
if( pFrom ){
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
||||
@@ -108,10 +106,7 @@ void sqlite3MaterializeView(
|
||||
assert( pFrom->a[0].pOn==0 );
|
||||
assert( pFrom->a[0].pUsing==0 );
|
||||
}
|
||||
|
||||
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
|
||||
if( pSel ) pSel->selFlags |= SF_Materialize;
|
||||
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
||||
sqlite3Select(pParse, pSel, &dest);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
@@ -636,7 +631,9 @@ void sqlite3GenerateRowDelete(
|
||||
** used by any BEFORE and AFTER triggers that exist. */
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( mask==0xffffffff || mask&(1<<iCol) ){
|
||||
testcase( mask!=0xffffffff && iCol==31 );
|
||||
testcase( mask!=0xffffffff && iCol==32 );
|
||||
if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-9
@@ -1064,6 +1064,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
pNew->nSelectRow = p->nSelectRow;
|
||||
pNew->pWith = withDup(db, p->pWith);
|
||||
return pNew;
|
||||
}
|
||||
@@ -1583,12 +1584,10 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
iCol = (i16)pExpr->iColumn;
|
||||
|
||||
/* Code an OP_VerifyCookie and OP_TableLock for <table>. */
|
||||
if( ALWAYS(pTab->pSchema) ){
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
}
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
/* This function is only called from two places. In both cases the vdbe
|
||||
** has already been allocated. So assume sqlite3GetVdbe() is always
|
||||
@@ -1764,7 +1763,6 @@ int sqlite3CodeSubselect(
|
||||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
|
||||
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
@@ -2687,7 +2685,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
FuncDef *pDef; /* The function definition object */
|
||||
int nId; /* Length of the function name in bytes */
|
||||
const char *zId; /* The function name */
|
||||
int constMask = 0; /* Mask of function arguments that are constant */
|
||||
u32 constMask = 0; /* Mask of function arguments that are constant */
|
||||
int i; /* Loop counter */
|
||||
u8 enc = ENC(db); /* The text encoding used by this database */
|
||||
CollSeq *pColl = 0; /* A collating sequence */
|
||||
@@ -2738,7 +2736,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
|
||||
for(i=0; i<nFarg; i++){
|
||||
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
|
||||
constMask |= (1<<i);
|
||||
testcase( i==31 );
|
||||
constMask |= MASKBIT32(i);
|
||||
}
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
case SQLITE_INTEGER: {
|
||||
i64 iVal = sqlite3_value_int64(argv[0]);
|
||||
if( iVal<0 ){
|
||||
if( (iVal<<1)==0 ){
|
||||
if( iVal==SMALLEST_INT64 ){
|
||||
/* IMP: R-31676-45509 If X is the integer -9223372036854775808
|
||||
** then abs(X) throws an integer overflow error since there is no
|
||||
** equivalent positive 64-bit two complement value. */
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ void sqlite3HashClear(Hash *pH){
|
||||
** The hashing function.
|
||||
*/
|
||||
static unsigned int strHash(const char *z, int nKey){
|
||||
int h = 0;
|
||||
unsigned int h = 0;
|
||||
assert( nKey>=0 );
|
||||
while( nKey > 0 ){
|
||||
h = (h<<3) ^ h ^ sqlite3UpperToLower[(unsigned char)*z++];
|
||||
|
||||
+18
-51
@@ -349,17 +349,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSDParm+1 The register holding the "completed" flag for the
|
||||
** co-routine. This register is 0 if the previous Yield
|
||||
** generated a new result row, or 1 if the subquery
|
||||
** has completed. If the Yield is called again
|
||||
** after this register becomes 1, then the VDBE will
|
||||
** halt with an SQLITE_INTERNAL error.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** At EOF the first result register will be marked as "undefined" so that
|
||||
** the caller can know when to stop reading results.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
@@ -370,7 +366,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** EOF <- 0
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
@@ -378,16 +373,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X
|
||||
** if EOF goto E
|
||||
** S: yield X, at EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
@@ -396,31 +388,21 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int regEof; /* Register holding co-routine completion flag */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int j1; /* Jump instruction */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
regEof = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
|
||||
VdbeComment((v, "Co-routine entry point"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||
VdbeComment((v, "Co-routine completion flag"));
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
|
||||
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
rc = sqlite3Select(pParse, pSelect, pDest);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||
VdbeComment((v, "End of coroutine"));
|
||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -488,7 +470,6 @@ static int xferOptimization(
|
||||
** and the SELECT clause does not read from <table> at any time.
|
||||
** The generated code follows this template:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
@@ -497,12 +478,9 @@ static int xferOptimization(
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** goto A
|
||||
** end-coroutine X
|
||||
** B: open write cursor to <table> and its indices
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: cleanup
|
||||
@@ -513,7 +491,6 @@ static int xferOptimization(
|
||||
** we have to use a intermediate table to store the results of
|
||||
** the select. The template is like this:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
@@ -522,12 +499,9 @@ static int xferOptimization(
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, at EOF goto M
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: open write cursor to <table> and its indices
|
||||
@@ -576,7 +550,6 @@ void sqlite3Insert(
|
||||
int regIns; /* Block of regs holding rowid+data being inserted */
|
||||
int regRowid; /* registers holding insert rowid */
|
||||
int regData; /* register holding first column to insert */
|
||||
int regEof = 0; /* Register recording end of SELECT data */
|
||||
int *aRegIdx = 0; /* One register allocated to each index */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
@@ -689,7 +662,6 @@ void sqlite3Insert(
|
||||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
|
||||
regEof = dest.iSDParm + 1;
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
@@ -714,8 +686,7 @@ void sqlite3Insert(
|
||||
** here is from the 4th template:
|
||||
**
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, goto M at EOF
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: ...
|
||||
@@ -723,19 +694,17 @@ void sqlite3Insert(
|
||||
int regRec; /* Register to hold packed record */
|
||||
int regTempRowid; /* Register to hold temp table ROWID */
|
||||
int addrTop; /* Label "L" */
|
||||
int addrIf; /* Address of jump to M */
|
||||
|
||||
srcTab = pParse->nTab++;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
regTempRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||
sqlite3VdbeJumpHere(v, addrIf);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
@@ -847,7 +816,7 @@ void sqlite3Insert(
|
||||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 4):
|
||||
**
|
||||
** rewind temp table
|
||||
** rewind temp table, if empty goto D
|
||||
** C: loop over rows of intermediate table
|
||||
** transfer values form intermediate table into <table>
|
||||
** end loop
|
||||
@@ -859,14 +828,12 @@ void sqlite3Insert(
|
||||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 3):
|
||||
**
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: ...
|
||||
*/
|
||||
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
}
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
|
||||
+1
-1
@@ -3303,7 +3303,7 @@ int sqlite3_test_control(int op, ...){
|
||||
** that demonstrat invariants on well-formed database files.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
|
||||
sqlite3Config.neverCorrupt = va_arg(ap, int);
|
||||
sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -4097,7 +4097,7 @@ static int unixShmSystemLock(
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ u16 mask;
|
||||
OSTRACE(("SHM-LOCK "));
|
||||
mask = ofst>31 ? 0xffffffff : (1<<(ofst+n)) - (1<<ofst);
|
||||
mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock %d ok", ofst));
|
||||
|
||||
+1
-1
@@ -3201,7 +3201,7 @@ static int winDeviceCharacteristics(sqlite3_file *id){
|
||||
** During sqlite3_os_init() we do a GetSystemInfo()
|
||||
** to get the granularity size.
|
||||
*/
|
||||
SYSTEM_INFO winSysInfo;
|
||||
static SYSTEM_INFO winSysInfo;
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
|
||||
+1
-1
@@ -397,7 +397,7 @@ cmd ::= DROP VIEW ifexists(E) fullname(X). {
|
||||
//////////////////////// The SELECT statement /////////////////////////////////
|
||||
//
|
||||
cmd ::= select(X). {
|
||||
SelectDest dest = {SRT_Output, 0, 0, 0, 0};
|
||||
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
|
||||
sqlite3Select(pParse, X, &dest);
|
||||
sqlite3ExplainBegin(pParse->pVdbe);
|
||||
sqlite3ExplainSelect(pParse->pVdbe, X);
|
||||
|
||||
+26
-8
@@ -23,7 +23,8 @@ struct PCache {
|
||||
int szCache; /* Configured cache size */
|
||||
int szPage; /* Size of every page in this cache */
|
||||
int szExtra; /* Size of extra space for each page */
|
||||
int bPurgeable; /* True if pages are on backing store */
|
||||
u8 bPurgeable; /* True if pages are on backing store */
|
||||
u8 eCreate; /* eCreate value for for xFetch() */
|
||||
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
||||
void *pStress; /* Argument to xStress */
|
||||
sqlite3_pcache *pCache; /* Pluggable cache module */
|
||||
@@ -90,6 +91,10 @@ static void pcacheRemoveFromDirtyList(PgHdr *pPage){
|
||||
}else{
|
||||
assert( pPage==p->pDirty );
|
||||
p->pDirty = pPage->pDirtyNext;
|
||||
if( p->pDirty==0 && p->bPurgeable ){
|
||||
assert( p->eCreate==1 );
|
||||
p->eCreate = 2;
|
||||
}
|
||||
}
|
||||
pPage->pDirtyNext = 0;
|
||||
pPage->pDirtyPrev = 0;
|
||||
@@ -110,6 +115,9 @@ static void pcacheAddToDirtyList(PgHdr *pPage){
|
||||
if( pPage->pDirtyNext ){
|
||||
assert( pPage->pDirtyNext->pDirtyPrev==0 );
|
||||
pPage->pDirtyNext->pDirtyPrev = pPage;
|
||||
}else if( p->bPurgeable ){
|
||||
assert( p->eCreate==2 );
|
||||
p->eCreate = 1;
|
||||
}
|
||||
p->pDirty = pPage;
|
||||
if( !p->pDirtyTail ){
|
||||
@@ -179,6 +187,7 @@ void sqlite3PcacheOpen(
|
||||
p->szPage = szPage;
|
||||
p->szExtra = szExtra;
|
||||
p->bPurgeable = bPurgeable;
|
||||
p->eCreate = 2;
|
||||
p->xStress = xStress;
|
||||
p->pStress = pStress;
|
||||
p->szCache = 100;
|
||||
@@ -218,7 +227,7 @@ int sqlite3PcacheFetch(
|
||||
int createFlag, /* If true, create page if it does not exist already */
|
||||
PgHdr **ppPage /* Write the page here */
|
||||
){
|
||||
sqlite3_pcache_page *pPage = 0;
|
||||
sqlite3_pcache_page *pPage;
|
||||
PgHdr *pPgHdr = 0;
|
||||
int eCreate;
|
||||
|
||||
@@ -229,8 +238,12 @@ int sqlite3PcacheFetch(
|
||||
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
|
||||
** allocate it now.
|
||||
*/
|
||||
if( !pCache->pCache && createFlag ){
|
||||
if( !pCache->pCache ){
|
||||
sqlite3_pcache *p;
|
||||
if( !createFlag ){
|
||||
*ppPage = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
p = sqlite3GlobalConfig.pcache2.xCreate(
|
||||
pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
||||
);
|
||||
@@ -241,11 +254,16 @@ int sqlite3PcacheFetch(
|
||||
pCache->pCache = p;
|
||||
}
|
||||
|
||||
eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
|
||||
if( pCache->pCache ){
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
}
|
||||
|
||||
/* eCreate defines what to do if the page does not exist.
|
||||
** 0 Do not allocate a new page. (createFlag==0)
|
||||
** 1 Allocate a new page if doing so is inexpensive.
|
||||
** (createFlag==1 AND bPurgeable AND pDirty)
|
||||
** 2 Allocate a new page even it doing so is difficult.
|
||||
** (createFlag==1 AND !(bPurgeable AND pDirty)
|
||||
*/
|
||||
eCreate = createFlag==0 ? 0 : pCache->eCreate;
|
||||
assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate );
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
if( !pPage && eCreate==1 ){
|
||||
PgHdr *pPg;
|
||||
|
||||
|
||||
+2
-1
@@ -720,6 +720,7 @@ static sqlite3_pcache_page *pcache1Fetch(
|
||||
PGroup *pGroup;
|
||||
PgHdr1 *pPage = 0;
|
||||
|
||||
assert( offsetof(PgHdr1,page)==0 );
|
||||
assert( pCache->bPurgeable || createFlag!=1 );
|
||||
assert( pCache->bPurgeable || pCache->nMin==0 );
|
||||
assert( pCache->bPurgeable==0 || pCache->nMin==10 );
|
||||
@@ -825,7 +826,7 @@ fetch_out:
|
||||
pCache->iMaxKey = iKey;
|
||||
}
|
||||
pcache1LeaveMutex(pGroup);
|
||||
return &pPage->page;
|
||||
return (sqlite3_pcache_page*)pPage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+76
-85
@@ -765,12 +765,8 @@ static void selectInnerLoop(
|
||||
}
|
||||
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/* Send the data to the callback function or to a subroutine. In the
|
||||
** case of a subroutine, the subroutine itself is responsible for
|
||||
** popping the data from the stack.
|
||||
*/
|
||||
case SRT_Coroutine:
|
||||
case SRT_Output: {
|
||||
case SRT_Coroutine: /* Send data to a co-routine */
|
||||
case SRT_Output: { /* Return the results */
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
if( pOrderBy ){
|
||||
@@ -814,6 +810,7 @@ static void selectInnerLoop(
|
||||
** been added */
|
||||
addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0, r3, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
}
|
||||
for(i=0; i<nKey; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy,
|
||||
@@ -1724,7 +1721,44 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
||||
|
||||
/*
|
||||
** The select statement passed as the second parameter is a compound SELECT
|
||||
** with an ORDER BY clause. This function allocates and returns a KeyInfo
|
||||
** structure suitable for implementing the ORDER BY.
|
||||
**
|
||||
** Space to hold the KeyInfo structure is obtained from malloc. The calling
|
||||
** function is responsible for ensuring that this structure is eventually
|
||||
** freed.
|
||||
*/
|
||||
static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
int nOrderBy = p->pOrderBy->nExpr;
|
||||
sqlite3 *db = pParse->db;
|
||||
KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
|
||||
if( pRet ){
|
||||
int i;
|
||||
for(i=0; i<nOrderBy; i++){
|
||||
struct ExprList_item *pItem = &pOrderBy->a[i];
|
||||
Expr *pTerm = pItem->pExpr;
|
||||
CollSeq *pColl;
|
||||
|
||||
if( pTerm->flags & EP_Collate ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pTerm);
|
||||
}else{
|
||||
pColl = multiSelectCollSeq(pParse, p, pItem->u.x.iOrderByCol-1);
|
||||
if( pColl==0 ) pColl = db->pDfltColl;
|
||||
pOrderBy->a[i].pExpr =
|
||||
sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
|
||||
}
|
||||
assert( sqlite3KeyInfoIsWriteable(pRet) );
|
||||
pRet->aColl[i] = pColl;
|
||||
pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
||||
}
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_CTE
|
||||
/*
|
||||
@@ -1774,7 +1808,7 @@ static void generateWithRecursiveQuery(
|
||||
Select *pSetup = p->pPrior; /* The setup query */
|
||||
int addrTop; /* Top of the loop */
|
||||
int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
|
||||
int iCurrent; /* The Current table */
|
||||
int iCurrent = 0; /* The Current table */
|
||||
int regCurrent; /* Register holding Current table */
|
||||
int iQueue; /* The Queue table */
|
||||
int iDistinct = 0; /* To ensure unique results if UNION */
|
||||
@@ -1798,6 +1832,7 @@ static void generateWithRecursiveQuery(
|
||||
regOffset = p->iOffset;
|
||||
p->pLimit = p->pOffset = 0;
|
||||
p->iLimit = p->iOffset = 0;
|
||||
pOrderBy = p->pOrderBy;
|
||||
|
||||
/* Locate the cursor number of the Current table */
|
||||
for(i=0; ALWAYS(i<pSrc->nSrc); i++){
|
||||
@@ -1807,10 +1842,6 @@ static void generateWithRecursiveQuery(
|
||||
}
|
||||
}
|
||||
|
||||
/* Detach the ORDER BY clause from the compound SELECT */
|
||||
pOrderBy = p->pOrderBy;
|
||||
p->pOrderBy = 0;
|
||||
|
||||
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
|
||||
** the Distinct table must be exactly one greater than Queue in order
|
||||
** for the SRT_DistTable and SRT_DistQueue destinations to work. */
|
||||
@@ -1827,7 +1858,7 @@ static void generateWithRecursiveQuery(
|
||||
regCurrent = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
|
||||
if( pOrderBy ){
|
||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 1);
|
||||
KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO);
|
||||
destQueue.pOrderBy = pOrderBy;
|
||||
@@ -1840,6 +1871,9 @@ static void generateWithRecursiveQuery(
|
||||
p->selFlags |= SF_UsesEphemeral;
|
||||
}
|
||||
|
||||
/* Detach the ORDER BY clause from the compound SELECT */
|
||||
p->pOrderBy = 0;
|
||||
|
||||
/* Store the results of the setup-query in Queue. */
|
||||
rc = sqlite3Select(pParse, pSetup, &destQueue);
|
||||
if( rc ) goto end_of_recursive_query;
|
||||
@@ -1882,7 +1916,7 @@ end_of_recursive_query:
|
||||
p->pOffset = pOffset;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif /* SQLITE_OMIT_CTE */
|
||||
|
||||
/* Forward references */
|
||||
static int multiSelectOrderBy(
|
||||
@@ -1892,7 +1926,6 @@ static int multiSelectOrderBy(
|
||||
);
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
/*
|
||||
** This routine is called to process a compound query form from
|
||||
** two or more separate queries using UNION, UNION ALL, EXCEPT, or
|
||||
@@ -1936,8 +1969,8 @@ static int multiSelect(
|
||||
Select *pDelete = 0; /* Chain of simple selects to delete */
|
||||
sqlite3 *db; /* Database connection */
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
int iSub1; /* EQP id of left-hand query */
|
||||
int iSub2; /* EQP id of right-hand query */
|
||||
int iSub1 = 0; /* EQP id of left-hand query */
|
||||
int iSub2 = 0; /* EQP id of right-hand query */
|
||||
#endif
|
||||
|
||||
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
|
||||
@@ -2535,9 +2568,7 @@ static int multiSelectOrderBy(
|
||||
SelectDest destA; /* Destination for coroutine A */
|
||||
SelectDest destB; /* Destination for coroutine B */
|
||||
int regAddrA; /* Address register for select-A coroutine */
|
||||
int regEofA; /* Flag to indicate when select-A is complete */
|
||||
int regAddrB; /* Address register for select-B coroutine */
|
||||
int regEofB; /* Flag to indicate when select-B is complete */
|
||||
int addrSelectA; /* Address of the select-A coroutine */
|
||||
int addrSelectB; /* Address of the select-B coroutine */
|
||||
int regOutA; /* Address register for the output-A subroutine */
|
||||
@@ -2545,6 +2576,7 @@ static int multiSelectOrderBy(
|
||||
int addrOutA; /* Address of the output-A subroutine */
|
||||
int addrOutB = 0; /* Address of the output-B subroutine */
|
||||
int addrEofA; /* Address of the select-A-exhausted subroutine */
|
||||
int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */
|
||||
int addrEofB; /* Address of the select-B-exhausted subroutine */
|
||||
int addrAltB; /* Address of the A<B subroutine */
|
||||
int addrAeqB; /* Address of the A==B subroutine */
|
||||
@@ -2624,24 +2656,7 @@ static int multiSelectOrderBy(
|
||||
&& pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
||||
aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
||||
}
|
||||
pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy, 1);
|
||||
if( pKeyMerge ){
|
||||
for(i=0; i<nOrderBy; i++){
|
||||
CollSeq *pColl;
|
||||
Expr *pTerm = pOrderBy->a[i].pExpr;
|
||||
if( pTerm->flags & EP_Collate ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pTerm);
|
||||
}else{
|
||||
pColl = multiSelectCollSeq(pParse, p, aPermute[i]);
|
||||
if( pColl==0 ) pColl = db->pDfltColl;
|
||||
pOrderBy->a[i].pExpr =
|
||||
sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
|
||||
}
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyMerge) );
|
||||
pKeyMerge->aColl[i] = pColl;
|
||||
pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
||||
}
|
||||
}
|
||||
pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
|
||||
}else{
|
||||
pKeyMerge = 0;
|
||||
}
|
||||
@@ -2698,37 +2713,30 @@ static int multiSelectOrderBy(
|
||||
p->pOffset = 0;
|
||||
|
||||
regAddrA = ++pParse->nMem;
|
||||
regEofA = ++pParse->nMem;
|
||||
regAddrB = ++pParse->nMem;
|
||||
regEofB = ++pParse->nMem;
|
||||
regOutA = ++pParse->nMem;
|
||||
regOutB = ++pParse->nMem;
|
||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
||||
|
||||
/* Jump past the various subroutines and coroutines to the main
|
||||
** merge loop
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement to the
|
||||
** left of the compound operator - the "A" select.
|
||||
*/
|
||||
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
|
||||
VdbeComment((v, "left SELECT"));
|
||||
pPrior->iLimit = regLimitA;
|
||||
explainSetInteger(iSub1, pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pPrior, &destA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
VdbeNoopComment((v, "End coroutine for left SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement on
|
||||
** the right - the "B" select
|
||||
*/
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v);
|
||||
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
|
||||
VdbeComment((v, "right SELECT"));
|
||||
savedLimit = p->iLimit;
|
||||
savedOffset = p->iOffset;
|
||||
p->iLimit = regLimitB;
|
||||
@@ -2737,9 +2745,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3Select(pParse, p, &destB);
|
||||
p->iLimit = savedLimit;
|
||||
p->iOffset = savedOffset;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "End coroutine for right SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
|
||||
|
||||
/* Generate a subroutine that outputs the current row of the A
|
||||
** select as the next output row of the compound select.
|
||||
@@ -2763,13 +2769,12 @@ static int multiSelectOrderBy(
|
||||
/* Generate a subroutine to run when the results from select A
|
||||
** are exhausted and only data in select B remains.
|
||||
*/
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
|
||||
addrEofA_noB = addrEofA = labelEnd;
|
||||
}else{
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
|
||||
p->nSelectRow += pPrior->nSelectRow;
|
||||
}
|
||||
@@ -2782,9 +2787,8 @@ static int multiSelectOrderBy(
|
||||
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
||||
}else{
|
||||
VdbeNoopComment((v, "eof-B subroutine"));
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
|
||||
}
|
||||
|
||||
@@ -2792,8 +2796,7 @@ static int multiSelectOrderBy(
|
||||
*/
|
||||
VdbeNoopComment((v, "A-lt-B subroutine"));
|
||||
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* Generate code to handle the case of A==B
|
||||
@@ -2806,8 +2809,7 @@ static int multiSelectOrderBy(
|
||||
}else{
|
||||
VdbeNoopComment((v, "A-eq-B subroutine"));
|
||||
addrAeqB =
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
}
|
||||
|
||||
@@ -2818,19 +2820,14 @@ static int multiSelectOrderBy(
|
||||
if( op==TK_ALL || op==TK_UNION ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* This code runs once to initialize everything.
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
|
||||
/* Implement the main merge loop
|
||||
*/
|
||||
@@ -4532,16 +4529,14 @@ int sqlite3Select(
|
||||
p->selFlags |= SF_Aggregate;
|
||||
}
|
||||
i = -1;
|
||||
}else if( pTabList->nSrc==1 && (p->selFlags & SF_Materialize)==0
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
}else if( pTabList->nSrc==1
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
*/
|
||||
int addrTop;
|
||||
int addrEof;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
addrEof = ++pParse->nMem;
|
||||
/* Before coding the OP_Goto to jump to the start of the main routine,
|
||||
** ensure that the jump to the verify-schema routine has already
|
||||
** been coded. Otherwise, the verify-schema would likely be coded as
|
||||
@@ -4554,10 +4549,8 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
|
||||
VdbeComment((v, "coroutine %s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
@@ -4565,9 +4558,7 @@ int sqlite3Select(
|
||||
pItem->viaCoroutine = 1;
|
||||
sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
|
||||
sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else{
|
||||
|
||||
+218
@@ -1543,6 +1543,7 @@ static int run_schema_dump_query(
|
||||
static char zHelp[] =
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
|
||||
".bail ON|OFF Stop after hitting an error. Default OFF\n"
|
||||
".clone NEWDB Clone data into NEWDB from the existing database\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
@@ -1896,6 +1897,219 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
return p->z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to transfer data for table zTable. If an error is seen while
|
||||
** moving forward, try to go backwards. The backwards movement won't
|
||||
** work for WITHOUT ROWID tables.
|
||||
*/
|
||||
static void tryToCloneData(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zTable
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
sqlite3_stmt *pInsert = 0;
|
||||
char *zQuery = 0;
|
||||
char *zInsert = 0;
|
||||
int rc;
|
||||
int i, j, n;
|
||||
int nTable = (int)strlen(zTable);
|
||||
int k = 0;
|
||||
int cnt = 0;
|
||||
const int spinRate = 10000;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
n = sqlite3_column_count(pQuery);
|
||||
zInsert = sqlite3_malloc(200 + nTable + n*3);
|
||||
if( zInsert==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
goto end_data_xfer;
|
||||
}
|
||||
sqlite3_snprintf(200+nTable,zInsert,
|
||||
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
|
||||
i = (int)strlen(zInsert);
|
||||
for(j=1; j<n; j++){
|
||||
memcpy(zInsert+i, ",?", 2);
|
||||
i += 2;
|
||||
}
|
||||
memcpy(zInsert+i, ");", 3);
|
||||
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
for(k=0; k<2; k++){
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
for(i=0; i<n; i++){
|
||||
switch( sqlite3_column_type(pQuery, i) ){
|
||||
case SQLITE_NULL: {
|
||||
sqlite3_bind_null(pInsert, i+1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
sqlite3_bind_text(pInsert, i+1,
|
||||
(const char*)sqlite3_column_text(pQuery,i),
|
||||
-1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
|
||||
sqlite3_column_bytes(pQuery,i),
|
||||
SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* End for */
|
||||
rc = sqlite3_step(pInsert);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
|
||||
fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
|
||||
sqlite3_errmsg(newDb));
|
||||
}
|
||||
sqlite3_reset(pInsert);
|
||||
cnt++;
|
||||
if( (cnt%spinRate)==0 ){
|
||||
printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
|
||||
fflush(stdout);
|
||||
}
|
||||
} /* End while */
|
||||
if( rc==SQLITE_DONE ) break;
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
|
||||
zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
|
||||
break;
|
||||
}
|
||||
} /* End for(k=0...) */
|
||||
|
||||
end_data_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_finalize(pInsert);
|
||||
sqlite3_free(zQuery);
|
||||
sqlite3_free(zInsert);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to transfer all rows of the schema that match zWhere. For
|
||||
** each row, invoke xForEach() on the object defined by that row.
|
||||
** If an error is encountered while moving forward through the
|
||||
** sqlite_master table, try again moving backwards.
|
||||
*/
|
||||
static void tryToCloneSchema(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zWhere,
|
||||
void (*xForEach)(struct callback_data*,sqlite3*,const char*)
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
char *zQuery = 0;
|
||||
int rc;
|
||||
const unsigned char *zName;
|
||||
const unsigned char *zSql;
|
||||
char *zErrMsg = 0;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s ORDER BY rowid DESC", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
}
|
||||
end_schema_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new database file named "zNewDb". Try to recover as much information
|
||||
** as possible out of the main database (which might be corrupt) and write it
|
||||
** into zNewDb.
|
||||
*/
|
||||
static void tryToClone(struct callback_data *p, const char *zNewDb){
|
||||
int rc;
|
||||
sqlite3 *newDb = 0;
|
||||
if( access(zNewDb,0)==0 ){
|
||||
fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_open(zNewDb, &newDb);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Cannot create output database: %s\n",
|
||||
sqlite3_errmsg(newDb));
|
||||
}else{
|
||||
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
|
||||
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
|
||||
tryToCloneSchema(p, newDb, "type!='table'", 0);
|
||||
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(newDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
@@ -2003,6 +2217,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
test_breakpoint();
|
||||
}else
|
||||
|
||||
if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
|
||||
tryToClone(p, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
|
||||
struct callback_data data;
|
||||
char *zErrMsg = 0;
|
||||
|
||||
+13
-8
@@ -1982,6 +1982,7 @@ typedef u64 Bitmask;
|
||||
** A bit in a Bitmask
|
||||
*/
|
||||
#define MASKBIT(n) (((Bitmask)1)<<(n))
|
||||
#define MASKBIT32(n) (((unsigned int)1)<<(n))
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
@@ -2160,7 +2161,7 @@ struct Select {
|
||||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
#define SF_Materialize 0x0100 /* Force materialization of views */
|
||||
#define SF_Materialize 0x0100 /* NOT USED */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
@@ -2357,22 +2358,23 @@ struct Parse {
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nOnce; /* Number of OP_Once instructions so far */
|
||||
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
|
||||
int nLabel; /* Number of labels used */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
|
||||
int ckBase; /* Base register of data during check constraints */
|
||||
int iPartIdxTab; /* Table corresponding to a partial index */
|
||||
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||
int nLabel; /* Number of labels used */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
struct yColCache {
|
||||
int iTable; /* Table cursor number */
|
||||
int iColumn; /* Table column number */
|
||||
i16 iColumn; /* Table column number */
|
||||
u8 tempReg; /* iReg is a temp register that needs to be freed */
|
||||
int iLevel; /* Nesting level */
|
||||
int iReg; /* Reg with value of this column. 0 means none. */
|
||||
int lru; /* Least recently used entry has the smallest value */
|
||||
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
|
||||
ExprList *pConstExpr;/* Constant expressions */
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
yDbMask writeMask; /* Start a write transaction on these databases */
|
||||
yDbMask cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
@@ -2380,7 +2382,6 @@ struct Parse {
|
||||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
int nMaxArg; /* Max args passed to user function by sub-program */
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
@@ -2399,12 +2400,17 @@ struct Parse {
|
||||
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
||||
u8 disableTriggers; /* True to disable triggers */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
/************************************************************************
|
||||
** Above is constant between recursions. Below is reset before and after
|
||||
** each recursion. The boundary between these two regions is determined
|
||||
** using offsetof(Parse,nVar) so the nVar field must be the first field
|
||||
** in the recursive region.
|
||||
************************************************************************/
|
||||
|
||||
int nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
int nzVar; /* Number of available slots in azVar[] */
|
||||
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
||||
u8 bFreeWith; /* True if pWith should be freed with parser */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
|
||||
@@ -2431,7 +2437,6 @@ struct Parse {
|
||||
Table *pZombieTab; /* List of Table objects to delete after code gen */
|
||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||
With *pWith; /* Current WITH clause, or NULL */
|
||||
u8 bFreeWith; /* True if pWith should be freed with parser */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+8
-8
@@ -873,7 +873,7 @@ static int auth_callback(
|
||||
const char *zArg3,
|
||||
const char *zArg4
|
||||
){
|
||||
char *zCode;
|
||||
const char *zCode;
|
||||
Tcl_DString str;
|
||||
int rc;
|
||||
const char *zReply;
|
||||
@@ -999,7 +999,7 @@ static int DbTransPostCmd(
|
||||
Tcl_Interp *interp, /* Tcl interpreter */
|
||||
int result /* Result of evaluating SCRIPT */
|
||||
){
|
||||
static const char *azEnd[] = {
|
||||
static const char *const azEnd[] = {
|
||||
"RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */
|
||||
"COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */
|
||||
"ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction",
|
||||
@@ -1937,7 +1937,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
Tcl_AppendResult(interp, pDb->zCommit, 0);
|
||||
}
|
||||
}else{
|
||||
char *zCommit;
|
||||
const char *zCommit;
|
||||
int len;
|
||||
if( pDb->zCommit ){
|
||||
Tcl_Free(pDb->zCommit);
|
||||
@@ -2010,14 +2010,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
char *zSql; /* An SQL statement */
|
||||
char *zLine; /* A single line of input from the file */
|
||||
char **azCol; /* zLine[] broken up into columns */
|
||||
char *zCommit; /* How to commit changes */
|
||||
const char *zCommit; /* How to commit changes */
|
||||
FILE *in; /* The input file */
|
||||
int lineno = 0; /* Line number of input file */
|
||||
char zLineNum[80]; /* Line number print buffer */
|
||||
Tcl_Obj *pResult; /* interp result */
|
||||
|
||||
char *zSep;
|
||||
char *zNull;
|
||||
const char *zSep;
|
||||
const char *zNull;
|
||||
if( objc<5 || objc>7 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv,
|
||||
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
||||
@@ -2935,7 +2935,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
Tcl_AppendResult(interp,sqlite3_version,0);
|
||||
Tcl_AppendResult(interp,sqlite3_libversion(),0);
|
||||
return TCL_OK;
|
||||
}
|
||||
if( strcmp(zArg,"-has-codec")==0 ){
|
||||
@@ -3017,7 +3017,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
zErrMsg = 0;
|
||||
p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
|
||||
if( p==0 ){
|
||||
Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
|
||||
Tcl_SetResult(interp, (char *)"malloc failed", TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
+23
-1
@@ -242,7 +242,28 @@ static int test_io_trace(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: clang_sanitize_address
|
||||
**
|
||||
** Returns true if the program was compiled using clang with the
|
||||
** -fsanitize=address switch on the command line. False otherwise.
|
||||
*/
|
||||
static int clang_sanitize_address(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
char **argv /* Text of each argument */
|
||||
){
|
||||
int res = 0;
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
res = 1;
|
||||
# endif
|
||||
#endif
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_exec_printf DB FORMAT STRING
|
||||
**
|
||||
@@ -6323,6 +6344,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
|
||||
{ "printf", (Tcl_CmdProc*)test_printf },
|
||||
{ "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace },
|
||||
{ "clang_sanitize_address", (Tcl_CmdProc*)clang_sanitize_address },
|
||||
};
|
||||
static struct {
|
||||
char *zName;
|
||||
|
||||
+1
-1
@@ -892,7 +892,7 @@ static int echoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
pIdxInfo->estimatedCost = cost;
|
||||
}else if( useIdx ){
|
||||
/* Approximation of log2(nRow). */
|
||||
for( ii=0; ii<(sizeof(int)*8); ii++ ){
|
||||
for( ii=0; ii<(sizeof(int)*8)-1; ii++ ){
|
||||
if( nRow & (1<<ii) ){
|
||||
pIdxInfo->estimatedCost = (double)ii;
|
||||
}
|
||||
|
||||
+3
-2
@@ -467,9 +467,10 @@ void sqlite3Update(
|
||||
);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( oldmask==0xffffffff
|
||||
|| (i<32 && (oldmask & (1<<i)))
|
||||
|| (i<32 && (oldmask & MASKBIT32(i))!=0)
|
||||
|| (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
|
||||
){
|
||||
testcase( oldmask!=0xffffffff && i==31 );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
|
||||
@@ -504,7 +505,7 @@ void sqlite3Update(
|
||||
j = aXRef[i];
|
||||
if( j>=0 ){
|
||||
sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
|
||||
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask&(1<<i)) ){
|
||||
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
|
||||
/* This branch loads the value of a column that will not be changed
|
||||
** into a register. This is done if there are no BEFORE triggers, or
|
||||
** if there are one or more BEFORE triggers that use this value via
|
||||
|
||||
+2
-1
@@ -1001,7 +1001,8 @@ int sqlite3VarintLen(u64 v){
|
||||
** Read or write a four-byte big-endian integer value.
|
||||
*/
|
||||
u32 sqlite3Get4byte(const u8 *p){
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
testcase( p[0]&0x80 );
|
||||
return ((unsigned)p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
void sqlite3Put4byte(unsigned char *p, u32 v){
|
||||
p[0] = (u8)(v>>24);
|
||||
|
||||
+153
-160
@@ -9,33 +9,8 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** The code in this file implements execution method of the
|
||||
** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c")
|
||||
** handles housekeeping details such as creating and deleting
|
||||
** VDBE instances. This file is solely interested in executing
|
||||
** the VDBE program.
|
||||
**
|
||||
** In the external interface, an "sqlite3_stmt*" is an opaque pointer
|
||||
** to a VDBE.
|
||||
**
|
||||
** The SQL parser generates a program which is then executed by
|
||||
** the VDBE to do the work of the SQL statement. VDBE programs are
|
||||
** similar in form to assembly language. The program consists of
|
||||
** a linear sequence of operations. Each operation has an opcode
|
||||
** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
|
||||
** is a null-terminated string. Operand P5 is an unsigned character.
|
||||
** Few opcodes use all 5 operands.
|
||||
**
|
||||
** Computation results are stored on a set of registers numbered beginning
|
||||
** with 1 and going up to Vdbe.nMem. Each register can store
|
||||
** either an integer, a null-terminated string, a floating point
|
||||
** number, or the SQL "NULL" value. An implicit conversion from one
|
||||
** type to the other occurs as necessary.
|
||||
**
|
||||
** Most of the code in this file is taken up by the sqlite3VdbeExec()
|
||||
** function which does the work of interpreting a VDBE program.
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
** The code in this file implements the function that runs the
|
||||
** bytecode of a prepared statement.
|
||||
**
|
||||
** Various scripts scan this source file in order to generate HTML
|
||||
** documentation, headers files, or other derived files. The formatting
|
||||
@@ -49,7 +24,11 @@
|
||||
/*
|
||||
** Invoke this macro on memory cells just prior to changing the
|
||||
** value of the cell. This macro verifies that shallow copies are
|
||||
** not misused.
|
||||
** not misused. A shallow copy of a string or blob just copies a
|
||||
** pointer to the string or blob, not the content. If the original
|
||||
** is changed while the copy is still in use, the string or blob might
|
||||
** be changed out from under the copy. This macro verifies that nothing
|
||||
** like that every happens.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M)
|
||||
@@ -108,7 +87,7 @@ static void updateMaxBlobsize(Mem *p){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The next global variable is incremented each type the OP_Found opcode
|
||||
** The next global variable is incremented each time the OP_Found opcode
|
||||
** is executed. This is used to test whether or not the foreign key
|
||||
** operation implemented using OP_FkIsZero is working. This variable
|
||||
** has no function other than to help verify the correct operation of the
|
||||
@@ -152,7 +131,7 @@ int sqlite3_found_count = 0;
|
||||
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
|
||||
|
||||
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
|
||||
# define isSorter(x) ((x)->pSorter!=0)
|
||||
#define isSorter(x) ((x)->pSorter!=0)
|
||||
|
||||
/*
|
||||
** Argument pMem points at a register that will be passed to a
|
||||
@@ -414,7 +393,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
** Print the value of a register for tracing purposes:
|
||||
*/
|
||||
static void memTracePrint(Mem *p){
|
||||
if( p->flags & MEM_Invalid ){
|
||||
if( p->flags & MEM_Undefined ){
|
||||
printf(" undefined");
|
||||
}else if( p->flags & MEM_Null ){
|
||||
printf(" NULL");
|
||||
@@ -458,20 +437,6 @@ static void registerTrace(int iReg, Mem *p){
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The CHECK_FOR_INTERRUPT macro defined here looks to see if the
|
||||
** sqlite3_interrupt() routine has been called. If it has been, then
|
||||
** processing of the VDBE program is interrupted.
|
||||
**
|
||||
** This macro added to every instruction that does a jump in order to
|
||||
** implement a loop. This test used to be on every single instruction,
|
||||
** but that meant we more testing than we needed. By only testing the
|
||||
** flag on jump instructions, we get a (small) speed improvement.
|
||||
*/
|
||||
#define CHECK_FOR_INTERRUPT \
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** This function is only called from within an assert() expression. It
|
||||
@@ -494,35 +459,8 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can then return.
|
||||
**
|
||||
** sqlite3VdbeMakeReady() must be called before this routine in order to
|
||||
** close the program with a final OP_Halt and to set up the callbacks
|
||||
** and the error message pointer.
|
||||
**
|
||||
** Whenever a row or result data is available, this routine will either
|
||||
** invoke the result callback (if there is one) or return with
|
||||
** SQLITE_ROW.
|
||||
**
|
||||
** If an attempt is made to open a locked database, then this routine
|
||||
** will either invoke the busy callback (if there is one) or it will
|
||||
** return SQLITE_BUSY.
|
||||
**
|
||||
** If an error occurs, an error message is written to memory obtained
|
||||
** from sqlite3_malloc() and p->zErrMsg is made to point to that memory.
|
||||
** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
|
||||
**
|
||||
** If the callback ever returns non-zero, then the program exits
|
||||
** immediately. There will be no error message but the p->rc field is
|
||||
** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
|
||||
**
|
||||
** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
|
||||
** routine to return SQLITE_ERROR.
|
||||
**
|
||||
** Other fatal errors return SQLITE_ERROR.
|
||||
**
|
||||
** After this routine has finished, sqlite3VdbeFinalize() should be
|
||||
** used to clean up the mess that was left behind.
|
||||
** Execute as much of a VDBE program as we can.
|
||||
** This is the core of sqlite3_step().
|
||||
*/
|
||||
int sqlite3VdbeExec(
|
||||
Vdbe *p /* The VDBE */
|
||||
@@ -566,7 +504,7 @@ int sqlite3VdbeExec(
|
||||
assert( p->explain==0 );
|
||||
p->pResultSet = 0;
|
||||
db->busyHandler.nBusy = 0;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
sqlite3VdbeIOTraceSql(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
@@ -742,7 +680,7 @@ case OP_Goto: { /* jump */
|
||||
** checks on every opcode. This helps sqlite3_step() to run about 1.5%
|
||||
** faster according to "valgrind --tool=cachegrind" */
|
||||
check_for_interrupt:
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Call the progress callback if it is configured and the required number
|
||||
** of VDBE ops have been executed (either since this invocation of
|
||||
@@ -782,20 +720,66 @@ case OP_Gosub: { /* jump */
|
||||
|
||||
/* Opcode: Return P1 * * * *
|
||||
**
|
||||
** Jump to the next instruction after the address in register P1.
|
||||
** Jump to the next instruction after the address in register P1. After
|
||||
** the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_Return: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags & MEM_Int );
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
pc = (int)pIn1->u.i;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 * * * *
|
||||
/* Opcode: InitCoroutine P1 P2 P3 * *
|
||||
**
|
||||
** Set up register P1 so that it will OP_Yield to the co-routine
|
||||
** located at address P3.
|
||||
**
|
||||
** If P2!=0 then the co-routine implementation immediately follows
|
||||
** this opcode. So jump over the co-routine implementation to
|
||||
** address P2.
|
||||
*/
|
||||
case OP_InitCoroutine: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2>=0 && pOp->p2<p->nOp );
|
||||
assert( pOp->p3>=0 && pOp->p3<p->nOp );
|
||||
pOut = &aMem[pOp->p1];
|
||||
assert( !VdbeMemDynamic(pOut) );
|
||||
pOut->u.i = pOp->p3 - 1;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->p2 ) pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: EndCoroutine P1 * * * *
|
||||
**
|
||||
** The instruction at the address in register P1 is an OP_Yield.
|
||||
** Jump to the P2 parameter of that OP_Yield.
|
||||
** After the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_EndCoroutine: { /* in1 */
|
||||
VdbeOp *pCaller;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp );
|
||||
pCaller = &aOp[pIn1->u.i];
|
||||
assert( pCaller->opcode==OP_Yield );
|
||||
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
|
||||
pc = pCaller->p2 - 1;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 P2 * * *
|
||||
**
|
||||
** Swap the program counter with the value in register P1.
|
||||
**
|
||||
** If the co-routine ends with OP_Yield or OP_Return then continue
|
||||
** to the next instruction. But if the co-routine ends with
|
||||
** OP_EndCoroutine, jump immediately to P2.
|
||||
*/
|
||||
case OP_Yield: { /* in1 */
|
||||
case OP_Yield: { /* in1, jump */
|
||||
int pcDest;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
@@ -808,7 +792,7 @@ case OP_Yield: { /* in1 */
|
||||
}
|
||||
|
||||
/* Opcode: HaltIfNull P1 P2 P3 P4 P5
|
||||
** Synopsis: if r[P3] null then halt
|
||||
** Synopsis: if r[P3]=null halt
|
||||
**
|
||||
** Check the value in register P3. If it is NULL then Halt using
|
||||
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
|
||||
@@ -956,7 +940,9 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
** Synopsis: r[P2]='P4'
|
||||
**
|
||||
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
||||
** into an OP_String before it is executed for the first time.
|
||||
** into an OP_String before it is executed for the first time. During
|
||||
** this transformation, the length of string P4 is computed and stored
|
||||
** as the P1 parameter.
|
||||
*/
|
||||
case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
assert( pOp->p4.z!=0 );
|
||||
@@ -1031,7 +1017,7 @@ case OP_Null: { /* out2-prerelease */
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: Blob P1 P2 * P4
|
||||
/* Opcode: Blob P1 P2 * P4 *
|
||||
** Synopsis: r[P2]=P4 (len=P1)
|
||||
**
|
||||
** P4 points to a blob of data P1 bytes long. Store this
|
||||
@@ -1050,7 +1036,7 @@ case OP_Blob: { /* out2-prerelease */
|
||||
**
|
||||
** Transfer the values of bound parameter P1 into register P2
|
||||
**
|
||||
** If the parameter is named, then its name appears in P4 and P3==1.
|
||||
** If the parameter is named, then its name appears in P4.
|
||||
** The P4 value is used by sqlite3_bind_parameter_name().
|
||||
*/
|
||||
case OP_Variable: { /* out2-prerelease */
|
||||
@@ -1169,8 +1155,8 @@ case OP_SCopy: { /* out2 */
|
||||
** The registers P1 through P1+P2-1 contain a single row of
|
||||
** results. This opcode causes the sqlite3_step() call to terminate
|
||||
** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
|
||||
** structure to provide access to the top P1 values as the result
|
||||
** row.
|
||||
** structure to provide access to the r[P1]..r[P1+P2-1] values as
|
||||
** the result row.
|
||||
*/
|
||||
case OP_ResultRow: {
|
||||
Mem *pMem;
|
||||
@@ -1698,7 +1684,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
**
|
||||
** Force the value in register P1 to be text.
|
||||
** If the value is numeric, convert it to a string using the
|
||||
** equivalent of printf(). Blob values are unchanged and
|
||||
** equivalent of sprintf(). Blob values are unchanged and
|
||||
** are afterwards simply interpreted as text.
|
||||
**
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
@@ -2153,7 +2139,9 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
** set the flag and fall through to the next instruction. In other words,
|
||||
** this opcode causes all following up codes up through P2 (but not including
|
||||
** P2) to run just once and skipped on subsequent times through the loop.
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
@@ -2946,7 +2934,7 @@ case OP_AutoCommit: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transaction P1 P2 * * *
|
||||
/* Opcode: Transaction P1 P2 P3 P4 P5
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
@@ -2976,9 +2964,17 @@ case OP_AutoCommit: {
|
||||
** will automatically commit when the VDBE halts.
|
||||
**
|
||||
** If P2 is zero, then a read-lock is obtained on the database file.
|
||||
**
|
||||
** If P5!=0 then this opcode also checks the schema cookie against P3
|
||||
** and the schema generation counter against P4.
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
Btree *pBt;
|
||||
int iMeta;
|
||||
int iGen;
|
||||
|
||||
assert( p->bIsReader );
|
||||
assert( p->readOnly==0 || pOp->p2==0 );
|
||||
@@ -3022,6 +3018,35 @@ case OP_Transaction: {
|
||||
p->nStmtDefCons = db->nDeferredCons;
|
||||
p->nStmtDefImmCons = db->nDeferredImmCons;
|
||||
}
|
||||
|
||||
/* Gather the schema version number for checking */
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
|
||||
if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3096,66 +3121,6 @@ case OP_SetCookie: { /* in3 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: VerifyCookie P1 P2 P3 * *
|
||||
**
|
||||
** Check the value of global database parameter number 0 (the
|
||||
** schema version) and make sure it is equal to P2 and that the
|
||||
** generation counter on the local schema parse equals P3.
|
||||
**
|
||||
** P1 is the database number which is 0 for the main database file
|
||||
** and 1 for the file holding temporary tables and some higher number
|
||||
** for auxiliary databases.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
**
|
||||
** Either a transaction needs to have been started or an OP_Open needs
|
||||
** to be executed (to establish a read lock) before this opcode is
|
||||
** invoked.
|
||||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int iMeta;
|
||||
int iGen;
|
||||
Btree *pBt;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
|
||||
assert( p->bIsReader );
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenRead P1 P2 P3 P4 P5
|
||||
** Synopsis: root=P2 iDb=P3
|
||||
**
|
||||
@@ -3369,7 +3334,7 @@ case OP_OpenEphemeral: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SorterOpen P1 * * P4 *
|
||||
/* Opcode: SorterOpen P1 P2 * P4 *
|
||||
**
|
||||
** This opcode works like OP_OpenEphemeral except that it opens
|
||||
** a transient index that is specifically designed to sort large
|
||||
@@ -3599,6 +3564,7 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
#endif
|
||||
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
||||
if( res<0 || (res==0 && oc==OP_SeekGt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
@@ -3608,6 +3574,7 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
}else{
|
||||
assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
||||
if( res>0 || (res==0 && oc==OP_SeekLt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
@@ -4234,7 +4201,7 @@ case OP_SorterData: {
|
||||
**
|
||||
** Write into register P2 the complete row key for cursor P1.
|
||||
** There is no interpretation of the data.
|
||||
** The key is copied onto the P3 register exactly as
|
||||
** The key is copied onto the P2 register exactly as
|
||||
** it is found in the database file.
|
||||
**
|
||||
** If the P1 cursor must be pointing to a valid row (not a NULL row)
|
||||
@@ -4460,7 +4427,7 @@ case OP_Rewind: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 * * P5
|
||||
/* Opcode: Next P1 P2 P3 P4 P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
@@ -4470,6 +4437,11 @@ case OP_Rewind: { /* jump */
|
||||
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
|
||||
** been opened prior to this opcode or the program will segfault.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreeNext().
|
||||
**
|
||||
@@ -4478,12 +4450,12 @@ case OP_Rewind: { /* jump */
|
||||
**
|
||||
** See also: Prev, NextIfOpen
|
||||
*/
|
||||
/* Opcode: NextIfOpen P1 P2 * * P5
|
||||
/* Opcode: NextIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Next except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
*/
|
||||
/* Opcode: Prev P1 P2 * * P5
|
||||
/* Opcode: Prev P1 P2 P3 P4 P5
|
||||
**
|
||||
** Back up cursor P1 so that it points to the previous key/data pair in its
|
||||
** table or index. If there is no previous key/value pairs then fall through
|
||||
@@ -4493,13 +4465,18 @@ case OP_Rewind: { /* jump */
|
||||
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
|
||||
** not open then the behavior is undefined.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreePrevious().
|
||||
**
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
*/
|
||||
/* Opcode: PrevIfOpen P1 P2 * * P5
|
||||
/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Prev except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
@@ -4521,9 +4498,12 @@ case OP_Next: /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<ArraySize(p->aCounter) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
res = pOp->p3;
|
||||
assert( pC!=0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( res==0 || (res==1 && pC->isTable==0) );
|
||||
testcase( res==1 );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
||||
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
@@ -4555,6 +4535,14 @@ next_tail:
|
||||
** P3 is a flag that provides a hint to the b-tree layer that this
|
||||
** insert is likely to be an append.
|
||||
**
|
||||
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
|
||||
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
|
||||
** then the change counter is unchanged.
|
||||
**
|
||||
** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
|
||||
** just done a seek to the spot where the new entry is to be inserted.
|
||||
** This flag avoids doing an extra seek.
|
||||
**
|
||||
** This instruction only works for indices. The equivalent instruction
|
||||
** for tables is OP_Insert.
|
||||
*/
|
||||
@@ -5155,7 +5143,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
||||
/* Opcode: Program P1 P2 P3 P4 *
|
||||
/* Opcode: Program P1 P2 P3 P4 P5
|
||||
**
|
||||
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
||||
**
|
||||
@@ -5167,6 +5155,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
** memory required by the sub-vdbe at runtime.
|
||||
**
|
||||
** P4 is a pointer to the VM containing the trigger program.
|
||||
**
|
||||
** If P5 is non-zero, then recursive program invocation is enabled.
|
||||
*/
|
||||
case OP_Program: { /* jump */
|
||||
int nMem; /* Number of memory registers for sub-program */
|
||||
@@ -5244,7 +5234,7 @@ case OP_Program: { /* jump */
|
||||
|
||||
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
|
||||
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
|
||||
pMem->flags = MEM_Invalid;
|
||||
pMem->flags = MEM_Undefined;
|
||||
pMem->db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -5554,7 +5544,7 @@ case OP_Checkpoint: {
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_PRAGMA
|
||||
/* Opcode: JournalMode P1 P2 P3 * P5
|
||||
/* Opcode: JournalMode P1 P2 P3 * *
|
||||
**
|
||||
** Change the journal mode of database P1 to P3. P3 must be one of the
|
||||
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
|
||||
@@ -6040,7 +6030,7 @@ case OP_VRename: {
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 *
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 P5
|
||||
** Synopsis: data=r[P3@P2]
|
||||
**
|
||||
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
|
||||
@@ -6063,6 +6053,9 @@ case OP_VRename: {
|
||||
** P1 is a boolean flag. If it is set to true and the xUpdate call
|
||||
** is successful, then the value returned by sqlite3_last_insert_rowid()
|
||||
** is set to the value of the rowid for the row just inserted.
|
||||
**
|
||||
** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
|
||||
** apply in the case of a constraint failure on an insert or update.
|
||||
*/
|
||||
case OP_VUpdate: {
|
||||
sqlite3_vtab *pVtab;
|
||||
@@ -6174,7 +6167,7 @@ case OP_Trace: {
|
||||
if( zTrace ){
|
||||
int i;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
if( ((1<<i) & p->btreeMask)==0 ) continue;
|
||||
if( MASKBIT(i) & p->btreeMask)==0 ) continue;
|
||||
sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -198,7 +198,7 @@ struct Mem {
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
#define MEM_Invalid 0x0080 /* Value is undefined */
|
||||
#define MEM_Undefined 0x0080 /* Value is undefined */
|
||||
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
|
||||
#define MEM_TypeMask 0x01ff /* Mask of type bits */
|
||||
|
||||
@@ -230,7 +230,7 @@ struct Mem {
|
||||
** is for use inside assert() statements only.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -425,9 +425,10 @@ int sqlite3VdbeMemNumerify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p);
|
||||
#define VdbeMemDynamic(X) \
|
||||
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
|
||||
#define VdbeMemRelease(X) \
|
||||
if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
|
||||
sqlite3VdbeMemReleaseExternal(X);
|
||||
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
const char *sqlite3OpcodeName(int);
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
|
||||
+18
-14
@@ -1234,7 +1234,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
p->zMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Invalid;
|
||||
p->flags = MEM_Undefined;
|
||||
}
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
@@ -1702,7 +1702,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Invalid;
|
||||
p->aMem[n].flags = MEM_Undefined;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
@@ -1814,7 +1814,7 @@ static void Cleanup(Vdbe *p){
|
||||
int i;
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2615,8 +2615,9 @@ void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
|
||||
while( *pp ){
|
||||
AuxData *pAux = *pp;
|
||||
if( (iOp<0)
|
||||
|| (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & ((u32)1<<pAux->iArg))))
|
||||
|| (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
|
||||
){
|
||||
testcase( pAux->iArg==31 );
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
}
|
||||
@@ -2931,6 +2932,9 @@ u32 sqlite3VdbeSerialGet(
|
||||
u32 serial_type, /* Serial type to deserialize */
|
||||
Mem *pMem /* Memory cell to write value into */
|
||||
){
|
||||
u64 x;
|
||||
u32 y;
|
||||
int i;
|
||||
switch( serial_type ){
|
||||
case 10: /* Reserved for future use */
|
||||
case 11: /* Reserved for future use */
|
||||
@@ -2944,23 +2948,26 @@ u32 sqlite3VdbeSerialGet(
|
||||
return 1;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
pMem->u.i = (((signed char)buf[0])<<8) | buf[1];
|
||||
i = 256*(signed char)buf[0] | buf[1];
|
||||
pMem->u.i = (i64)i;
|
||||
pMem->flags = MEM_Int;
|
||||
return 2;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
pMem->u.i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
|
||||
i = 65536*(signed char)buf[0] | (buf[1]<<8) | buf[2];
|
||||
pMem->u.i = (i64)i;
|
||||
pMem->flags = MEM_Int;
|
||||
return 3;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
pMem->u.i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
pMem->u.i = (i64)*(int*)&y;
|
||||
pMem->flags = MEM_Int;
|
||||
return 4;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
u64 x = (((signed char)buf[0])<<8) | buf[1];
|
||||
u32 y = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
|
||||
x = 256*(signed char)buf[0] + buf[1];
|
||||
y = ((unsigned)buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
|
||||
x = (x<<32) | y;
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
@@ -2968,8 +2975,6 @@ u32 sqlite3VdbeSerialGet(
|
||||
}
|
||||
case 6: /* 8-byte signed integer */
|
||||
case 7: { /* IEEE floating point */
|
||||
u64 x;
|
||||
u32 y;
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
/* Verify that integers and floating point values use the same
|
||||
** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
|
||||
@@ -2982,9 +2987,8 @@ u32 sqlite3VdbeSerialGet(
|
||||
swapMixedEndianFloat(t2);
|
||||
assert( sizeof(r1)==sizeof(t2) && memcmp(&r1, &t2, sizeof(r1))==0 );
|
||||
#endif
|
||||
|
||||
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||
x = ((unsigned)buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||
y = ((unsigned)buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||
x = (x<<32) | y;
|
||||
if( serial_type==6 ){
|
||||
pMem->u.i = *(i64*)&x;
|
||||
|
||||
+26
-32
@@ -134,21 +134,20 @@ int sqlite3_blob_open(
|
||||
** transaction.
|
||||
*/
|
||||
static const VdbeOpList openBlob[] = {
|
||||
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
|
||||
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
|
||||
{OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
|
||||
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
|
||||
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
|
||||
|
||||
/* One of the following two instructions is replaced by an OP_Noop. */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Goto, 0, 5, 0}, /* 9 */
|
||||
{OP_Close, 0, 0, 0}, /* 10 */
|
||||
{OP_Halt, 0, 0, 0}, /* 11 */
|
||||
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 6 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 7 */
|
||||
{OP_Goto, 0, 4, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
};
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
@@ -261,36 +260,31 @@ int sqlite3_blob_open(
|
||||
Vdbe *v = (Vdbe *)pBlob->pStmt;
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
|
||||
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
|
||||
pTab->pSchema->schema_cookie,
|
||||
pTab->pSchema->iGeneration);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
|
||||
|
||||
/* Configure the OP_Transaction */
|
||||
sqlite3VdbeChangeP1(v, 0, iDb);
|
||||
sqlite3VdbeChangeP2(v, 0, flags);
|
||||
|
||||
/* Configure the OP_VerifyCookie */
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
|
||||
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the OP_TableLock instruction */
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3VdbeChangeToNoop(v, 2);
|
||||
sqlite3VdbeChangeToNoop(v, 1);
|
||||
#else
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2, flags);
|
||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 1, flags);
|
||||
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
|
||||
#endif
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum. */
|
||||
sqlite3VdbeChangeToNoop(v, 4 - flags);
|
||||
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
|
||||
sqlite3VdbeChangeToNoop(v, 3 - flags);
|
||||
sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2 + flags, iDb);
|
||||
|
||||
/* Configure the number of columns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
@@ -299,8 +293,8 @@ int sqlite3_blob_open(
|
||||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
|
||||
sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
|
||||
if( !db->mallocFailed ){
|
||||
pParse->nVar = 1;
|
||||
pParse->nMem = 1;
|
||||
|
||||
+2
-2
@@ -587,7 +587,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
Mem *pX;
|
||||
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
|
||||
if( pX->pScopyFrom==pMem ){
|
||||
pX->flags |= MEM_Invalid;
|
||||
pX->flags |= MEM_Undefined;
|
||||
pX->pScopyFrom = 0;
|
||||
}
|
||||
}
|
||||
@@ -598,7 +598,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
/*
|
||||
** Size of struct Mem not including the Mem.zMalloc member.
|
||||
*/
|
||||
#define MEMCELLSIZE (size_t)(&(((Mem *)0)->zMalloc))
|
||||
#define MEMCELLSIZE offsetof(Mem,zMalloc)
|
||||
|
||||
/*
|
||||
** Make an shallow copy of pFrom into pTo. Prior contents of
|
||||
|
||||
+11
-9
@@ -2785,10 +2785,9 @@ static Bitmask codeOneLoopStart(
|
||||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
if( pTabItem->viaCoroutine ){
|
||||
int regYield = pTabItem->regReturn;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
|
||||
pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
|
||||
VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
|
||||
pLevel->op = OP_Goto;
|
||||
}else
|
||||
|
||||
@@ -3184,6 +3183,8 @@ static Bitmask codeOneLoopStart(
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
pLevel->p1 = iIdxCur;
|
||||
assert( (WHERE_UNQ_WANTED>>16)==1 );
|
||||
pLevel->p3 = (pLoop->wsFlags>>16)&1;
|
||||
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
}else{
|
||||
@@ -3986,12 +3987,13 @@ static int whereLoopAddBtreeIndex(
|
||||
|| nInMul==0
|
||||
);
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
if( iCol<0
|
||||
|| (pProbe->onError!=OE_None && nInMul==0
|
||||
&& pNew->u.btree.nEq==pProbe->nKeyCol-1)
|
||||
){
|
||||
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){
|
||||
assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 );
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
if( iCol>=0 && pProbe->onError==OE_None ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
}
|
||||
}
|
||||
pNew->u.btree.nEq++;
|
||||
pNew->nOut = nRowEst + nInMul;
|
||||
@@ -5785,7 +5787,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
pLoop = pLevel->pWLoop;
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
|
||||
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
||||
sqlite3VdbeChangeP5(v, pLevel->p5);
|
||||
}
|
||||
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
||||
|
||||
+2
-1
@@ -70,7 +70,7 @@ struct WhereLevel {
|
||||
int addrFirst; /* First instruction of interior of the loop */
|
||||
int addrBody; /* Beginning of the body of this loop */
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
|
||||
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to ends the loop */
|
||||
union { /* Information that depends on pWLoop->wsFlags */
|
||||
struct {
|
||||
@@ -457,3 +457,4 @@ struct WhereInfo {
|
||||
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
|
||||
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
||||
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
||||
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
||||
|
||||
+24
-18
@@ -179,16 +179,18 @@ do_test capi3-3.4 {
|
||||
do_test capi3-3.5 {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_OK}
|
||||
do_test capi3-3.6.1-misuse {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_MISUSE}
|
||||
do_test capi3-3.6.2-misuse {
|
||||
sqlite3_errmsg $db2
|
||||
} {library routine called out of sequence}
|
||||
ifcapable {utf16} {
|
||||
do_test capi3-3.6.3-misuse {
|
||||
utf8 [sqlite3_errmsg16 $db2]
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3-3.6.1-misuse {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_MISUSE}
|
||||
do_test capi3-3.6.2-misuse {
|
||||
sqlite3_errmsg $db2
|
||||
} {library routine called out of sequence}
|
||||
ifcapable {utf16} {
|
||||
do_test capi3-3.6.3-misuse {
|
||||
utf8 [sqlite3_errmsg16 $db2]
|
||||
} {library routine called out of sequence}
|
||||
}
|
||||
}
|
||||
|
||||
do_test capi3-3.7 {
|
||||
@@ -661,10 +663,12 @@ do_test capi3-6.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test capi3-6.4-misuse {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_OK}
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3-6.4-misuse {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_OK}
|
||||
}
|
||||
db close
|
||||
|
||||
# This procedure sets the value of the file-format in file 'test.db'
|
||||
@@ -1060,11 +1064,13 @@ if {[llength [info commands sqlite3_sleep]]>0} {
|
||||
}
|
||||
|
||||
# Ticket #1219: Make sure binding APIs can handle a NULL pointer.
|
||||
#
|
||||
do_test capi3-14.1-misuse {
|
||||
set rc [catch {sqlite3_bind_text 0 1 hello 5} msg]
|
||||
lappend rc $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
#
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3-14.1-misuse {
|
||||
set rc [catch {sqlite3_bind_text 0 1 hello 5} msg]
|
||||
lappend rc $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
}
|
||||
|
||||
# Ticket #1650: Honor the nBytes parameter to sqlite3_prepare.
|
||||
#
|
||||
|
||||
+21
-15
@@ -169,16 +169,18 @@ do_test capi3c-3.4 {
|
||||
do_test capi3c-3.5 {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_OK}
|
||||
do_test capi3c-3.6.1-misuse {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_MISUSE}
|
||||
do_test capi3c-3.6.2-misuse {
|
||||
sqlite3_errmsg $db2
|
||||
} {library routine called out of sequence}
|
||||
ifcapable {utf16} {
|
||||
do_test capi3c-3.6.3-misuse {
|
||||
utf8 [sqlite3_errmsg16 $db2]
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3c-3.6.1-misuse {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_MISUSE}
|
||||
do_test capi3c-3.6.2-misuse {
|
||||
sqlite3_errmsg $db2
|
||||
} {library routine called out of sequence}
|
||||
ifcapable {utf16} {
|
||||
do_test capi3c-3.6.3-misuse {
|
||||
utf8 [sqlite3_errmsg16 $db2]
|
||||
} {library routine called out of sequence}
|
||||
}
|
||||
}
|
||||
|
||||
# rename sqlite3_open ""
|
||||
@@ -627,13 +629,17 @@ check_data $STMT capi3c-6.3 {INTEGER} {1} {1.0} {1}
|
||||
do_test capi3c-6.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
do_test capi3c-6.4 {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_OK}
|
||||
do_test capi3c-6.99-misuse {
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test capi3c-6.4 {
|
||||
db cache flush
|
||||
sqlite3_close $DB
|
||||
} {SQLITE_OK}
|
||||
do_test capi3c-6.99-misuse {
|
||||
db close
|
||||
} {}
|
||||
} else {
|
||||
db close
|
||||
} {}
|
||||
}
|
||||
|
||||
# This procedure sets the value of the file-format in file 'test.db'
|
||||
# to $newval. Also, the schema cookie is incremented.
|
||||
|
||||
+75
-25
@@ -15,51 +15,68 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix closure01
|
||||
|
||||
ifcapable !vtab { finish_test ; return }
|
||||
ifcapable !vtab||!cte { finish_test ; return }
|
||||
|
||||
load_static_extension db closure
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
BEGIN;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y INTEGER);
|
||||
WITH RECURSIVE
|
||||
cnt(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM cnt LIMIT 131072)
|
||||
INSERT INTO t1(x, y) SELECT i, nullif(i,1)/2 FROM cnt;
|
||||
CREATE INDEX t1y ON t1(y);
|
||||
INSERT INTO t1(x) VALUES(1),(2);
|
||||
INSERT INTO t1(x) SELECT x+2 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+4 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+8 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+16 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+32 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+64 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+128 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+256 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+512 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+1024 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+2048 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+4096 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+8192 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+16384 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+32768 FROM t1;
|
||||
INSERT INTO t1(x) SELECT x+65536 FROM t1;
|
||||
UPDATE t1 SET y=x/2 WHERE x>1;
|
||||
COMMIT;
|
||||
CREATE VIRTUAL TABLE cx
|
||||
USING transitive_closure(tablename=t1, idcolumn=x, parentcolumn=y);
|
||||
} {}
|
||||
|
||||
# The entire table
|
||||
do_execsql_test 1.1 {
|
||||
do_timed_execsql_test 1.1 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 GROUP BY depth ORDER BY 1;
|
||||
} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/}
|
||||
do_timed_execsql_test 1.1-cte {
|
||||
WITH RECURSIVE
|
||||
below(id,depth) AS (
|
||||
VALUES(1,0)
|
||||
UNION ALL
|
||||
SELECT t1.x, below.depth+1
|
||||
FROM t1 JOIN below on t1.y=below.id
|
||||
)
|
||||
SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1;
|
||||
} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/}
|
||||
|
||||
# descendents of 32768
|
||||
do_execsql_test 1.2 {
|
||||
do_timed_execsql_test 1.2 {
|
||||
SELECT * FROM cx WHERE root=32768 ORDER BY id;
|
||||
} {32768 0 65536 1 65537 1 131072 2}
|
||||
do_timed_execsql_test 1.2-cte {
|
||||
WITH RECURSIVE
|
||||
below(id,depth) AS (
|
||||
VALUES(32768,0)
|
||||
UNION ALL
|
||||
SELECT t1.x, below.depth+1
|
||||
FROM t1 JOIN below on t1.y=below.id
|
||||
WHERE below.depth<2
|
||||
)
|
||||
SELECT id, depth FROM below ORDER BY id;
|
||||
} {32768 0 65536 1 65537 1 131072 2}
|
||||
|
||||
# descendents of 16384
|
||||
do_execsql_test 1.3 {
|
||||
do_timed_execsql_test 1.3 {
|
||||
SELECT * FROM cx WHERE root=16384 AND depth<=2 ORDER BY id;
|
||||
} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2}
|
||||
do_timed_execsql_test 1.3-cte {
|
||||
WITH RECURSIVE
|
||||
below(id,depth) AS (
|
||||
VALUES(16384,0)
|
||||
UNION ALL
|
||||
SELECT t1.x, below.depth+1
|
||||
FROM t1 JOIN below on t1.y=below.id
|
||||
WHERE below.depth<2
|
||||
)
|
||||
SELECT id, depth FROM below ORDER BY id;
|
||||
} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2}
|
||||
|
||||
# children of 16384
|
||||
do_execsql_test 1.4 {
|
||||
@@ -70,19 +87,41 @@ do_execsql_test 1.4 {
|
||||
} {32768 1 {} t1 x y 32769 1 {} t1 x y}
|
||||
|
||||
# great-grandparent of 16384
|
||||
do_execsql_test 1.5 {
|
||||
do_timed_execsql_test 1.5 {
|
||||
SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx
|
||||
WHERE root=16384
|
||||
AND depth=3
|
||||
AND idcolumn='Y'
|
||||
AND parentcolumn='X';
|
||||
} {2048 3 {} t1 Y X}
|
||||
do_timed_execsql_test 1.5-cte {
|
||||
WITH RECURSIVE
|
||||
above(id,depth) AS (
|
||||
VALUES(16384,0)
|
||||
UNION ALL
|
||||
SELECT t1.y, above.depth+1
|
||||
FROM t1 JOIN above ON t1.x=above.id
|
||||
WHERE above.depth<3
|
||||
)
|
||||
SELECT id FROM above WHERE depth=3;
|
||||
} {2048}
|
||||
|
||||
# depth<5
|
||||
do_execsql_test 1.6 {
|
||||
do_timed_execsql_test 1.6 {
|
||||
SELECT count(*), depth FROM cx WHERE root=1 AND depth<5
|
||||
GROUP BY depth ORDER BY 1;
|
||||
} {1 0 2 1 4 2 8 3 16 4}
|
||||
do_timed_execsql_test 1.6-cte {
|
||||
WITH RECURSIVE
|
||||
below(id,depth) AS (
|
||||
VALUES(1,0)
|
||||
UNION ALL
|
||||
SELECT t1.x, below.depth+1
|
||||
FROM t1 JOIN below ON t1.y=below.id
|
||||
WHERE below.depth<4
|
||||
)
|
||||
SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1;
|
||||
} {1 0 2 1 4 2 8 3 16 4}
|
||||
|
||||
# depth<=5
|
||||
do_execsql_test 1.7 {
|
||||
@@ -103,9 +142,20 @@ do_execsql_test 1.9 {
|
||||
} {8 3 16 4 32 5}
|
||||
|
||||
# depth==5 with min() and max()
|
||||
do_execsql_test 1.10 {
|
||||
do_timed_execsql_test 1.10 {
|
||||
SELECT count(*), min(id), max(id) FROM cx WHERE root=1 AND depth=5;
|
||||
} {32 32 63}
|
||||
do_timed_execsql_test 1.10-cte {
|
||||
WITH RECURSIVE
|
||||
below(id,depth) AS (
|
||||
VALUES(1,0)
|
||||
UNION ALL
|
||||
SELECT t1.x, below.depth+1
|
||||
FROM t1 JOIN below ON t1.y=below.id
|
||||
WHERE below.depth<5
|
||||
)
|
||||
SELECT count(*), min(id), max(id) FROM below WHERE depth=5;
|
||||
} {32 32 63}
|
||||
|
||||
# Create a much smaller table t2 with only 32 elements
|
||||
db eval {
|
||||
|
||||
+27
-1
@@ -66,6 +66,7 @@ reset_db
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
PRAGMA auto_vacuum=0;
|
||||
PRAGMA page_size=1024;
|
||||
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
@@ -95,8 +96,31 @@ do_test 2.2 {
|
||||
sqlite3 db test.db
|
||||
} {}
|
||||
|
||||
|
||||
# The corruption migration caused by the test case below does not
|
||||
# cause corruption to be detected in mmap mode.
|
||||
#
|
||||
# The trick here is that the root page of the tree scanned by the outer
|
||||
# query is also currently on the free-list. So while the first seek on
|
||||
# the table (for a==1) works, by the time the second is attempted The
|
||||
# "INSERT INTO t2..." statements have recycled the root page of t1 and
|
||||
# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects
|
||||
# that the PgHdr object associated with said root page does not match
|
||||
# the cursor (as it is now marked with PgHdr.intKey==0) and returns
|
||||
# SQLITE_CORRUPT.
|
||||
#
|
||||
# However, in mmap mode, the outer query and the inner queries use
|
||||
# different PgHdr objects (same data, but different PgHdr container
|
||||
# objects). And so the corruption is not detected. Instead, the second
|
||||
# seek fails to find anything and only a single row is returned.
|
||||
#
|
||||
set res23 {1 {database disk image is malformed}}
|
||||
if {[permutation]=="mmap"} {
|
||||
set res23 {0 one}
|
||||
}
|
||||
do_test 2.3 {
|
||||
list [catch {
|
||||
set res [list]
|
||||
db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
|
||||
db eval {
|
||||
INSERT INTO t2 SELECT randomblob(100) FROM t2;
|
||||
@@ -105,9 +129,11 @@ do_test 2.3 {
|
||||
INSERT INTO t2 SELECT randomblob(100) FROM t2;
|
||||
INSERT INTO t2 SELECT randomblob(100) FROM t2;
|
||||
}
|
||||
lappend res $b
|
||||
}
|
||||
set res
|
||||
} msg] $msg
|
||||
} {1 {database disk image is malformed}}
|
||||
} $res23
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
+39
-32
@@ -2946,38 +2946,45 @@ proc test_on_update_recursion {limit} {
|
||||
"
|
||||
}
|
||||
|
||||
do_test e_fkey-63.1.1 {
|
||||
test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH
|
||||
} {0 0}
|
||||
do_test e_fkey-63.1.2 {
|
||||
test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.1.3 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
|
||||
test_on_delete_recursion 5
|
||||
} {0 0}
|
||||
do_test e_fkey-63.1.4 {
|
||||
test_on_delete_recursion 6
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.1.5 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
|
||||
} {5}
|
||||
do_test e_fkey-63.2.1 {
|
||||
test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH
|
||||
} {0 0}
|
||||
do_test e_fkey-63.2.2 {
|
||||
test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.2.3 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
|
||||
test_on_update_recursion 5
|
||||
} {0 0}
|
||||
do_test e_fkey-63.2.4 {
|
||||
test_on_update_recursion 6
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.2.5 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
|
||||
} {5}
|
||||
# If the current build was created using clang with the -fsanitize=address
|
||||
# switch, then the library uses considerably more stack space than usual.
|
||||
# So much more, that some of the following tests cause stack overflows
|
||||
# if they are run under this configuration.
|
||||
#
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test e_fkey-63.1.1 {
|
||||
test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH
|
||||
} {0 0}
|
||||
do_test e_fkey-63.1.2 {
|
||||
test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.1.3 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
|
||||
test_on_delete_recursion 5
|
||||
} {0 0}
|
||||
do_test e_fkey-63.1.4 {
|
||||
test_on_delete_recursion 6
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.1.5 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
|
||||
} {5}
|
||||
do_test e_fkey-63.2.1 {
|
||||
test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH
|
||||
} {0 0}
|
||||
do_test e_fkey-63.2.2 {
|
||||
test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1]
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.2.3 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5
|
||||
test_on_update_recursion 5
|
||||
} {0 0}
|
||||
do_test e_fkey-63.2.4 {
|
||||
test_on_update_recursion 6
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
do_test e_fkey-63.2.5 {
|
||||
sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000
|
||||
} {5}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The setting of the recursive_triggers pragma does not affect foreign
|
||||
|
||||
+51
-43
@@ -333,9 +333,9 @@ do_select_tests e_select-1.1 {
|
||||
6 "SELECT count(*) WHERE 1" {1}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-48114-33255 If there is only a single table in the
|
||||
# join-source following the FROM clause, then the input data used by the
|
||||
# SELECT statement is the contents of the named table.
|
||||
# EVIDENCE-OF: R-45424-07352 If there is only a single table or subquery
|
||||
# in the FROM clause, then the input data used by the SELECT statement
|
||||
# is the contents of the named table.
|
||||
#
|
||||
# The results of the SELECT queries suggest that they are operating on the
|
||||
# contents of the table 'xx'.
|
||||
@@ -357,10 +357,10 @@ do_select_tests e_select-1.2 {
|
||||
3 "SELECT sum(x), sum(y) FROM xx" {-17.89 -16.87}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-23593-12456 If there is more than one table specified
|
||||
# as part of the join-source following the FROM keyword, then the
|
||||
# contents of each named table are joined into a single dataset for the
|
||||
# simple SELECT statement to operate on.
|
||||
# EVIDENCE-OF: R-28355-09804 If there is more than one table or subquery
|
||||
# in FROM clause then the contents of all tables and/or subqueries are
|
||||
# joined into a single dataset for the simple SELECT statement to
|
||||
# operate on.
|
||||
#
|
||||
# There are more detailed tests for subsequent requirements that add
|
||||
# more detail to this idea. We just add a single test that shows that
|
||||
@@ -383,10 +383,10 @@ do_select_tests e_select-1.3 {
|
||||
# of cartesian joins in the SELECT documentation is consistent with SQLite.
|
||||
# In doing so, we test the following three requirements as a side-effect:
|
||||
#
|
||||
# EVIDENCE-OF: R-46122-14930 If the join-op is "CROSS JOIN", "INNER
|
||||
# JOIN", "JOIN" or a comma (",") and there is no ON or USING clause,
|
||||
# then the result of the join is simply the cartesian product of the
|
||||
# left and right-hand datasets.
|
||||
# EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN",
|
||||
# "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING
|
||||
# clause, then the result of the join is simply the cartesian product of
|
||||
# the left and right-hand datasets.
|
||||
#
|
||||
# The tests are built on this assertion. Really, they test that the output
|
||||
# of a CROSS JOIN, JOIN, INNER JOIN or "," join matches the expected result
|
||||
@@ -464,10 +464,10 @@ do_join_test e_select-1.4.2.1 {
|
||||
]
|
||||
# TODO: Come back and add a few more like the above.
|
||||
|
||||
# EVIDENCE-OF: R-20659-43267 In other words, if the left-hand dataset
|
||||
# consists of Nlhs rows of Mlhs columns, and the right-hand dataset of
|
||||
# Nrhs rows of Mrhs columns, then the cartesian product is a dataset of
|
||||
# Nlhs.Nrhs rows, each containing Mlhs+Mrhs columns.
|
||||
# EVIDENCE-OF: R-18439-38548 In other words, if the left-hand dataset
|
||||
# consists of Nleft rows of Mleft columns, and the right-hand dataset of
|
||||
# Nright rows of Mright columns, then the cartesian product is a dataset
|
||||
# of Nleft×Nright rows, each containing Mleft+Mright columns.
|
||||
#
|
||||
# x1, x2 (Nlhs=3, Nrhs=2) (Mlhs=2, Mrhs=3)
|
||||
do_join_test e_select-1.4.3.1 {
|
||||
@@ -513,11 +513,10 @@ do_select_tests e_select-1.4.5 [list \
|
||||
4 { SELECT * FROM t1 AS y INNER JOIN t1 AS x } $t1_cross_t1 \
|
||||
]
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-22775-56496 If there is an ON clause specified, then
|
||||
# the ON expression is evaluated for each row of the cartesian product
|
||||
# as a boolean expression. All rows for which the expression evaluates
|
||||
# to false are excluded from the dataset.
|
||||
# EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON
|
||||
# expression is evaluated for each row of the cartesian product as a
|
||||
# boolean expression. Only rows for which the expression evaluates to
|
||||
# true are included from the dataset.
|
||||
#
|
||||
foreach {tn select res} [list \
|
||||
1 { SELECT * FROM t1 %JOIN% t2 ON (1) } $t1_cross_t2 \
|
||||
@@ -540,9 +539,9 @@ foreach {tn select res} [list \
|
||||
do_join_test e_select-1.3.$tn $select $res
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-63358-54862 If there is a USING clause specified as
|
||||
# part of the join-constraint, then each of the column names specified
|
||||
# must exist in the datasets to both the left and right of the join-op.
|
||||
# EVIDENCE-OF: R-49933-05137 If there is a USING clause then each of the
|
||||
# column names specified must exist in the datasets to both the left and
|
||||
# right of the join-operator.
|
||||
#
|
||||
do_select_tests e_select-1.4 -error {
|
||||
cannot join using column %s - column not present in both tables
|
||||
@@ -552,10 +551,10 @@ do_select_tests e_select-1.4 -error {
|
||||
3 { SELECT * FROM t3, (SELECT a AS b, b AS c FROM t1) USING (a) } "a"
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-55987-04584 For each pair of namesake columns, the
|
||||
# EVIDENCE-OF: R-22776-52830 For each pair of named columns, the
|
||||
# expression "lhs.X = rhs.X" is evaluated for each row of the cartesian
|
||||
# product as a boolean expression. All rows for which one or more of the
|
||||
# expressions evaluates to false are excluded from the result set.
|
||||
# product as a boolean expression. Only rows for which all such
|
||||
# expressions evaluates to true are included from the result set.
|
||||
#
|
||||
do_select_tests e_select-1.5 {
|
||||
1 { SELECT * FROM t1, t3 USING (a) } {a one 1 b two 2}
|
||||
@@ -566,8 +565,8 @@ do_select_tests e_select-1.5 {
|
||||
# USING clause, the normal rules for handling affinities, collation
|
||||
# sequences and NULL values in comparisons apply.
|
||||
#
|
||||
# EVIDENCE-OF: R-35466-18578 The column from the dataset on the
|
||||
# left-hand side of the join operator is considered to be on the
|
||||
# EVIDENCE-OF: R-38422-04402 The column from the dataset on the
|
||||
# left-hand side of the join-operator is considered to be on the
|
||||
# left-hand side of the comparison operator (=) for the purposes of
|
||||
# collation sequence and affinity precedence.
|
||||
#
|
||||
@@ -622,10 +621,9 @@ foreach {tn select res} {
|
||||
} {
|
||||
do_join_test e_select-1.7.$tn $select $res
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-41434-12448 If the join-op is a "LEFT JOIN" or "LEFT
|
||||
# OUTER JOIN", then after the ON or USING filtering clauses have been
|
||||
# applied, an extra row is added to the output for each row in the
|
||||
# EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or
|
||||
# "LEFT OUTER JOIN", then after the ON or USING filtering clauses have
|
||||
# been applied, an extra row is added to the output for each row in the
|
||||
# original left-hand input dataset that corresponds to no rows at all in
|
||||
# the composite dataset (if any).
|
||||
#
|
||||
@@ -660,8 +658,8 @@ do_select_tests e_select-1.9 {
|
||||
2b "SELECT * FROM t7 LEFT JOIN t8 USING (a)" {x ex 24 abc 24 y why 25 {} {}}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-01809-52134 If the NATURAL keyword is added to any of
|
||||
# the join-ops, then an implicit USING clause is added to the
|
||||
# EVIDENCE-OF: R-04932-55942 If the NATURAL keyword is in the
|
||||
# join-operator then an implicit USING clause is added to the
|
||||
# join-constraints. The implicit USING clause contains each of the
|
||||
# column names that appear in both the left and right-hand input
|
||||
# datasets.
|
||||
@@ -734,10 +732,10 @@ do_execsql_test e_select-3.0 {
|
||||
INSERT INTO x2 VALUES(7, 'mistrusted', 'standardized');
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-06999-14330 If a WHERE clause is specified, the WHERE
|
||||
# EVIDENCE-OF: R-60775-64916 If a WHERE clause is specified, the WHERE
|
||||
# expression is evaluated for each row in the input data as a boolean
|
||||
# expression. All rows for which the WHERE clause expression evaluates
|
||||
# to false are excluded from the dataset before continuing.
|
||||
# expression. Only rows for which the WHERE clause expression evaluates
|
||||
# to true are included from the dataset before continuing.
|
||||
#
|
||||
do_execsql_test e_select-3.1.1 { SELECT k FROM x1 WHERE x } {3}
|
||||
do_execsql_test e_select-3.1.2 { SELECT k FROM x1 WHERE y } {3 5 6}
|
||||
@@ -815,8 +813,8 @@ do_select_tests e_select-4.1 {
|
||||
}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-61869-22578 It is an error to use a "*" or "alias.*"
|
||||
# expression in any context other than than a result expression list.
|
||||
# EVIDENCE-OF: R-38023-18396 It is an error to use a "*" or "alias.*"
|
||||
# expression in any context other than a result expression list.
|
||||
#
|
||||
# EVIDENCE-OF: R-44324-41166 It is also an error to use a "*" or
|
||||
# "alias.*" expression in a simple SELECT query that does not have a
|
||||
@@ -1009,12 +1007,12 @@ do_execsql_test e_select-4.9.0 {
|
||||
INSERT INTO b3 VALUES('dEF', 'dEF');
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-57754-57109 If the SELECT statement is an aggregate
|
||||
# EVIDENCE-OF: R-07284-35990 If the SELECT statement is an aggregate
|
||||
# query with a GROUP BY clause, then each of the expressions specified
|
||||
# as part of the GROUP BY clause is evaluated for each row of the
|
||||
# dataset. Each row is then assigned to a "group" based on the results;
|
||||
# rows for which the results of evaluating the GROUP BY expressions are
|
||||
# the same are assigned to the same group.
|
||||
# the same get assigned to the same group.
|
||||
#
|
||||
# These tests also show that the following is not untrue:
|
||||
#
|
||||
@@ -1373,8 +1371,9 @@ foreach {tn select op1 op2} {
|
||||
do_catchsql_test e_select-7.2.$tn $select [list 1 $err]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-22874-32655 ORDER BY and LIMIT clauses may only occur
|
||||
# at the end of the entire compound SELECT.
|
||||
# EVIDENCE-OF: R-45440-25633 ORDER BY and LIMIT clauses may only occur
|
||||
# at the end of the entire compound SELECT, and then only if the final
|
||||
# element of the compound is not a VALUES clause.
|
||||
#
|
||||
foreach {tn select} {
|
||||
1 "SELECT * FROM j1 UNION ALL SELECT * FROM j2,j3 ORDER BY a"
|
||||
@@ -1386,6 +1385,7 @@ foreach {tn select} {
|
||||
|
||||
7 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 ORDER BY a"
|
||||
8 "SELECT count(*) FROM j1 UNION SELECT max(e) FROM j2 ORDER BY 1"
|
||||
8b "VALUES('8b') UNION SELECT max(e) FROM j2 ORDER BY 1"
|
||||
9 "SELECT count(*), * FROM j1 UNION SELECT *,* FROM j2 ORDER BY 1,2,3"
|
||||
10 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 LIMIT 10"
|
||||
11 "SELECT * FROM j1 UNION SELECT * FROM j2,j3 LIMIT 10 OFFSET 5"
|
||||
@@ -1407,6 +1407,14 @@ foreach {tn select} {
|
||||
} {
|
||||
do_test e_select-7.3.$tn { catch {execsql $select} msg } 0
|
||||
}
|
||||
foreach {tn select} {
|
||||
50 "SELECT * FROM j1 ORDER BY 1 UNION ALL SELECT * FROM j2,j3"
|
||||
51 "SELECT * FROM j1 LIMIT 1 UNION ALL SELECT * FROM j2,j3"
|
||||
52 "SELECT count(*) FROM j1 UNION ALL VALUES(11) ORDER BY 1"
|
||||
53 "SELECT count(*) FROM j1 UNION ALL VALUES(11) LIMIT 1"
|
||||
} {
|
||||
do_test e_select-7.3.$tn { catch {execsql $select} msg } 1
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-08531-36543 A compound SELECT created using UNION ALL
|
||||
# operator returns all the rows from the SELECT to the left of the UNION
|
||||
|
||||
+15
-15
@@ -344,10 +344,10 @@ foreach {tn indexes} {
|
||||
catchsql { DROP INDEX i3 }
|
||||
execsql $indexes
|
||||
|
||||
# EVIDENCE-OF: R-46122-14930 If the join-op is "CROSS JOIN", "INNER
|
||||
# JOIN", "JOIN" or a comma (",") and there is no ON or USING clause,
|
||||
# then the result of the join is simply the cartesian product of the
|
||||
# left and right-hand datasets.
|
||||
# EVIDENCE-OF: R-49872-03192 If the join-operator is "CROSS JOIN",
|
||||
# "INNER JOIN", "JOIN" or a comma (",") and there is no ON or USING
|
||||
# clause, then the result of the join is simply the cartesian product of
|
||||
# the left and right-hand datasets.
|
||||
#
|
||||
# EVIDENCE-OF: R-46256-57243 There is no difference between the "INNER
|
||||
# JOIN", "JOIN" and "," join operators.
|
||||
@@ -368,10 +368,10 @@ foreach {tn indexes} {
|
||||
test_join $tn.1.11 "t2 CROSS JOIN t2 AS x" {t2 t2}
|
||||
test_join $tn.1.12 "t2 JOIN t2 AS x" {t2 t2}
|
||||
|
||||
# EVIDENCE-OF: R-22775-56496 If there is an ON clause specified, then
|
||||
# the ON expression is evaluated for each row of the cartesian product
|
||||
# as a boolean expression. All rows for which the expression evaluates
|
||||
# to false are excluded from the dataset.
|
||||
# EVIDENCE-OF: R-38465-03616 If there is an ON clause then the ON
|
||||
# expression is evaluated for each row of the cartesian product as a
|
||||
# boolean expression. Only rows for which the expression evaluates to
|
||||
# true are included from the dataset.
|
||||
#
|
||||
test_join $tn.2.1 "t1, t2 ON (t1.a=t2.a)" {t1 t2 -on {te_equals a a}}
|
||||
test_join $tn.2.2 "t2, t1 ON (t1.a=t2.a)" {t2 t1 -on {te_equals a a}}
|
||||
@@ -504,14 +504,14 @@ do_execsql_test e_select-2.2.0 {
|
||||
INSERT INTO t5 VALUES(2, 'two');
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-55824-40976 A sub-select specified in the join-source
|
||||
# following the FROM clause in a simple SELECT statement is handled as
|
||||
# if it was a table containing the data returned by executing the
|
||||
# sub-select statement.
|
||||
# EVIDENCE-OF: R-59237-46742 A subquery specified in the
|
||||
# table-or-subquery following the FROM clause in a simple SELECT
|
||||
# statement is handled as if it was a table containing the data returned
|
||||
# by executing the subquery statement.
|
||||
#
|
||||
# EVIDENCE-OF: R-42612-06757 Each column of the sub-select dataset
|
||||
# inherits the collation sequence and affinity of the corresponding
|
||||
# expression in the sub-select statement.
|
||||
# EVIDENCE-OF: R-27438-53558 Each column of the subquery has the
|
||||
# collation sequence and affinity of the corresponding expression in the
|
||||
# subquery statement.
|
||||
#
|
||||
foreach {tn subselect select spec} {
|
||||
1 "SELECT * FROM t2" "SELECT * FROM t1 JOIN %ss%"
|
||||
|
||||
+5
-3
@@ -15,9 +15,11 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_test misc7-1-misuse {
|
||||
c_misuse_test
|
||||
} {}
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test misc7-1-misuse {
|
||||
c_misuse_test
|
||||
} {}
|
||||
}
|
||||
|
||||
do_test misc7-2 {
|
||||
c_realloc_test
|
||||
|
||||
+32
-29
@@ -171,37 +171,40 @@ do_test misuse-4.3 {
|
||||
} msg]
|
||||
lappend v $msg $r
|
||||
} {0 {} SQLITE_BUSY}
|
||||
do_test misuse-4.4 {
|
||||
|
||||
if {[clang_sanitize_address]==0} {
|
||||
do_test misuse-4.4 {
|
||||
# Flush the TCL statement cache here, otherwise the sqlite3_close() will
|
||||
# fail because there are still un-finalized() VDBEs.
|
||||
db cache flush
|
||||
sqlite3_close $::DB
|
||||
catchsql2 {SELECT * FROM t1}
|
||||
} {1 {library routine called out of sequence}}
|
||||
do_test misuse-4.5 {
|
||||
catchsql {
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {1 {library routine called out of sequence}}
|
||||
db cache flush
|
||||
sqlite3_close $::DB
|
||||
catchsql2 {SELECT * FROM t1}
|
||||
} {1 {library routine called out of sequence}}
|
||||
do_test misuse-4.5 {
|
||||
catchsql {
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {1 {library routine called out of sequence}}
|
||||
|
||||
# Attempt to use a database after it has been closed.
|
||||
#
|
||||
do_test misuse-5.1 {
|
||||
db close
|
||||
sqlite3 db test2.db; set ::DB [sqlite3_connection_pointer db]
|
||||
execsql {
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {1 2}
|
||||
do_test misuse-5.2 {
|
||||
catchsql2 {SELECT * FROM t1}
|
||||
} {0 {a b 1 2}}
|
||||
do_test misuse-5.3 {
|
||||
db close
|
||||
set r [catch {
|
||||
sqlite3_prepare $::DB {SELECT * FROM t1} -1 TAIL
|
||||
} msg]
|
||||
lappend r $msg
|
||||
} {1 {(21) library routine called out of sequence}}
|
||||
# Attempt to use a database after it has been closed.
|
||||
#
|
||||
do_test misuse-5.1 {
|
||||
db close
|
||||
sqlite3 db test2.db; set ::DB [sqlite3_connection_pointer db]
|
||||
execsql {
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {1 2}
|
||||
do_test misuse-5.2 {
|
||||
catchsql2 {SELECT * FROM t1}
|
||||
} {0 {a b 1 2}}
|
||||
do_test misuse-5.3 {
|
||||
db close
|
||||
set r [catch {
|
||||
sqlite3_prepare $::DB {SELECT * FROM t1} -1 TAIL
|
||||
} msg]
|
||||
lappend r $msg
|
||||
} {1 {(21) library routine called out of sequence}}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+6
-1
@@ -9,7 +9,7 @@
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Tests for the SQLITE_IOERR_NODB error condition: the database file file
|
||||
# Tests for the SQLITE_READONLY_DBMOVED error condition: the database file
|
||||
# is unlinked or renamed out from under SQLite.
|
||||
#
|
||||
|
||||
@@ -18,6 +18,11 @@ if {$tcl_platform(platform)!="unix"} return
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
if {[permutation]=="inmemory_journal"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# Create a database file for testing
|
||||
#
|
||||
do_execsql_test pager4-1.1 {
|
||||
|
||||
@@ -1544,5 +1544,6 @@ do_faultsim_test pagerfault-36 -prep {
|
||||
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_uri 0
|
||||
sqlite3_initialize
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -642,7 +642,7 @@ test_suite "inmemory_journal" -description {
|
||||
ioerr.test ioerr2.test ioerr3.test ioerr4.test ioerr5.test
|
||||
vacuum3.test incrblob_err.test diskfull.test backup_ioerr.test
|
||||
e_fts3.test fts3cov.test fts3malloc.test fts3rnd.test
|
||||
fts3snippet.test
|
||||
fts3snippet.test mmapfault.test
|
||||
|
||||
# Exclude test scripts that use tcl IO to access journal files or count
|
||||
# the number of fsync() calls.
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ do_execsql_test printf2-1.11 {
|
||||
SELECT printf('%lld%n',314159.2653,'hi');
|
||||
} {314159}
|
||||
|
||||
# EVIDENCE-OF: R-20555-31089 The %z format is interchangable with %s.
|
||||
# EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s.
|
||||
#
|
||||
do_execsql_test printf2-1.12 {
|
||||
SELECT printf('%.*z',5,'abcdefghijklmnop');
|
||||
|
||||
+16
-14
@@ -138,21 +138,23 @@ ifcapable {subquery && compound} {
|
||||
# Verify that an error occurs if you have too many terms on a
|
||||
# compound select statement.
|
||||
#
|
||||
ifcapable compound {
|
||||
if {$SQLITE_MAX_COMPOUND_SELECT>0} {
|
||||
set sql {SELECT 0}
|
||||
set result 0
|
||||
for {set i 1} {$i<$SQLITE_MAX_COMPOUND_SELECT} {incr i} {
|
||||
append sql " UNION ALL SELECT $i"
|
||||
lappend result $i
|
||||
if {[clang_sanitize_address]==0} {
|
||||
ifcapable compound {
|
||||
if {$SQLITE_MAX_COMPOUND_SELECT>0} {
|
||||
set sql {SELECT 0}
|
||||
set result 0
|
||||
for {set i 1} {$i<$SQLITE_MAX_COMPOUND_SELECT} {incr i} {
|
||||
append sql " UNION ALL SELECT $i"
|
||||
lappend result $i
|
||||
}
|
||||
do_test select7-6.1 {
|
||||
catchsql $sql
|
||||
} [list 0 $result]
|
||||
append sql { UNION ALL SELECT 99999999}
|
||||
do_test select7-6.2 {
|
||||
catchsql $sql
|
||||
} {1 {too many terms in compound SELECT}}
|
||||
}
|
||||
do_test select7-6.1 {
|
||||
catchsql $sql
|
||||
} [list 0 $result]
|
||||
append sql { UNION ALL SELECT 99999999}
|
||||
do_test select7-6.2 {
|
||||
catchsql $sql
|
||||
} {1 {too many terms in compound SELECT}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,6 +221,53 @@ foreach {tn word res} {
|
||||
} $res
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Try some queries by rowid.
|
||||
#
|
||||
do_execsql_test 6.1.1 {
|
||||
SELECT word FROM t3 WHERE rowid = 10;
|
||||
} {keener}
|
||||
do_execsql_test 6.1.2 {
|
||||
SELECT word, distance FROM t3 WHERE rowid = 10;
|
||||
} {keener {}}
|
||||
do_execsql_test 6.1.3 {
|
||||
SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
|
||||
} {keener 300}
|
||||
|
||||
ifcapable trace {
|
||||
proc trace_callback {sql} {
|
||||
if {[string range $sql 0 2] == "-- "} {
|
||||
lappend ::trace [string range $sql 3 end]
|
||||
}
|
||||
}
|
||||
|
||||
proc do_tracesql_test {tn sql {res {}}} {
|
||||
set ::trace [list]
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
set vals [execsql {$sql}]
|
||||
concat [set vals] [set ::trace]
|
||||
}] [list {*}$res]]
|
||||
}
|
||||
|
||||
db trace trace_callback
|
||||
do_tracesql_test 6.2.1 {
|
||||
SELECT word FROM t3 WHERE rowid = 10;
|
||||
} {keener
|
||||
{SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
|
||||
}
|
||||
do_tracesql_test 6.2.2 {
|
||||
SELECT word, distance FROM t3 WHERE rowid = 10;
|
||||
} {keener {}
|
||||
{SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
|
||||
}
|
||||
do_tracesql_test 6.2.3 {
|
||||
SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
|
||||
} {keener 300
|
||||
{SELECT id, word, rank, k1 FROM "main"."t3_vocab" WHERE langid=0 AND k2>=?1 AND k2<?2}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
# do_test TESTNAME SCRIPT EXPECTED
|
||||
# do_execsql_test TESTNAME SQL EXPECTED
|
||||
# do_catchsql_test TESTNAME SQL EXPECTED
|
||||
# do_timed_execsql_test TESTNAME SQL EXPECTED
|
||||
#
|
||||
# Commands providing a lower level interface to the global test counters:
|
||||
#
|
||||
@@ -717,6 +718,11 @@ proc do_catchsql_test {testname sql result} {
|
||||
fix_testname testname
|
||||
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result]
|
||||
}
|
||||
proc do_timed_execsql_test {testname sql {result {}}} {
|
||||
fix_testname testname
|
||||
uplevel do_test [list $testname] [list "execsql_timed {$sql}"]\
|
||||
[list [list {*}$result]]
|
||||
}
|
||||
proc do_eqp_test {name sql res} {
|
||||
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
|
||||
}
|
||||
@@ -1013,6 +1019,14 @@ proc execsql {sql {db db}} {
|
||||
# puts "SQL = $sql"
|
||||
uplevel [list $db eval $sql]
|
||||
}
|
||||
proc execsql_timed {sql {db db}} {
|
||||
set tm [time {
|
||||
set x [uplevel [list $db eval $sql]]
|
||||
} 1]
|
||||
set tm [lindex $tm 0]
|
||||
puts -nonewline " ([expr {$tm*0.001}]ms) "
|
||||
set x
|
||||
}
|
||||
|
||||
# Execute SQL and catch exceptions.
|
||||
#
|
||||
|
||||
+367
-2
@@ -374,7 +374,7 @@ do_catchsql_test 7.6 {
|
||||
|
||||
# Compute the mandelbrot set using a recursive query
|
||||
#
|
||||
do_execsql_test 8.1 {
|
||||
do_execsql_test 8.1-mandelbrot {
|
||||
WITH RECURSIVE
|
||||
xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+0.05 FROM xaxis WHERE x<1.2),
|
||||
yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+0.1 FROM yaxis WHERE y<1.0),
|
||||
@@ -417,7 +417,7 @@ do_execsql_test 8.1 {
|
||||
|
||||
# Solve a sudoku puzzle using a recursive query
|
||||
#
|
||||
do_execsql_test 8.2 {
|
||||
do_execsql_test 8.2-soduko {
|
||||
WITH RECURSIVE
|
||||
input(sud) AS (
|
||||
VALUES('53..7....6..195....98....6.8...6...34..8.3..17...2...6.6....28....419..5....8..79')
|
||||
@@ -452,4 +452,369 @@ do_execsql_test 8.2 {
|
||||
SELECT s FROM x WHERE ind=0;
|
||||
} {534678912672195348198342567859761423426853791713924856961537284287419635345286179}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Some tests that use LIMIT and OFFSET in the definition of recursive CTEs.
|
||||
#
|
||||
set I [list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
|
||||
proc limit_test {tn iLimit iOffset} {
|
||||
if {$iOffset < 0} { set iOffset 0 }
|
||||
if {$iLimit < 0 } {
|
||||
set result [lrange $::I $iOffset end]
|
||||
} else {
|
||||
set result [lrange $::I $iOffset [expr $iLimit+$iOffset-1]]
|
||||
}
|
||||
uplevel [list do_execsql_test $tn [subst -nocommands {
|
||||
WITH ii(a) AS (
|
||||
VALUES(1)
|
||||
UNION ALL
|
||||
SELECT a+1 FROM ii WHERE a<20
|
||||
LIMIT $iLimit OFFSET $iOffset
|
||||
)
|
||||
SELECT * FROM ii
|
||||
}] $result]
|
||||
}
|
||||
|
||||
limit_test 9.1 20 0
|
||||
limit_test 9.2 0 0
|
||||
limit_test 9.3 19 1
|
||||
limit_test 9.4 20 -1
|
||||
limit_test 9.5 5 5
|
||||
limit_test 9.6 0 -1
|
||||
limit_test 9.7 40 -1
|
||||
limit_test 9.8 -1 -1
|
||||
limit_test 9.9 -1 -1
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Test the ORDER BY clause on recursive tables.
|
||||
#
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
DROP TABLE IF EXISTS tree;
|
||||
CREATE TABLE tree(id INTEGER PRIMARY KEY, parentid, payload);
|
||||
}
|
||||
|
||||
proc insert_into_tree {L} {
|
||||
db eval { DELETE FROM tree }
|
||||
foreach key $L {
|
||||
unset -nocomplain parentid
|
||||
foreach seg [split $key /] {
|
||||
if {$seg==""} continue
|
||||
set id [db one {
|
||||
SELECT id FROM tree WHERE parentid IS $parentid AND payload=$seg
|
||||
}]
|
||||
if {$id==""} {
|
||||
db eval { INSERT INTO tree VALUES(NULL, $parentid, $seg) }
|
||||
set parentid [db last_insert_rowid]
|
||||
} else {
|
||||
set parentid $id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insert_into_tree {
|
||||
/a/a/a
|
||||
/a/b/c
|
||||
/a/b/c/d
|
||||
/a/b/d
|
||||
}
|
||||
do_execsql_test 10.2 {
|
||||
WITH flat(fid, p) AS (
|
||||
SELECT id, '/' || payload FROM tree WHERE parentid IS NULL
|
||||
UNION ALL
|
||||
SELECT id, p || '/' || payload FROM flat, tree WHERE parentid=fid
|
||||
)
|
||||
SELECT p FROM flat ORDER BY p;
|
||||
} {
|
||||
/a /a/a /a/a/a
|
||||
/a/b /a/b/c /a/b/c/d
|
||||
/a/b/d
|
||||
}
|
||||
|
||||
# Scan the tree-structure currently stored in table tree. Return a list
|
||||
# of nodes visited.
|
||||
#
|
||||
proc scan_tree {bDepthFirst bReverse} {
|
||||
|
||||
set order "ORDER BY "
|
||||
if {$bDepthFirst==0} { append order "2 ASC," }
|
||||
if {$bReverse==0} {
|
||||
append order " 3 ASC"
|
||||
} else {
|
||||
append order " 3 DESC"
|
||||
}
|
||||
|
||||
db eval "
|
||||
WITH flat(fid, depth, p) AS (
|
||||
SELECT id, 1, '/' || payload FROM tree WHERE parentid IS NULL
|
||||
UNION ALL
|
||||
SELECT id, depth+1, p||'/'||payload FROM flat, tree WHERE parentid=fid
|
||||
$order
|
||||
)
|
||||
SELECT p FROM flat;
|
||||
"
|
||||
}
|
||||
|
||||
insert_into_tree {
|
||||
/a/b
|
||||
/a/b/c
|
||||
/a/d
|
||||
/a/d/e
|
||||
/a/d/f
|
||||
/g/h
|
||||
}
|
||||
|
||||
# Breadth first, siblings in ascending order.
|
||||
#
|
||||
do_test 10.3 {
|
||||
scan_tree 0 0
|
||||
} [list {*}{
|
||||
/a /g
|
||||
/a/b /a/d /g/h
|
||||
/a/b/c /a/d/e /a/d/f
|
||||
}]
|
||||
|
||||
# Depth first, siblings in ascending order.
|
||||
#
|
||||
do_test 10.4 {
|
||||
scan_tree 1 0
|
||||
} [list {*}{
|
||||
/a /a/b /a/b/c
|
||||
/a/d /a/d/e
|
||||
/a/d/f
|
||||
/g /g/h
|
||||
}]
|
||||
|
||||
# Breadth first, siblings in descending order.
|
||||
#
|
||||
do_test 10.5 {
|
||||
scan_tree 0 1
|
||||
} [list {*}{
|
||||
/g /a
|
||||
/g/h /a/d /a/b
|
||||
/a/d/f /a/d/e /a/b/c
|
||||
}]
|
||||
|
||||
# Depth first, siblings in ascending order.
|
||||
#
|
||||
do_test 10.6 {
|
||||
scan_tree 1 1
|
||||
} [list {*}{
|
||||
/g /g/h
|
||||
/a /a/d /a/d/f
|
||||
/a/d/e
|
||||
/a/b /a/b/c
|
||||
}]
|
||||
|
||||
|
||||
# Test name resolution in ORDER BY clauses.
|
||||
#
|
||||
do_catchsql_test 10.7.1 {
|
||||
WITH t(a) AS (
|
||||
SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY a
|
||||
)
|
||||
SELECT * FROM t
|
||||
} {1 {1st ORDER BY term does not match any column in the result set}}
|
||||
do_execsql_test 10.7.2 {
|
||||
WITH t(a) AS (
|
||||
SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY b
|
||||
)
|
||||
SELECT * FROM t
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 10.7.3 {
|
||||
WITH t(a) AS (
|
||||
SELECT 1 AS b UNION ALL SELECT a+1 AS c FROM t WHERE a<5 ORDER BY c
|
||||
)
|
||||
SELECT * FROM t
|
||||
} {1 2 3 4 5}
|
||||
|
||||
# Test COLLATE clauses attached to ORDER BY.
|
||||
#
|
||||
insert_into_tree {
|
||||
/a/b
|
||||
/a/C
|
||||
/a/d
|
||||
/B/e
|
||||
/B/F
|
||||
/B/g
|
||||
/c/h
|
||||
/c/I
|
||||
/c/j
|
||||
}
|
||||
|
||||
do_execsql_test 10.8.1 {
|
||||
WITH flat(fid, depth, p) AS (
|
||||
SELECT id, 1, '/' || payload FROM tree WHERE parentid IS NULL
|
||||
UNION ALL
|
||||
SELECT id, depth+1, p||'/'||payload FROM flat, tree WHERE parentid=fid
|
||||
ORDER BY 2, 3 COLLATE nocase
|
||||
)
|
||||
SELECT p FROM flat;
|
||||
} {
|
||||
/a /B /c
|
||||
/a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
|
||||
}
|
||||
do_execsql_test 10.8.2 {
|
||||
WITH flat(fid, depth, p) AS (
|
||||
SELECT id, 1, ('/' || payload) COLLATE nocase
|
||||
FROM tree WHERE parentid IS NULL
|
||||
UNION ALL
|
||||
SELECT id, depth+1, (p||'/'||payload)
|
||||
FROM flat, tree WHERE parentid=fid
|
||||
ORDER BY 2, 3
|
||||
)
|
||||
SELECT p FROM flat;
|
||||
} {
|
||||
/a /B /c
|
||||
/a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
|
||||
}
|
||||
|
||||
do_execsql_test 10.8.3 {
|
||||
WITH flat(fid, depth, p) AS (
|
||||
SELECT id, 1, ('/' || payload)
|
||||
FROM tree WHERE parentid IS NULL
|
||||
UNION ALL
|
||||
SELECT id, depth+1, (p||'/'||payload) COLLATE nocase
|
||||
FROM flat, tree WHERE parentid=fid
|
||||
ORDER BY 2, 3
|
||||
)
|
||||
SELECT p FROM flat;
|
||||
} {
|
||||
/a /B /c
|
||||
/a/b /a/C /a/d /B/e /B/F /B/g /c/h /c/I /c/j
|
||||
}
|
||||
|
||||
do_execsql_test 10.8.4.1 {
|
||||
CREATE TABLE tst(a,b);
|
||||
INSERT INTO tst VALUES('a', 'A');
|
||||
INSERT INTO tst VALUES('b', 'B');
|
||||
INSERT INTO tst VALUES('c', 'C');
|
||||
SELECT a COLLATE nocase FROM tst UNION ALL SELECT b FROM tst ORDER BY 1;
|
||||
} {a A b B c C}
|
||||
do_execsql_test 10.8.4.2 {
|
||||
SELECT a FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1;
|
||||
} {A B C a b c}
|
||||
do_execsql_test 10.8.4.3 {
|
||||
SELECT a||'' FROM tst UNION ALL SELECT b COLLATE nocase FROM tst ORDER BY 1;
|
||||
} {a A b B c C}
|
||||
|
||||
# Test cases to illustrate on the ORDER BY clause on a recursive query can be
|
||||
# used to control depth-first versus breath-first search in a tree.
|
||||
#
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE org(
|
||||
name TEXT PRIMARY KEY,
|
||||
boss TEXT REFERENCES org
|
||||
) WITHOUT ROWID;
|
||||
INSERT INTO org VALUES('Alice',NULL);
|
||||
INSERT INTO org VALUES('Bob','Alice');
|
||||
INSERT INTO org VALUES('Cindy','Alice');
|
||||
INSERT INTO org VALUES('Dave','Bob');
|
||||
INSERT INTO org VALUES('Emma','Bob');
|
||||
INSERT INTO org VALUES('Fred','Cindy');
|
||||
INSERT INTO org VALUES('Gail','Cindy');
|
||||
INSERT INTO org VALUES('Harry','Dave');
|
||||
INSERT INTO org VALUES('Ingrid','Dave');
|
||||
INSERT INTO org VALUES('Jim','Emma');
|
||||
INSERT INTO org VALUES('Kate','Emma');
|
||||
INSERT INTO org VALUES('Lanny','Fred');
|
||||
INSERT INTO org VALUES('Mary','Fred');
|
||||
INSERT INTO org VALUES('Noland','Gail');
|
||||
INSERT INTO org VALUES('Olivia','Gail');
|
||||
-- The above are all under Alice. Add a few more records for people
|
||||
-- not in Alice's group, just to prove that they won't be selected.
|
||||
INSERT INTO org VALUES('Xaviar',NULL);
|
||||
INSERT INTO org VALUES('Xia','Xaviar');
|
||||
INSERT INTO org VALUES('Xerxes','Xaviar');
|
||||
INSERT INTO org VALUES('Xena','Xia');
|
||||
-- Find all members of Alice's group, breath-first order
|
||||
WITH RECURSIVE
|
||||
under_alice(name,level) AS (
|
||||
VALUES('Alice','0')
|
||||
UNION ALL
|
||||
SELECT org.name, under_alice.level+1
|
||||
FROM org, under_alice
|
||||
WHERE org.boss=under_alice.name
|
||||
ORDER BY 2
|
||||
)
|
||||
SELECT group_concat(substr('...............',1,level*3) || name,x'0a')
|
||||
FROM under_alice;
|
||||
} {{Alice
|
||||
...Bob
|
||||
...Cindy
|
||||
......Dave
|
||||
......Emma
|
||||
......Fred
|
||||
......Gail
|
||||
.........Harry
|
||||
.........Ingrid
|
||||
.........Jim
|
||||
.........Kate
|
||||
.........Lanny
|
||||
.........Mary
|
||||
.........Noland
|
||||
.........Olivia}}
|
||||
|
||||
# The previous query used "ORDER BY level" to yield a breath-first search.
|
||||
# Change that to "ORDER BY level DESC" for a depth-first search.
|
||||
#
|
||||
do_execsql_test 11.2 {
|
||||
WITH RECURSIVE
|
||||
under_alice(name,level) AS (
|
||||
VALUES('Alice','0')
|
||||
UNION ALL
|
||||
SELECT org.name, under_alice.level+1
|
||||
FROM org, under_alice
|
||||
WHERE org.boss=under_alice.name
|
||||
ORDER BY 2 DESC
|
||||
)
|
||||
SELECT group_concat(substr('...............',1,level*3) || name,x'0a')
|
||||
FROM under_alice;
|
||||
} {{Alice
|
||||
...Bob
|
||||
......Dave
|
||||
.........Harry
|
||||
.........Ingrid
|
||||
......Emma
|
||||
.........Jim
|
||||
.........Kate
|
||||
...Cindy
|
||||
......Fred
|
||||
.........Lanny
|
||||
.........Mary
|
||||
......Gail
|
||||
.........Noland
|
||||
.........Olivia}}
|
||||
|
||||
# Without an ORDER BY clause, the recursive query should use a FIFO,
|
||||
# resulting in a breath-first search.
|
||||
#
|
||||
do_execsql_test 11.3 {
|
||||
WITH RECURSIVE
|
||||
under_alice(name,level) AS (
|
||||
VALUES('Alice','0')
|
||||
UNION ALL
|
||||
SELECT org.name, under_alice.level+1
|
||||
FROM org, under_alice
|
||||
WHERE org.boss=under_alice.name
|
||||
)
|
||||
SELECT group_concat(substr('...............',1,level*3) || name,x'0a')
|
||||
FROM under_alice;
|
||||
} {{Alice
|
||||
...Bob
|
||||
...Cindy
|
||||
......Dave
|
||||
......Emma
|
||||
......Fred
|
||||
......Gail
|
||||
.........Harry
|
||||
.........Ingrid
|
||||
.........Jim
|
||||
.........Kate
|
||||
.........Lanny
|
||||
.........Mary
|
||||
.........Noland
|
||||
.........Olivia}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ proc main {argv} {
|
||||
SQLITE_OMIT_COMPILEOPTION_DIAGS \
|
||||
SQLITE_OMIT_COMPLETE \
|
||||
SQLITE_OMIT_COMPOUND_SELECT \
|
||||
SQLITE_OMIT_CTE \
|
||||
SQLITE_OMIT_DATETIME_FUNCS \
|
||||
SQLITE_OMIT_DECLTYPE \
|
||||
SQLITE_OMIT_DEPRECATED \
|
||||
|
||||
+5
-6
@@ -119,7 +119,7 @@ static unsigned char *print_byte_range(
|
||||
/*
|
||||
** Print an entire page of content as hex
|
||||
*/
|
||||
static print_page(int iPg){
|
||||
static void print_page(int iPg){
|
||||
int iStart;
|
||||
unsigned char *aData;
|
||||
iStart = (iPg-1)*pagesize;
|
||||
@@ -131,7 +131,7 @@ static print_page(int iPg){
|
||||
|
||||
/* Print a line of decode output showing a 4-byte integer.
|
||||
*/
|
||||
static print_decode_line(
|
||||
static void print_decode_line(
|
||||
unsigned char *aData, /* Content being decoded */
|
||||
int ofst, int nByte, /* Start and size of decode */
|
||||
const char *zMsg /* Message to append */
|
||||
@@ -428,7 +428,7 @@ static void decode_trunk_page(
|
||||
int detail, /* Show leaf pages if true */
|
||||
int recursive /* Follow the trunk change if true */
|
||||
){
|
||||
int n, i, k;
|
||||
int n, i;
|
||||
unsigned char *a;
|
||||
while( pgno>0 ){
|
||||
a = getContent((pgno-1)*pagesize, pagesize);
|
||||
@@ -495,7 +495,6 @@ static void page_usage_cell(
|
||||
int cellno /* Index of the cell on the page */
|
||||
){
|
||||
int i;
|
||||
int nDesc = 0;
|
||||
int n = 0;
|
||||
i64 nPayload;
|
||||
i64 rowid;
|
||||
@@ -677,7 +676,7 @@ static void page_usage_report(const char *zDbName){
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
int pgno = sqlite3_column_int(pStmt, 2);
|
||||
page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
|
||||
page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1));
|
||||
}
|
||||
}else{
|
||||
printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
|
||||
@@ -835,7 +834,6 @@ int main(int argc, char **argv){
|
||||
free(a);
|
||||
continue;
|
||||
}else if( zLeft && zLeft[0]=='t' ){
|
||||
unsigned char *a;
|
||||
int detail = 0;
|
||||
int recursive = 0;
|
||||
int i;
|
||||
@@ -861,4 +859,5 @@ int main(int argc, char **argv){
|
||||
}
|
||||
}
|
||||
close(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user