Compare commits

...

21 Commits

Author SHA1 Message Date
drh 1b2f6fa20a Merge in all the trunk enhancements of the previous 7 months. The LIKE
optimization has stopped working when there is an ESCAPE - that problem will
be addressed in a subsequent check-in.

FossilOrigin-Name: 8d2a1cca613f75fb4b1a050cf7ea03b74a4d98f4c56d8079201035d7fdc49e85
2017-09-22 20:18:41 +00:00
drh faa18c354b Merge recent enhancements from trunk.
FossilOrigin-Name: 325ccfa95e3afed2dc6849d6b05d81f0203bf73e
2017-02-16 14:02:04 +00:00
drh d81158dc32 Merge all recent enhancements from trunk.
FossilOrigin-Name: fe86ff54293fbee69126aca9ca9839e3e16d7a1c
2017-01-27 16:24:22 +00:00
drh d49eabfaa6 Merge the pragma-as-vtab enhancement from trunk.
FossilOrigin-Name: 89250777b253f90f133d41f5387671429a562c07
2016-12-16 21:15:04 +00:00
drh 4dd9004289 Fix a potential memory leak following an OOM error in the pragma processing.
FossilOrigin-Name: 396ab8f87ea85a01f7cb73aa83d6572057ae97fc
2016-12-16 21:02:17 +00:00
drh 968067d282 Merge recent trunk enhancements.
FossilOrigin-Name: 74a0ca1f152d6d8454787557c6e990efe0e47a50
2016-12-16 15:57:40 +00:00
drh 6bebbb6a2d Merge recent enhancements from trunk.
FossilOrigin-Name: dc006e08b80758b8ac3addd98a532b074b5ca132
2016-12-12 12:58:55 +00:00
drh 94c4553f48 Merge all the latest changes from trunk.
FossilOrigin-Name: 7ca58a07d3e6c15b227000daae32a4a0a84948ff
2016-11-30 16:39:40 +00:00
drh 1f47b2aaa5 Add an elapsed-time output for faststat1.c.
FossilOrigin-Name: 7116795134922b7dc6c527365faadf0b9101c1d4
2016-10-26 12:58:31 +00:00
drh 57ad53ada4 Simplifications to faststat1.c. Fix a bug in sqlite3MovetoProportional() for
very large b-trees.

FossilOrigin-Name: f7f78147c5d51dfb4c46b2d9afad0648f57d54f3
2016-10-25 19:39:31 +00:00
drh b94664711b Further refinements to the faststat1.c utility.
FossilOrigin-Name: b051fd19bc5b4e5805154b40beb703674f2a8ba8
2016-10-25 19:21:18 +00:00
drh 6d51243979 Enhance faststat1.c to deal better with WITHOUT ROWID tables.
FossilOrigin-Name: 65444f2e35cfd51ece1ba6e37b39d181da479137
2016-10-25 18:28:29 +00:00
drh 7fdaca40b7 Merge recent trunk changes, and especially the PRAGMA index_info enhancement
which is needed on this branch.

FossilOrigin-Name: c3570e462a41586487c4ab3bd08129affe8bed3c
2016-10-25 17:28:49 +00:00
drh 2a3489ae82 Enhance the "PRAGMA index_info" and "PRAGMA index_xinfo" statements so that
they work on WITHOUT ROWID tables and provide information about the underlying
index btree that implements the WITHOUT ROWID table.

FossilOrigin-Name: fe49fb03133fec8bed51c2e2c1b6848ab9fc563e
2016-10-25 15:39:58 +00:00
drh 5fba856bbf First attempt at a utility program to compute sqlite_stat1 without doing
a full table scan.

FossilOrigin-Name: 7b83581a43384fe81dc319482e03be0df45ab25d
2016-10-25 13:57:40 +00:00
drh 052153994b When reading from an index, the shared-cache lock must be on the corresponding
table.

FossilOrigin-Name: 04fe12b590ab67e40cd079b5e614b787f5f525ad
2016-10-21 18:01:40 +00:00
drh c844fac64d Merge updates from trunk, and especially the ".mode quote" enhancement to
the shell.

FossilOrigin-Name: 0c8a5b8844df3389881aecd8e853eb3c78edd954
2016-10-21 17:45:06 +00:00
drh a3c79ae7cd Add the btree_sample(INDEX,LOCATION,LIMIT) pragma.
FossilOrigin-Name: affc2ef5ee3d8885e74051fd508a3d6f8c313857
2016-10-21 17:25:47 +00:00
drh f87f9c240f Fix problems in the est_count pragma for indexes and WITHOUT ROWID tables.
FossilOrigin-Name: c39fd9b8f11b3f1df489df1df4197fe4a670732c
2016-10-21 15:36:51 +00:00
drh a74480a217 Experimental est_count pragma.
FossilOrigin-Name: 340822afbe0c6b47fdd789c56acd9e1058a434cb
2016-10-20 22:02:43 +00:00
drh 19dbfa8adc Add the ability for the PRAGMA statement to accept multiple arguments.
Currently all arguments other than the first are ignored.

FossilOrigin-Name: fd81d8a4300c36d02f07371b722124ccf619654c
2016-10-20 18:20:10 +00:00
14 changed files with 751 additions and 113 deletions
+4
View File
@@ -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)
+19 -18
View File
@@ -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
View File
@@ -1 +1 @@
2c03d8b8f028b6a736aaf2cf8b28a51b3434cf341c95cf3a80469e0a24acdd98
8d2a1cca613f75fb4b1a050cf7ea03b74a4d98f4c56d8079201035d7fdc49e85
+67
View File
@@ -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.
**
+1
View File
@@ -239,6 +239,7 @@ void sqlite3BtreeCursorHint(BtCursor*, int, ...);
#endif
int sqlite3BtreeCloseCursor(BtCursor*);
int sqlite3BtreeMovetoProportional(BtCursor*,u32,u64*);
int sqlite3BtreeMovetoUnpacked(
BtCursor*,
UnpackedRecord *pUnKey,
+17 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+21 -4
View File
@@ -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
+354
View File
@@ -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;
}
+6
View File
@@ -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)