Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b2f6fa20a | |||
| faa18c354b | |||
| d81158dc32 | |||
| d49eabfaa6 | |||
| 4dd9004289 | |||
| 968067d282 | |||
| 6bebbb6a2d | |||
| 94c4553f48 | |||
| 1f47b2aaa5 | |||
| 57ad53ada4 | |||
| b94664711b | |||
| 6d51243979 | |||
| 7fdaca40b7 | |||
| 2a3489ae82 | |||
| 5fba856bbf | |||
| 052153994b | |||
| c844fac64d | |||
| a3c79ae7cd | |||
| f87f9c240f | |||
| a74480a217 | |||
| 19dbfa8adc |
@@ -508,6 +508,10 @@ dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h
|
||||
$(TCCX) -o dbhash$(EXE) -DSQLITE_THREADSAFE=0 \
|
||||
$(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB)
|
||||
|
||||
faststat1$(EXE): $(TOP)/tool/faststat1.c sqlite3.c sqlite3.h
|
||||
$(TCCX) -o faststat1$(EXE) -DSQLITE_THREADSAFE=0 \
|
||||
$(TOP)/tool/faststat1.c sqlite3.c $(TLIBS) $(THREADLIB)
|
||||
|
||||
scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o
|
||||
$(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Use\sthe\supdated\sWin32\sVFS\ssemantics\sfor\swinOpen\sfrom\scheck-in\s[5d03c738e9]\sfor\sWinRT,\set\sal,\sas\swell.
|
||||
D 2017-09-22T16:23:23.946
|
||||
C Merge\sin\sall\sthe\strunk\senhancements\sof\sthe\sprevious\s7\smonths.\s\sThe\sLIKE\noptimization\shas\sstopped\sworking\swhen\sthere\sis\san\sESCAPE\s-\sthat\sproblem\swill\nbe\saddressed\sin\sa\ssubsequent\scheck-in.
|
||||
D 2017-09-22T20:18:41.272
|
||||
F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f
|
||||
@@ -36,7 +36,7 @@ F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 278113807f49d12d04179a93fab92b5b917a08771152ca7949d34e928efa3941
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
|
||||
F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd w ext/README.txt
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
|
||||
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
|
||||
@@ -382,7 +382,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk d0145f02deb67d65c4822225847cba112c237cdb62f4905eeb4b648e82bfc222
|
||||
F main.mk 018c64f868af7027c22d7e39ee94e3826f86db53b111ce402bd6bd188e7e0fec
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -401,10 +401,10 @@ F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 1c2b2f1714c411d7a9bc52c90d9dd7eab261261d5691ac0f67e1ced92419799c
|
||||
F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
|
||||
F src/btree.c 9c273587506a42f1961840b7bf423a3bfe0783a04cba707e792dec4db637b9ff
|
||||
F src/btree.h 90eae6df0e4e9aada570980f7b0473a6f705b563bd49183b9adeebd278d8e3db
|
||||
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
|
||||
F src/build.c e71e96a67daf3d1dd23188423e66cd6af38017e2ec73fead5d2b57da2d3c7e16
|
||||
F src/build.c ff2ea9709d2cfb83ad8caee97541a89d099f46b46ff4ec278bf5e55824c6f99d
|
||||
F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
||||
@@ -447,12 +447,12 @@ F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 2aa56a99bb13128d9102e84c7a9f835e546cbb58f0861d481bc3db32973b1628
|
||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||
F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
|
||||
F src/parse.y 6fa01cadb6c1d29ce623bbb5f4001f92962d171e41dcdcd4d05ef0509f5ceabe
|
||||
F src/pcache.c 4bada070456980c3c1f16d58ec2e64e389ad77b935e3d77e0c96e7bbd397289c
|
||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||
F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602
|
||||
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
|
||||
F src/pragma.c 9f8839691c075f367679a5b8fcf145e1c24fc0c685ef75d253ad7a47ab8d0950
|
||||
F src/pragma.h aaf1207923ec3524346e53c912eb7990bd4bed8798a78193bd6a51adce95252a
|
||||
F src/prepare.c 9a141a1b02dca53beaa9771699d390aafcac01f5d1f1c0ae6e23ded8dcdb709a
|
||||
F src/printf.c 40aee47ae9be4bd3dbdc8968bd07fddc027be8edec8daddf24d3391d36698a1c
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
@@ -464,7 +464,7 @@ F src/shell.c.in bb9720a8c5c98d3984b16ab7540e7142bcae959666ecf248bfc523a1d44220e
|
||||
F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
|
||||
F src/sqliteInt.h 12aa1f626b3209ffa6a50d9d1e6b4235abd33273a0fcbfeedb66f573a68932b9
|
||||
F src/sqliteInt.h 8943d3b3f9ebd4ffb6a8f0d4b52cd28f523f1c2f7cc422909b0b3d5644aeca49
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@@ -526,7 +526,7 @@ F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
|
||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||
F src/util.c 5168013cfd937a695d23cce8c67cb07a3dda242d4cb812530ba1148b88e0f159
|
||||
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
||||
F src/vdbe.c 176c0897af0aedecd3abc9afaf7fa80eaa7cf5eaf62583de256a9961df474373
|
||||
F src/vdbe.c 1c0a8c8e65e0a7b6289f66d6775b0293b849b3ee461691ec1b55c2e78121029e
|
||||
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
|
||||
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
|
||||
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
|
||||
@@ -1551,7 +1551,7 @@ F test/with1.test 732e3ef398dcecb609839cd5ef0cb63beb2a9eff31420f3b745fc55b9e85b6
|
||||
F test/with2.test 2b40da883658eb74ad8ad06afabe11a408e7fb87
|
||||
F test/with3.test e71604a0e53cba82bc04c703987cb1d6751ec0b6
|
||||
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
|
||||
F test/without_rowid1.test 06b7215130882d6a072233820dd364c874c4fd69221e8fc756ec471009192874
|
||||
F test/without_rowid1.test aafbe8b016e190cf23c5bec0708349e0ea9b0a060f3edfd48e4d6e8db82e015a
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test 2724c787a51a5dce09d078453a758117b4b728f1
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
@@ -1572,6 +1572,7 @@ F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5
|
||||
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
|
||||
F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1
|
||||
F tool/faststat1.c 67637f03dced49951f1021bfdc95aa9ffadbe871
|
||||
F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
|
||||
F tool/fuzzershell.c e1d90a03ca790d7c331c2aae08ca46ff435f1ae1faa6cb9cc48f4687c18fdc6e
|
||||
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
|
||||
@@ -1591,7 +1592,7 @@ F tool/mkmsvcmin.tcl cbd93f1cfa3a0a9ae56fc958510aa3fc3ac65e29cb111716199e3d0e66e
|
||||
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
|
||||
F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
|
||||
F tool/mkpragmatab.tcl 0ee82c05406f7fb218eb4ad0b557596d0148aac24507f7971d75f6417ad92802
|
||||
F tool/mkshellc.tcl 950c36f45941c12140e346a907fb66198bc2770ff7a17c749201e78d34bb3b0b
|
||||
F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
@@ -1655,7 +1656,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 403b88a894d877b85bcc33133abad06c3c576e4928de4a4b0c091f74c4015355
|
||||
R 7f08f0df04c939d1dd5a187c9ae3cc49
|
||||
U mistachkin
|
||||
Z 321f82ff3326ba269549cfe661409f34
|
||||
P 325ccfa95e3afed2dc6849d6b05d81f0203bf73e 2c03d8b8f028b6a736aaf2cf8b28a51b3434cf341c95cf3a80469e0a24acdd98
|
||||
R 9c70c731081fc8d935ffa7f95aaf0d4e
|
||||
U drh
|
||||
Z c1e4e80ea16b3e736eda73c5e9d93cfe
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2c03d8b8f028b6a736aaf2cf8b28a51b3434cf341c95cf3a80469e0a24acdd98
|
||||
8d2a1cca613f75fb4b1a050cf7ea03b74a4d98f4c56d8079201035d7fdc49e85
|
||||
+67
@@ -5150,6 +5150,73 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the cursor pCur to a location within its b-tree that is
|
||||
** approximately the x/1e9*nRow entry in the table, assuming the
|
||||
** table contains nRow entries. So, in other words, if x==0 move
|
||||
** to the first entry and if x=1e9 move to the last entry and if
|
||||
** x=5e8 move to the middle entry. The final landing spot is
|
||||
** approximate.
|
||||
**
|
||||
** Write an estimate of the number of entries in the b-tree into
|
||||
** the *pnRowEst variable.
|
||||
**
|
||||
** This routine works by first moving the cursor to the root of the
|
||||
** b-tree, then following pointers down to a leaf, selecting a pointer
|
||||
** according to x.
|
||||
**
|
||||
** The estimated number of entries is found by multiplying the number of
|
||||
** entries on the leaf page by the number of pointers at each layer of
|
||||
** non-leaf pages.
|
||||
**
|
||||
** Return SQLITE_OK on success or an error code if problems are encountered.
|
||||
*/
|
||||
int sqlite3BtreeMovetoProportional(
|
||||
BtCursor *pCur, /* Cursor to reposition */
|
||||
u32 x, /* approximate location to position the cursor */
|
||||
sqlite3_uint64 *pnRowEst /* Write estimated entry count here */
|
||||
){
|
||||
sqlite3_uint64 n = 1;
|
||||
int rc;
|
||||
Pgno chldPg;
|
||||
u32 mx = 1000000000;
|
||||
u32 perChild;
|
||||
u16 rx;
|
||||
MemPage *pPage;
|
||||
rc = moveToRoot(pCur);
|
||||
if( rc ) return rc;
|
||||
pPage = pCur->apPage[0];
|
||||
while( !pPage->leaf ){
|
||||
perChild = (mx+pPage->nCell)/(pPage->nCell+1);
|
||||
if( perChild<1 ) perChild = 1;
|
||||
rx = x/perChild;
|
||||
x %= perChild;
|
||||
mx = perChild;
|
||||
if( rx>=pPage->nCell ){
|
||||
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage,rx));
|
||||
}
|
||||
n *= pPage->nCell+1;
|
||||
pCur->aiIdx[pCur->iPage] = rx;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) return rc;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
}
|
||||
*pnRowEst = n*pPage->nCell;
|
||||
if( pPage->nCell==0 ){
|
||||
rx = 0;
|
||||
}else{
|
||||
perChild = mx/pPage->nCell;
|
||||
if( perChild<1 ) perChild = 1;
|
||||
rx = x/perChild;
|
||||
if( rx>=pPage->nCell ) rx = pPage->nCell-1;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = rx;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Move the cursor so that it points to an entry near the key
|
||||
** specified by pIdxKey or intKey. Return a success code.
|
||||
**
|
||||
|
||||
@@ -239,6 +239,7 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...);
|
||||
#endif
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMovetoProportional(BtCursor*,u32,u64*);
|
||||
int sqlite3BtreeMovetoUnpacked(
|
||||
BtCursor*,
|
||||
UnpackedRecord *pUnKey,
|
||||
|
||||
+17
-4
@@ -3603,12 +3603,21 @@ void *sqlite3ArrayAllocate(
|
||||
** need be.
|
||||
**
|
||||
** A new IdList is returned, or NULL if malloc() fails.
|
||||
**
|
||||
** The zName must have been obtained from sqlite3DbMalloc(). This routine
|
||||
** accepts ownership of the zName string and will ensure that it is freed
|
||||
** when no longer in use.
|
||||
*/
|
||||
IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
||||
IdList *sqlite3IdListAppend(
|
||||
Parse *pParse, /* Parsing context */
|
||||
IdList *pList, /* ID list to append to */
|
||||
char *zName /* Token to append */
|
||||
){
|
||||
int i;
|
||||
sqlite3 *db = pParse->db;
|
||||
if( pList==0 ){
|
||||
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
||||
if( pList==0 ) return 0;
|
||||
if( pList==0 ) goto id_list_append_fail;
|
||||
}
|
||||
pList->a = sqlite3ArrayAllocate(
|
||||
db,
|
||||
@@ -3619,10 +3628,14 @@ IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
|
||||
);
|
||||
if( i<0 ){
|
||||
sqlite3IdListDelete(db, pList);
|
||||
return 0;
|
||||
goto id_list_append_fail;
|
||||
}
|
||||
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
||||
pList->a[i].zName = zName;
|
||||
return pList;
|
||||
|
||||
id_list_append_fail:
|
||||
sqlite3DbFree(db, zName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+35
-22
@@ -246,11 +246,15 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
|
||||
%left COLLATE.
|
||||
%right BITNOT.
|
||||
|
||||
// An IDENTIFIER can be a generic identifier, or one of several
|
||||
// An "id" can be a generic identifier, or one of several
|
||||
// keywords. Any non-standard keyword can also be an identifier.
|
||||
//
|
||||
%token_class id ID|INDEXED.
|
||||
|
||||
// A "number" can be either an integer or a floating point value
|
||||
%token_class number INTEGER|FLOAT.
|
||||
|
||||
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
//
|
||||
@@ -279,8 +283,8 @@ typetoken(A) ::= typename(A) LP signed COMMA signed RP(Y). {
|
||||
%type typename {Token}
|
||||
typename(A) ::= ids(A).
|
||||
typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);}
|
||||
signed ::= plus_num.
|
||||
signed ::= minus_num.
|
||||
signed ::= PLUS|MINUS number.
|
||||
signed ::= number.
|
||||
|
||||
// "carglist" is a list of additional constraints that come after the
|
||||
// column name and column type in a CREATE TABLE statement.
|
||||
@@ -832,12 +836,13 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
|
||||
%type idlist {IdList*}
|
||||
%destructor idlist {sqlite3IdListDelete(pParse->db, $$);}
|
||||
|
||||
idlist_opt(A) ::= . {A = 0;}
|
||||
idlist_opt(A) ::= . {A = 0;}
|
||||
idlist_opt(A) ::= LP idlist(X) RP. {A = X;}
|
||||
idlist(A) ::= idlist(A) COMMA nm(Y).
|
||||
{A = sqlite3IdListAppend(pParse->db,A,&Y);}
|
||||
{A = sqlite3IdListAppend(pParse,A,sqlite3NameFromToken(pParse->db,&Y));}
|
||||
idlist(A) ::= nm(Y).
|
||||
{A = sqlite3IdListAppend(pParse->db,0,&Y); /*A-overwrites-Y*/}
|
||||
{A = sqlite3IdListAppend(pParse,0,sqlite3NameFromToken(pParse->db,&Y));
|
||||
/*A-overwrites-Y*/}
|
||||
|
||||
/////////////////////////// Expression Processing /////////////////////////////
|
||||
//
|
||||
@@ -1348,24 +1353,32 @@ cmd ::= VACUUM nm(X). {sqlite3Vacuum(pParse,&X);}
|
||||
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_PRAGMA
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y).
|
||||
{sqlite3Pragma(pParse,&X,&Z,&Y,1);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP.
|
||||
{sqlite3Pragma(pParse,&X,&Z,&Y,1);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) EQ pragma_arglist(Y).
|
||||
{sqlite3Pragma(pParse,&X,&Z,Y);}
|
||||
cmd ::= PRAGMA nm(X) dbnm(Z) LP pragma_arglist(Y) RP.
|
||||
{sqlite3Pragma(pParse,&X,&Z,Y);}
|
||||
|
||||
%type pragma_arglist {IdList*}
|
||||
%destructor pragma_arglist {sqlite3IdListDelete(pParse->db,$$);}
|
||||
|
||||
pragma_arglist(A) ::= pragma_arg(X).
|
||||
{ A = sqlite3IdListAppend(pParse,0,X)/*A-overwrites-X*/; }
|
||||
pragma_arglist(A) ::= pragma_arglist(A) COMMA pragma_arg(Y).
|
||||
{ A = sqlite3IdListAppend(pParse,A,Y); }
|
||||
|
||||
%type pragma_arg {char*}
|
||||
%destructor pragma_arg {sqlite3DbFree(pParse->db,$$);}
|
||||
pragma_arg(A) ::= number(X).
|
||||
{A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/}
|
||||
pragma_arg(A) ::= nm(X).
|
||||
{A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/}
|
||||
pragma_arg(A) ::= ON|DELETE|DEFAULT(X).
|
||||
{A = sqlite3NameFromToken(pParse->db,&X);/*A-overwrites-X*/}
|
||||
pragma_arg(A) ::= PLUS number(X). {A = sqlite3NameFromToken(pParse->db,&X);}
|
||||
pragma_arg(A) ::= MINUS number(X). {A = sqlite3MPrintf(pParse->db,"-%T",&X);}
|
||||
|
||||
nmnum(A) ::= plus_num(A).
|
||||
nmnum(A) ::= nm(A).
|
||||
nmnum(A) ::= ON(A).
|
||||
nmnum(A) ::= DELETE(A).
|
||||
nmnum(A) ::= DEFAULT(A).
|
||||
%endif SQLITE_OMIT_PRAGMA
|
||||
%token_class number INTEGER|FLOAT.
|
||||
plus_num(A) ::= PLUS number(X). {A = X;}
|
||||
plus_num(A) ::= number(A).
|
||||
minus_num(A) ::= MINUS number(X). {A = X;}
|
||||
//////////////////////////// The CREATE TRIGGER command /////////////////////
|
||||
|
||||
%ifndef SQLITE_OMIT_TRIGGER
|
||||
|
||||
+139
-17
@@ -316,11 +316,7 @@ static int integrityCheckResultRow(Vdbe *v){
|
||||
**
|
||||
** Pragmas are of this form:
|
||||
**
|
||||
** PRAGMA [schema.]id [= value]
|
||||
**
|
||||
** The identifier might also be a string. The value is a string, and
|
||||
** identifier, or a number. If minusFlag is true, then the value is
|
||||
** a number that was preceded by a minus sign.
|
||||
** PRAGMA [schema.]id [= value-list]
|
||||
**
|
||||
** If the left side is "database.id" then pId1 is the database name
|
||||
** and pId2 is the id. If the left side is just "id" then pId1 is the
|
||||
@@ -330,8 +326,7 @@ void sqlite3Pragma(
|
||||
Parse *pParse,
|
||||
Token *pId1, /* First part of [schema.]id field */
|
||||
Token *pId2, /* Second part of [schema.]id field, or NULL */
|
||||
Token *pValue, /* Token for <value>, or NULL */
|
||||
int minusFlag /* True if a '-' sign preceded <value> */
|
||||
IdList *pValues /* The value-list arguments. NULL if omitted */
|
||||
){
|
||||
char *zLeft = 0; /* Nul-terminated UTF-8 string <id> */
|
||||
char *zRight = 0; /* Nul-terminated UTF-8 string <value>, or NULL */
|
||||
@@ -345,30 +340,26 @@ void sqlite3Pragma(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
|
||||
const PragmaName *pPragma; /* The pragma */
|
||||
|
||||
if( v==0 ) return;
|
||||
if( v==0 ) goto pragma_out;
|
||||
sqlite3VdbeRunOnlyOnce(v);
|
||||
pParse->nMem = 2;
|
||||
|
||||
/* Interpret the [schema.] part of the pragma statement. iDb is the
|
||||
** index of the database this pragma is being applied to in db.aDb[]. */
|
||||
iDb = sqlite3TwoPartName(pParse, pId1, pId2, &pId);
|
||||
if( iDb<0 ) return;
|
||||
if( iDb<0 ) goto pragma_out;
|
||||
pDb = &db->aDb[iDb];
|
||||
|
||||
/* If the temp database has been explicitly named as part of the
|
||||
** pragma, make sure it is open.
|
||||
*/
|
||||
if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
|
||||
return;
|
||||
goto pragma_out;
|
||||
}
|
||||
|
||||
zLeft = sqlite3NameFromToken(db, pId);
|
||||
if( !zLeft ) return;
|
||||
if( minusFlag ){
|
||||
zRight = sqlite3MPrintf(db, "-%T", pValue);
|
||||
}else{
|
||||
zRight = sqlite3NameFromToken(db, pValue);
|
||||
}
|
||||
if( !zLeft ) goto pragma_out;
|
||||
if( pValues ) zRight = pValues->a[0].zName;
|
||||
|
||||
assert( pId2 );
|
||||
zDb = pId2->n>0 ? pDb->zDbSName : 0;
|
||||
@@ -1148,6 +1139,10 @@ void sqlite3Pragma(
|
||||
Index *pIdx;
|
||||
Table *pTab;
|
||||
pIdx = sqlite3FindIndex(db, zRight, zDb);
|
||||
if( pIdx==0 ){
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab);
|
||||
}
|
||||
if( pIdx ){
|
||||
int i;
|
||||
int mx;
|
||||
@@ -1434,6 +1429,133 @@ void sqlite3Pragma(
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
** PRAGMA est_row_cnt(<table-or-index>,<fraction>);
|
||||
**
|
||||
** Seek in <table-or-index> through the first <fraction> of rows and
|
||||
** estimate the total number of rows based on the path back up to the
|
||||
** root.
|
||||
*/
|
||||
case PragTyp_EST_COUNT: {
|
||||
Index *pIdx;
|
||||
Table *pTab = 0;
|
||||
Pgno iRoot = 0;
|
||||
const char *zName = 0;
|
||||
int regResult;
|
||||
double r;
|
||||
if( (pIdx = sqlite3FindIndex(db, zRight, zDb))!=0 ){
|
||||
iRoot = pIdx->tnum;
|
||||
zName = pIdx->zName;
|
||||
}else if( (pTab = sqlite3FindTable(db, zRight, zDb))!=0 ){
|
||||
zName = pTab->zName;
|
||||
if( HasRowid(pTab) ){
|
||||
iRoot = pTab->tnum;
|
||||
}else{
|
||||
pIdx = sqlite3PrimaryKeyIndex(pTab);
|
||||
iRoot = pIdx->tnum;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
sqlite3TableLock(pParse, iDb, iRoot, 0, zName);
|
||||
regResult = ++pParse->nMem;
|
||||
if( pValues->nId>=2 ){
|
||||
const char *z = pValues->a[1].zName;
|
||||
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
}else{
|
||||
r = 0.5;
|
||||
}
|
||||
if( r<0.0 ) r = 0.0;
|
||||
if( r>1.0 ) r = 1.0;
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
pParse->nTab++;
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenRead, 0, iRoot, iDb, 1);
|
||||
if( pIdx ) sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
sqlite3VdbeAddOp3(v, OP_EstRowCnt, 0, regResult, (int)(r*1000000000));
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
** PRAGMA btree_sample(<table-or-index>,<fraction>,<limit>);
|
||||
**
|
||||
** Seek in <table-or-index> through the first <fraction> of rows and
|
||||
** then begin returning rows, one by one. A max of <limit> rows will
|
||||
** be returned.
|
||||
*/
|
||||
case PragTyp_BTREE_SAMPLE: {
|
||||
Index *pIdx;
|
||||
Table *pTab = 0;
|
||||
Pgno iRoot = 0;
|
||||
Pgno iLock = 0;
|
||||
int nCol = 0;
|
||||
const char *zName = 0;
|
||||
int iLimit = 10;
|
||||
int i;
|
||||
int regResult;
|
||||
int regLimit;
|
||||
int addrTop;
|
||||
int addrJmp;
|
||||
int addrSkip;
|
||||
double r;
|
||||
if( (pIdx = sqlite3FindIndex(db, zRight, zDb))!=0 ){
|
||||
iRoot = pIdx->tnum;
|
||||
iLock = pIdx->pTable->tnum;
|
||||
zName = pIdx->zName;
|
||||
nCol = pIdx->nColumn;
|
||||
}else if( (pTab = sqlite3FindTable(db, zRight, zDb))!=0 ){
|
||||
zName = pTab->zName;
|
||||
if( HasRowid(pTab) ){
|
||||
iLock = iRoot = pTab->tnum;
|
||||
nCol = pTab->nCol;
|
||||
}else{
|
||||
pIdx = sqlite3PrimaryKeyIndex(pTab);
|
||||
iLock = iRoot = pIdx->tnum;
|
||||
nCol = pIdx->nColumn;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
sqlite3VdbeSetNumCols(v, nCol);
|
||||
for(i=0; i<nCol; i++){
|
||||
char zCol[30];
|
||||
sqlite3_snprintf(sizeof(zCol),zCol,"c%06d",i);
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
|
||||
}
|
||||
if( pValues->nId>=2 ){
|
||||
const char *z = pValues->a[1].zName;
|
||||
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
}else{
|
||||
r = 0.5;
|
||||
}
|
||||
if( r<0.0 ) r = 0.0;
|
||||
if( r>1.0 ) r = 1.0;
|
||||
if( pValues->nId>=3 ){
|
||||
iLimit = sqlite3Atoi(pValues->a[2].zName);
|
||||
}
|
||||
pParse->nTab++;
|
||||
sqlite3TableLock(pParse, iDb, iLock, 0, zName);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3VdbeAddOp4Int(v, OP_OpenRead, 0, iRoot, iDb, nCol);
|
||||
if( pIdx ) sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
regLimit = ++pParse->nMem;
|
||||
regResult = pParse->nMem+1;
|
||||
pParse->nMem += nCol;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, iLimit, regLimit);
|
||||
addrSkip = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_EstRowCnt, 0, regResult, (int)(r*1000000000));
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, 0, i, regResult+i);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nCol);
|
||||
addrJmp = sqlite3VdbeAddOp1(v, OP_DecrJumpZero, regLimit); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addrJmp);
|
||||
sqlite3VdbeJumpHere(v, addrSkip);
|
||||
}
|
||||
break;
|
||||
|
||||
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
||||
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
|
||||
#endif
|
||||
@@ -2171,7 +2293,7 @@ void sqlite3Pragma(
|
||||
|
||||
pragma_out:
|
||||
sqlite3DbFree(db, zLeft);
|
||||
sqlite3DbFree(db, zRight);
|
||||
sqlite3IdListDelete(db, pValues);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/*****************************************************************************
|
||||
|
||||
+57
-45
@@ -8,50 +8,52 @@
|
||||
#define PragTyp_HEADER_VALUE 0
|
||||
#define PragTyp_AUTO_VACUUM 1
|
||||
#define PragTyp_FLAG 2
|
||||
#define PragTyp_BUSY_TIMEOUT 3
|
||||
#define PragTyp_CACHE_SIZE 4
|
||||
#define PragTyp_CACHE_SPILL 5
|
||||
#define PragTyp_CASE_SENSITIVE_LIKE 6
|
||||
#define PragTyp_COLLATION_LIST 7
|
||||
#define PragTyp_COMPILE_OPTIONS 8
|
||||
#define PragTyp_DATA_STORE_DIRECTORY 9
|
||||
#define PragTyp_DATABASE_LIST 10
|
||||
#define PragTyp_DEFAULT_CACHE_SIZE 11
|
||||
#define PragTyp_ENCODING 12
|
||||
#define PragTyp_FOREIGN_KEY_CHECK 13
|
||||
#define PragTyp_FOREIGN_KEY_LIST 14
|
||||
#define PragTyp_FUNCTION_LIST 15
|
||||
#define PragTyp_INCREMENTAL_VACUUM 16
|
||||
#define PragTyp_INDEX_INFO 17
|
||||
#define PragTyp_INDEX_LIST 18
|
||||
#define PragTyp_INTEGRITY_CHECK 19
|
||||
#define PragTyp_JOURNAL_MODE 20
|
||||
#define PragTyp_JOURNAL_SIZE_LIMIT 21
|
||||
#define PragTyp_LOCK_PROXY_FILE 22
|
||||
#define PragTyp_LOCKING_MODE 23
|
||||
#define PragTyp_PAGE_COUNT 24
|
||||
#define PragTyp_MMAP_SIZE 25
|
||||
#define PragTyp_MODULE_LIST 26
|
||||
#define PragTyp_OPTIMIZE 27
|
||||
#define PragTyp_PAGE_SIZE 28
|
||||
#define PragTyp_PRAGMA_LIST 29
|
||||
#define PragTyp_SECURE_DELETE 30
|
||||
#define PragTyp_SHRINK_MEMORY 31
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 32
|
||||
#define PragTyp_SYNCHRONOUS 33
|
||||
#define PragTyp_TABLE_INFO 34
|
||||
#define PragTyp_TEMP_STORE 35
|
||||
#define PragTyp_TEMP_STORE_DIRECTORY 36
|
||||
#define PragTyp_THREADS 37
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 38
|
||||
#define PragTyp_WAL_CHECKPOINT 39
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 40
|
||||
#define PragTyp_HEXKEY 41
|
||||
#define PragTyp_KEY 42
|
||||
#define PragTyp_REKEY 43
|
||||
#define PragTyp_LOCK_STATUS 44
|
||||
#define PragTyp_PARSER_TRACE 45
|
||||
#define PragTyp_STATS 46
|
||||
#define PragTyp_BTREE_SAMPLE 3
|
||||
#define PragTyp_BUSY_TIMEOUT 4
|
||||
#define PragTyp_CACHE_SIZE 5
|
||||
#define PragTyp_CACHE_SPILL 6
|
||||
#define PragTyp_CASE_SENSITIVE_LIKE 7
|
||||
#define PragTyp_COLLATION_LIST 8
|
||||
#define PragTyp_COMPILE_OPTIONS 9
|
||||
#define PragTyp_DATA_STORE_DIRECTORY 10
|
||||
#define PragTyp_DATABASE_LIST 11
|
||||
#define PragTyp_DEFAULT_CACHE_SIZE 12
|
||||
#define PragTyp_ENCODING 13
|
||||
#define PragTyp_EST_COUNT 14
|
||||
#define PragTyp_FOREIGN_KEY_CHECK 15
|
||||
#define PragTyp_FOREIGN_KEY_LIST 16
|
||||
#define PragTyp_FUNCTION_LIST 17
|
||||
#define PragTyp_INCREMENTAL_VACUUM 18
|
||||
#define PragTyp_INDEX_INFO 19
|
||||
#define PragTyp_INDEX_LIST 20
|
||||
#define PragTyp_INTEGRITY_CHECK 21
|
||||
#define PragTyp_JOURNAL_MODE 22
|
||||
#define PragTyp_JOURNAL_SIZE_LIMIT 23
|
||||
#define PragTyp_LOCK_PROXY_FILE 24
|
||||
#define PragTyp_LOCKING_MODE 25
|
||||
#define PragTyp_PAGE_COUNT 26
|
||||
#define PragTyp_MMAP_SIZE 27
|
||||
#define PragTyp_MODULE_LIST 28
|
||||
#define PragTyp_OPTIMIZE 29
|
||||
#define PragTyp_PAGE_SIZE 30
|
||||
#define PragTyp_PRAGMA_LIST 31
|
||||
#define PragTyp_SECURE_DELETE 32
|
||||
#define PragTyp_SHRINK_MEMORY 33
|
||||
#define PragTyp_SOFT_HEAP_LIMIT 34
|
||||
#define PragTyp_SYNCHRONOUS 35
|
||||
#define PragTyp_TABLE_INFO 36
|
||||
#define PragTyp_TEMP_STORE 37
|
||||
#define PragTyp_TEMP_STORE_DIRECTORY 38
|
||||
#define PragTyp_THREADS 39
|
||||
#define PragTyp_WAL_AUTOCHECKPOINT 40
|
||||
#define PragTyp_WAL_CHECKPOINT 41
|
||||
#define PragTyp_ACTIVATE_EXTENSIONS 42
|
||||
#define PragTyp_HEXKEY 43
|
||||
#define PragTyp_KEY 44
|
||||
#define PragTyp_REKEY 45
|
||||
#define PragTyp_LOCK_STATUS 46
|
||||
#define PragTyp_PARSER_TRACE 47
|
||||
#define PragTyp_STATS 48
|
||||
|
||||
/* Property flags associated with various pragma. */
|
||||
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
|
||||
@@ -162,6 +164,11 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_AutoIndex },
|
||||
#endif
|
||||
#endif
|
||||
{/* zName: */ "btree_sample",
|
||||
/* ePragTyp: */ PragTyp_BTREE_SAMPLE,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
{/* zName: */ "busy_timeout",
|
||||
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
|
||||
/* ePragFlg: */ PragFlg_Result0,
|
||||
@@ -270,6 +277,11 @@ static const PragmaName aPragmaName[] = {
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#endif
|
||||
{/* zName: */ "est_count",
|
||||
/* ePragTyp: */ PragTyp_EST_COUNT,
|
||||
/* ePragFlg: */ PragFlg_NeedSchema,
|
||||
/* ColNames: */ 0, 0,
|
||||
/* iArg: */ 0 },
|
||||
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
||||
{/* zName: */ "foreign_key_check",
|
||||
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
||||
@@ -646,4 +658,4 @@ static const PragmaName aPragmaName[] = {
|
||||
/* iArg: */ SQLITE_WriteSchema },
|
||||
#endif
|
||||
};
|
||||
/* Number of pragmas: 60 on by default, 77 total. */
|
||||
/* Number of pragmas: 62 on by default, 79 total. */
|
||||
|
||||
+2
-2
@@ -3642,7 +3642,7 @@ void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
||||
u32 sqlite3ExprListFlags(const ExprList*);
|
||||
int sqlite3Init(sqlite3*, char**);
|
||||
int sqlite3InitCallback(void*, int, char**, char**);
|
||||
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
|
||||
void sqlite3Pragma(Parse*,Token*,Token*,IdList*);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
|
||||
#endif
|
||||
@@ -3720,7 +3720,7 @@ void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
#endif
|
||||
void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int);
|
||||
void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
||||
IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
|
||||
IdList *sqlite3IdListAppend(Parse*, IdList*, char*);
|
||||
int sqlite3IdListIndex(IdList*,const char*);
|
||||
SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
|
||||
SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
|
||||
|
||||
+28
@@ -4967,6 +4967,34 @@ case OP_Rewind: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Opcode: EstRowCnt P1 P2 P3 * * *
|
||||
**
|
||||
** Estimate the number of entries in btree for cursor P1 do a proportional
|
||||
** seek to of P3. Store the result as a floating point value in P2.
|
||||
*/
|
||||
case OP_EstRowCnt: { /* out2 */
|
||||
VdbeCursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
int rc;
|
||||
sqlite3_uint64 n = 0;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeMovetoProportional(pCrsr, pOp->p3, &n);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
pOut = out2Prerelease(p, pOp);
|
||||
pOut->flags = MEM_Real;
|
||||
pOut->u.r = n;
|
||||
pC->nullRow = 0;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 P3 P4 P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
|
||||
@@ -328,19 +328,36 @@ do_catchsql_test 7.3 {
|
||||
) WITHOUT ROWID;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# The PRAGMA index_info and index_xinfo pragmas work on
|
||||
# WITHOUT ROWID tables too, but not on rowid tables.
|
||||
#
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t80a(a TEXT, b INT, c BLOB, PRIMARY KEY(c,b));
|
||||
PRAGMA index_info(t80a);
|
||||
} {}
|
||||
do_execsql_test 8.2 {
|
||||
PRAGMA index_xinfo(t80a);
|
||||
} {}
|
||||
do_execsql_test 8.3 {
|
||||
CREATE TABLE t80b(a TEXT, b INT, c BLOB, PRIMARY KEY(c,b)) WITHOUT ROWID;
|
||||
PRAGMA index_info(t80b);
|
||||
} {0 2 c 1 1 b}
|
||||
do_execsql_test 8.4 {
|
||||
PRAGMA index_xinfo(t80b);
|
||||
} {0 2 c 0 BINARY 1 1 1 b 0 BINARY 1 2 0 a 0 BINARY 0}
|
||||
|
||||
|
||||
# 2017-07-30: OSSFuzz discovered that an extra entry was being
|
||||
# added in the sqlite_master table for an "INTEGER PRIMARY KEY UNIQUE"
|
||||
# WITHOUT ROWID table. Make sure this has now been fixed.
|
||||
#
|
||||
db close
|
||||
sqlite3 db :memory:
|
||||
do_execsql_test 8.1 {
|
||||
do_execsql_test 9.1 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY UNIQUE, b) WITHOUT ROWID;
|
||||
CREATE INDEX t1x ON t1(x);
|
||||
INSERT INTO t1(x,b) VALUES('funny','buffalo');
|
||||
SELECT type, name, '|' FROM sqlite_master;
|
||||
} {table t1 | index t1x |}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
** 2016-10-24
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This is a utility program that uses the est_count and btree_sample
|
||||
** pragmas to try to approximate the content of the sqlite_stat1 table
|
||||
** without doing a full table scan.
|
||||
**
|
||||
** To compile, simply link against SQLite.
|
||||
**
|
||||
** See the showHelp() routine below for a brief description of how to
|
||||
** run the utility.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** All global variables are gathered into the "g" singleton.
|
||||
*/
|
||||
struct GlobalVars {
|
||||
const char *zArgv0; /* Name of program */
|
||||
unsigned fDebug; /* Debug flags */
|
||||
sqlite3 *db; /* The database connection */
|
||||
} g;
|
||||
|
||||
/*
|
||||
** Allowed values for g.fDebug
|
||||
*/
|
||||
#define DEBUG_NONE 0
|
||||
|
||||
|
||||
/*
|
||||
** Print an error resulting from faulting command-line arguments and
|
||||
** abort the program.
|
||||
*/
|
||||
static void cmdlineError(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
fprintf(stderr, "%s: ", g.zArgv0);
|
||||
va_start(ap, zFormat);
|
||||
vfprintf(stderr, zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Print an error message for an error that occurs at runtime, then
|
||||
** abort the program.
|
||||
*/
|
||||
static void runtimeError(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
fprintf(stderr, "%s: ", g.zArgv0);
|
||||
va_start(ap, zFormat);
|
||||
vfprintf(stderr, zFormat, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current time in milliseconds since the julian epoch.
|
||||
*/
|
||||
static sqlite3_int64 currentTime(void){
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
||||
sqlite3_int64 x = 0;
|
||||
(void)pVfs->xCurrentTimeInt64(pVfs, &x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
** Prepare a new SQL statement. Print an error and abort if anything
|
||||
** goes wrong.
|
||||
*/
|
||||
static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){
|
||||
char *zSql;
|
||||
int rc;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
if( zSql==0 ) runtimeError("out of memory");
|
||||
rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0);
|
||||
if( rc ){
|
||||
runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db),
|
||||
zSql);
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
return pStmt;
|
||||
}
|
||||
static sqlite3_stmt *db_prepare(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
sqlite3_stmt *pStmt;
|
||||
va_start(ap, zFormat);
|
||||
pStmt = db_vprepare(zFormat, ap);
|
||||
va_end(ap);
|
||||
return pStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Estimate the number of rows in the given table or index.
|
||||
*/
|
||||
static sqlite3_int64 estEntryCount(const char *zTabIdx){
|
||||
double sum = 0.0;
|
||||
int i;
|
||||
int n = 0;
|
||||
sqlite3_stmt *pStmt;
|
||||
# define N_CNT_SAMPLE 10
|
||||
for(i=0; i<=N_CNT_SAMPLE; i++){
|
||||
pStmt = db_prepare("PRAGMA est_count(\"%w\",%g)",
|
||||
zTabIdx, ((double)i)/(double)(N_CNT_SAMPLE));
|
||||
if( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
sum += sqlite3_column_double(pStmt, 0);
|
||||
n++;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
}
|
||||
return n==0 ? 0 : (sqlite3_int64)(sum/n);
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare the i-th column of pStmt against pValue. Return true if they
|
||||
** are different.
|
||||
*/
|
||||
static int columnNotEqual(sqlite3_stmt *pStmt, int i, sqlite3_value *pValue){
|
||||
int n1, n2, n;
|
||||
if( sqlite3_column_type(pStmt,i)!=sqlite3_value_type(pValue) ) return 1;
|
||||
switch( sqlite3_column_type(pStmt,i) ){
|
||||
case SQLITE_NULL:
|
||||
return 0; /* Nulls compare equal to one another in this context */
|
||||
|
||||
case SQLITE_INTEGER:
|
||||
return sqlite3_column_int64(pStmt,i)!=sqlite3_value_int64(pValue);
|
||||
|
||||
case SQLITE_FLOAT:
|
||||
return sqlite3_column_double(pStmt,i)!=sqlite3_value_double(pValue);
|
||||
|
||||
case SQLITE_BLOB:
|
||||
n1 = sqlite3_column_bytes(pStmt,i);
|
||||
n2 = sqlite3_value_bytes(pValue);
|
||||
n = n1<n2 ? n1 : n2;
|
||||
if( memcmp(sqlite3_column_blob(pStmt,i), sqlite3_value_blob(pValue),n) ){
|
||||
return 1;
|
||||
}
|
||||
return n1!=n2;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
n1 = sqlite3_column_bytes(pStmt,i);
|
||||
n2 = sqlite3_value_bytes(pValue);
|
||||
n = n1<n2 ? n1 : n2;
|
||||
if( memcmp(sqlite3_column_text(pStmt,i), sqlite3_value_text(pValue),n) ){
|
||||
return 1;
|
||||
}
|
||||
return n1!=n2;
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Stat1 for an index. Return non-zero if an entry was created.
|
||||
*/
|
||||
static int analyzeIndex(const char *zTab, const char *zIdx){
|
||||
sqlite3_int64 n = estEntryCount(zIdx);
|
||||
sqlite3_stmt *pStmt;
|
||||
sqlite3_uint64 *aCnt;
|
||||
sqlite3_value **apValue;
|
||||
int nCol = 0;
|
||||
int nByte;
|
||||
int i, j, k;
|
||||
int iLimit;
|
||||
int nRow = 0;
|
||||
char *zRes;
|
||||
int szRes;
|
||||
int rc;
|
||||
|
||||
# define N_SPAN 5
|
||||
if( n==0 ) return 0;
|
||||
pStmt = db_prepare("PRAGMA index_xinfo=\"%w\"", zIdx);
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
const char *zColl = (const char*)sqlite3_column_text(pStmt,4);
|
||||
if( sqlite3_stricmp(zColl,"binary")!=0 ){
|
||||
printf("-- cannot analyze index \"%s\" because column \"%s\" uses"
|
||||
" collating sequence \"%s\".\n",
|
||||
zIdx, sqlite3_column_text(pStmt, 2), zColl);
|
||||
sqlite3_finalize(pStmt);
|
||||
return 0;
|
||||
}
|
||||
if( sqlite3_column_int(pStmt, 5)==0 ) break;
|
||||
nCol++;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( nCol==0 ) return 0;
|
||||
nByte = (sizeof(aCnt[0]) + sizeof(apValue[0]))*nCol + 30*(nCol+1);
|
||||
aCnt = sqlite3_malloc( nByte );
|
||||
if( aCnt==0 ){
|
||||
runtimeError("out of memory");
|
||||
}
|
||||
memset(aCnt, 0, nByte);
|
||||
apValue = (sqlite3_value**)&aCnt[nCol];
|
||||
zRes = (char*)&apValue[nCol];
|
||||
szRes = 30*(nCol+1);
|
||||
|
||||
iLimit = n>10000 ? 100 : 20000;
|
||||
pStmt = db_prepare("PRAGMA btree_sample(\"%w\",0.0,%lld)",
|
||||
zIdx, n*2);
|
||||
for(i=0; i<=N_SPAN; i++){
|
||||
k = 0;
|
||||
while( k<iLimit && (rc = sqlite3_step(pStmt))==SQLITE_ROW ){
|
||||
int iFirst;
|
||||
for(iFirst=0; iFirst<nCol; iFirst++){
|
||||
if( apValue[iFirst]==0 ) break;
|
||||
if( columnNotEqual(pStmt, iFirst, apValue[iFirst]) ) break;
|
||||
}
|
||||
for(j=iFirst; j<nCol; j++){
|
||||
aCnt[j]++;
|
||||
sqlite3_value_free(apValue[j]);
|
||||
apValue[j] = sqlite3_value_dup(sqlite3_column_value(pStmt,j));
|
||||
}
|
||||
if( k==0 && iFirst==nCol ){
|
||||
nRow += n/(N_SPAN+1) - iLimit;
|
||||
}
|
||||
nRow++;
|
||||
k++;
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( rc!=SQLITE_ROW || i==N_SPAN-1 ) break;
|
||||
pStmt = db_prepare("PRAGMA btree_sample(\"%w\",%g,%lld)",
|
||||
zIdx, ((double)i)/(double)N_SPAN, n*2);
|
||||
}
|
||||
for(j=0; j<nCol; j++) sqlite3_value_free(apValue[j]);
|
||||
sqlite3_snprintf(szRes, zRes, "%lld", n);
|
||||
k = (int)strlen(zRes);
|
||||
for(j=0; j<nCol; j++){
|
||||
sqlite3_snprintf(szRes-k, zRes+k, " %d", (nRow+aCnt[j]-1)/aCnt[j]);
|
||||
k += (int)strlen(zRes+k);
|
||||
}
|
||||
printf("INSERT INTO sqlite_stat1 VALUES('%s','%s','%s');\n",
|
||||
zTab, zIdx, zRes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Stat1 for a table.
|
||||
*/
|
||||
static void analyzeTable(const char *zTab){
|
||||
sqlite3_int64 n = estEntryCount(zTab);
|
||||
sqlite3_stmt *pStmt;
|
||||
int nIndex = 0;
|
||||
int isWithoutRowid = 0;
|
||||
if( n==0 ){
|
||||
printf("-- empty table: %s\n", zTab);
|
||||
return;
|
||||
}
|
||||
if( analyzeIndex(zTab,zTab) ){
|
||||
isWithoutRowid = 1;
|
||||
nIndex++;
|
||||
}
|
||||
pStmt = db_prepare("PRAGMA index_list(\"%w\")", zTab);
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
if( sqlite3_column_text(pStmt,3)[0]=='p' && isWithoutRowid ) continue;
|
||||
if( sqlite3_column_int(pStmt,4)==0 ) nIndex++;
|
||||
analyzeIndex(zTab, (const char*)sqlite3_column_text(pStmt,1));
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
if( nIndex==0 ){
|
||||
printf("INSERT INTO sqlite_stat1 VALUES('%s',NULL,'%lld');\n", zTab, n);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Print sketchy documentation for this utility program
|
||||
*/
|
||||
static void showHelp(void){
|
||||
printf("Usage: %s [options] DBFILE\n", g.zArgv0);
|
||||
printf(
|
||||
"Generate an approximate sqlite_stat1 table for the database in the DBFILE\n"
|
||||
"file. Write the result to standard output.\n"
|
||||
"Options:\n"
|
||||
" (none yet....)\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
const char *zDb = 0;
|
||||
int i;
|
||||
int rc;
|
||||
char *zErrMsg = 0;
|
||||
sqlite3_stmt *pStmt;
|
||||
sqlite3_int64 iStart, iTotal;
|
||||
|
||||
g.zArgv0 = argv[0];
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
iStart = currentTime();
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
if( z[0]=='-' ){
|
||||
z++;
|
||||
if( z[0]=='-' ) z++;
|
||||
if( strcmp(z,"debug")==0 ){
|
||||
if( i==argc-1 ) cmdlineError("missing argument to %s", argv[i]);
|
||||
g.fDebug = strtol(argv[++i], 0, 0);
|
||||
}else
|
||||
if( strcmp(z,"help")==0 ){
|
||||
showHelp();
|
||||
return 0;
|
||||
}else
|
||||
{
|
||||
cmdlineError("unknown option: %s", argv[i]);
|
||||
}
|
||||
}else if( zDb==0 ){
|
||||
zDb = argv[i];
|
||||
}else{
|
||||
cmdlineError("unknown argument: %s", argv[i]);
|
||||
}
|
||||
}
|
||||
if( zDb==0 ){
|
||||
cmdlineError("database filename required");
|
||||
}
|
||||
rc = sqlite3_open_v2(zDb, &g.db, SQLITE_OPEN_READONLY, 0);
|
||||
if( rc ){
|
||||
cmdlineError("cannot open database file \"%s\"", zDb);
|
||||
}
|
||||
rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, &zErrMsg);
|
||||
if( rc || zErrMsg ){
|
||||
cmdlineError("\"%s\" does not appear to be a valid SQLite database", zDb);
|
||||
}
|
||||
printf("ANALYZE sqlite_master;\nDELETE FROM sqlite_stat1;\n");
|
||||
pStmt = db_prepare("SELECT name FROM sqlite_master"
|
||||
" WHERE type='table' AND rootpage>0"
|
||||
" AND name NOT LIKE 'sqlite_%%'"
|
||||
" ORDER BY name");
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
const char *zName = (const char*)sqlite3_column_text(pStmt, 0);
|
||||
analyzeTable(zName);
|
||||
}
|
||||
sqlite3_finalize(pStmt);
|
||||
printf("ANALYZE sqlite_master;\n");
|
||||
sqlite3_close(g.db);
|
||||
iTotal = currentTime() - iStart;
|
||||
printf("-- elapsed time: %lld.%03lld seconds\n", iTotal/1000, iTotal%1000);
|
||||
return 0;
|
||||
}
|
||||
@@ -300,6 +300,12 @@ set pragma_def {
|
||||
FLAG: NeedSchema Result0 Result1
|
||||
IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
||||
|
||||
NAME: est_count
|
||||
FLAG: NeedSchema
|
||||
|
||||
NAME: btree_sample
|
||||
FLAG: NeedSchema
|
||||
|
||||
NAME: encoding
|
||||
FLAG: Result0 NoColumns1
|
||||
IF: !defined(SQLITE_OMIT_UTF16)
|
||||
|
||||
Reference in New Issue
Block a user