diff --git a/Makefile.in b/Makefile.in index a1e2737f95..d76b5e4d18 100644 --- a/Makefile.in +++ b/Makefile.in @@ -652,9 +652,9 @@ sqlite3.lo: sqlite3.c # Rules to build the LEMON compiler generator # -lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/src/lempar.c +lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c $(BCC) -o $@ $(TOP)/tool/lemon.c - cp $(TOP)/src/lempar.c . + cp $(TOP)/tool/lempar.c . # Rules to build individual *.o files from generated *.c files. This # applies to: diff --git a/Makefile.msc b/Makefile.msc index 33e7aa1791..355435384e 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1335,8 +1335,8 @@ sqlite3.lo: $(SQLITE3C) # Rules to build the LEMON compiler generator # -lempar.c: $(TOP)\src\lempar.c - copy $(TOP)\src\lempar.c . +lempar.c: $(TOP)\tool\lempar.c + copy $(TOP)\tool\lempar.c . lemon.exe: $(TOP)\tool\lemon.c lempar.c $(BCC) $(NO_WARN) -Daccess=_access \ diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am index 5b7c4a090a..eed3ba41cb 100644 --- a/autoconf/Makefile.am +++ b/autoconf/Makefile.am @@ -6,8 +6,10 @@ libsqlite3_la_SOURCES = sqlite3.c libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8 bin_PROGRAMS = sqlite3 -sqlite3_SOURCES = shell.c sqlite3.c sqlite3.h -sqlite3_LDADD = @READLINE_LIBS@ +sqlite3_SOURCES = shell.c sqlite3.h +EXTRA_sqlite3_SOURCES = sqlite3.c +sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@ +sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@ sqlite3_CFLAGS = $(AM_CFLAGS) include_HEADERS = sqlite3.h sqlite3ext.h diff --git a/autoconf/configure.ac b/autoconf/configure.ac index 7812927557..e03dfe289b 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -4,6 +4,8 @@ # # --enable-threadsafe # --enable-readline +# --enable-editline +# --enable-static-shell # --enable-dynamic-extensions # @@ -117,6 +119,21 @@ fi AC_SUBST(JSON1_FLAGS) #----------------------------------------------------------------------- +#----------------------------------------------------------------------- +# --enable-static-shell +# +AC_ARG_ENABLE(static-shell, [AS_HELP_STRING( + [--enable-static-shell], + [statically link libsqlite3 into shell tool [default=yes]])], + [], [enable_static_shell=yes]) +if test x"$enable_static_shell" == "xyes"; then + EXTRA_SHELL_OBJ=sqlite3.$OBJEXT +else + EXTRA_SHELL_OBJ=libsqlite3.la +fi +AC_SUBST(EXTRA_SHELL_OBJ) +#----------------------------------------------------------------------- + AC_CHECK_FUNCS(posix_fallocate) #----------------------------------------------------------------------- diff --git a/ext/fts5/fts5parse.y b/ext/fts5/fts5parse.y index 065af77053..0e81771b4f 100644 --- a/ext/fts5/fts5parse.y +++ b/ext/fts5/fts5parse.y @@ -58,6 +58,18 @@ */ #define yytestcase(X) testcase(X) +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENOTNULL 1 + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + } // end %include %left OR. @@ -168,7 +180,3 @@ phrase(A) ::= STRING(Y) star_opt(Z). { star_opt(A) ::= STAR. { A = 1; } star_opt(A) ::= . { A = 0; } - - - - diff --git a/main.mk b/main.mk index dd74aecf77..45bb6e9c1d 100644 --- a/main.mk +++ b/main.mk @@ -563,9 +563,9 @@ fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl # Rules to build the LEMON compiler generator # -lemon: $(TOP)/tool/lemon.c $(TOP)/src/lempar.c +lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c $(BCC) -o lemon $(TOP)/tool/lemon.c - cp $(TOP)/src/lempar.c . + cp $(TOP)/tool/lempar.c . # Rules to build individual *.o files from generated *.c files. This # applies to: diff --git a/manifest b/manifest index 701f0d01fc..dfc4906ec6 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -C Merge\srecent\senhancements\sand\sbug\sfixes\sfrom\strunk. -D 2015-11-07T01:33:30.741 -F Makefile.in 7037017983949da7c736ca3de2c3d29611b77d1c +C Merge\sthe\slatest\senhancements\sfrom\strunk. +D 2015-11-19T19:40:40.385 +F Makefile.in c9dfc95717a5af63ab90b36f22afd11e865e3559 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 -F Makefile.msc 2ed14817d36a6c26cb146e53b9c8a7318ba5bdd4 +F Makefile.msc 4f04d3dbe993b706c956509b1437559d7f2469b1 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION 8b9d3ac6f1962f94e06ba05462422a544f9c4e36 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -10,12 +10,12 @@ F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90 F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2 F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903 -F autoconf/Makefile.am bd4a90972aa87f079af6624ddea3df3d58f26d2f +F autoconf/Makefile.am 089e5ecdb5761e64ea1013ded02feb4d8b29927d F autoconf/README 14458f1046c118efa721aadec5f227e876d3cd38 F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7 F autoconf/config.guess 94cc57e2a3fdb9c235b362ace86d77e89d188cad x F autoconf/config.sub 1efb390a8fb4bfafd74783a15a8fb5311c84300e x -F autoconf/configure.ac bec3caf78cf1bdbaad903dcd5c6029292eda3d2d +F autoconf/configure.ac 9a65da17e440466f9842288163f16f9b21298129 F autoconf/depcomp 0b26f101e3bc9fd1ff0be1da9fb4a82371142f92 x F autoconf/install-sh 06ee6336e63bb845c8439d777c32eb2eccc4fbf1 x F autoconf/ltmain.sh 7a658a24028f02331c1d2446562758083c5eadd1 @@ -118,7 +118,7 @@ F ext/fts5/fts5_tokenize.c 12c5d925286491a71bb3dad7c8924ce9cfd18320 F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1 F ext/fts5/fts5_vocab.c 3742d0abfe8aa8c3cb4a7df56aa38f2e3c3fb1c2 -F ext/fts5/fts5parse.y e83dca6028e3309178d05b5bd920e372dc295d35 +F ext/fts5/fts5parse.y 1647eba089b9b3fc058b4dc989d9da87d15b9580 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/test/fts5_common.tcl 51f7ef3af444b89c6f6ce3896a0ac349ff4e996d F ext/fts5/test/fts5aa.test 2c553eea4dab4bc5a75928f56729277c7bc1d206 @@ -283,7 +283,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 2e67604b0dbd7670230ed626b6a2947f05a35ba5 +F main.mk 4f8d448adb9a7302cd5106f583ddc47067f1017d F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -302,16 +302,16 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 2869a76c03eb393ee795416e2387005553df72bc F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 9e5d713bf54be8bfcae9b60210173dd53570f56d -F src/btree.h 1b8bf2818b5e256c25a5e09126720113b1d783da +F src/btree.c d3bdd8462a86492e2ebc9aca4a0168429017de25 +F src/btree.h 2d76dee44704c47eed323356a758662724b674a0 F src/btreeInt.h 3ab435ed27adea54d040584b0bcc488ee7db1e38 -F src/build.c ca574d33ffb1763cfd2979383f4d507095bfbe19 +F src/build.c 5a3b71786e2b96d2bb92d40f190eb1fe736f25ca F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 509ef9c64d1321f42448f111da86400b1799218a F src/date.c fb1c99172017dcc8e237339132c91a21a0788584 F src/dbstat.c ffd63fc8ba7541476ced189b95e95d7f2bc63f78 -F src/delete.c 9dddc4434aace0f42f1ed1c5224cdcfc2328ed67 +F src/delete.c 86e3940d07fe69a40270c2aaf6ca6c7adf19246c F src/expr.c 0080c0f12806eca91e75a23a121a68918e9da357 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 31900763094a3736a5fc887469202eb579fef2d0 @@ -320,12 +320,11 @@ F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 0dbbde4b667b6e47a45ea98958516e2f30a9f9c4 +F src/insert.c 8ab83219eb56a103edb73bb0a1e9057c4d3b976b F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e -F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012 F src/loadext.c 18586e45a215325f15096821e9c082035d4fb810 -F src/main.c cae25642d7f49cd94d833c49726eeb28381349f0 +F src/main.c 59798e68b7f93eaf243b2b4d054dd4eb6ead907a F src/malloc.c 337bbe9c7d436ef9b7d06b5dd10bbfc8f3025972 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b @@ -344,33 +343,33 @@ F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa -F src/os_unix.c cf72e06e15839ebe7121e01d3eebf256c039b0ca -F src/os_win.c 1716291e5ec2dbfc5a1fe0b32182030f1f7d8acf +F src/os_unix.c eb24e0340fbe3cfd0eabfb15a71476953e54fa73 +F src/os_win.c 2d77dab5c555a18c0aff379c6a692fc3499044d9 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca -F src/pager.c ed5cff11793b6a4146582aabb29ed8613a6cf89e -F src/pager.h 7fc069c07f3120ee466ff3d48a9d376974ebffa7 -F src/parse.y 11078cd8e3af00f030505b6a86a06a4536cfdeaa -F src/pcache.c 24be750c79272e0ca7b6e007bc94999700f3e5ef -F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9 +F src/pager.c 18341e2b759b447cbc82fb9215d08d9c5864e92e +F src/pager.h 87c4118a71ba3965184148b379a6d93179071091 +F src/parse.y 23737e649c26ce327603799e57f5c2ff50e5e6ba +F src/pcache.c 73895411fa6b7bd6f0091212feabbe833b358d23 +F src/pcache.h 1ff11adce609ba7de139b6abfabaf9a2bac947b5 F src/pcache1.c 902e1bc7bdaa81b40f8543407c5e2ac8ef4dc035 -F src/pragma.c 8fd4c8a12e25f0d916426f160255ebe25415eba7 -F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a +F src/pragma.c f3e7147299ca05ef4304a36f1fd6e002729c72c6 +F src/pragma.h 3d94aebbebd2089899fecc01909bf2608b39507d F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 -F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a +F src/printf.c f8fc8f04e75b1e983ef2793c27ec7a43b287e94a F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 1954a0f01bf65d78d7d559aea3d5c67f33376d91 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 167b4e9058bc8e997d18d6b6b20ecbb0c9c457af -F src/shell.c 993863f82d764be0c00803056e56b9b744f86f02 -F src/sqlite.h.in 45821b35edf55ac410c16a3e1de4d6d43aa7ee16 +F src/select.c 2376d320907a5c28c55290f18fd94aa3400bf97c +F src/shell.c 072fc3601b0ac02e50939b469fabeecfe3d66dcd +F src/sqlite.h.in eed36953a0b5ce6c099b0cb2cb6b6ba220e6ca77 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 4b66e3e3435da4b4c8c83696d0349f0c503b3924 -F src/sqliteInt.h a02b33a3b68913394c218ec27f24b8fa33518244 +F src/sqliteInt.h d85782b8b5b2057ac015f7ec20195b7ce869960d F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e F src/tclsqlite.c e2344bee0d192397f555a24ef3fab26f2ed93bcc -F src/test1.c a719afff3144f7f01c6dc3f7d118ac31d15e7527 +F src/test1.c 4004bcc1b3b361a9137acd1d875599ecbdd6f961 F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b F src/test3.c a8887dabbbee3059af338f20d290084a63ed1b0f F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e @@ -384,7 +383,7 @@ F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12 F src/test_backup.c 2e6e6a081870150f20c526a2e9d0d29cda47d803 F src/test_blob.c e5a7a81d61a780da79101aeb1e60d300af169e07 F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f -F src/test_config.c e1fc48719655d83ea23513f3c3da32b4c4205899 +F src/test_config.c a25edf31cc0dbe17f5d1d667b1320cbb4e52b6dd F src/test_demovfs.c 0de72c2c89551629f58486fde5734b7d90758852 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f @@ -407,7 +406,7 @@ F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d F src/test_rtree.c 43fff4c5a01576d6d213f27472598801a247890c F src/test_schema.c 2bdba21b82f601da69793e1f1d11bf481a79b091 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe -F src/test_sqllog.c b690c12933f50ff46491e0d56a251f84ae16e914 +F src/test_sqllog.c 0d138a8180a312bf996b37fa66da5c5799d4d57b F src/test_superlock.c 06797157176eb7085027d9dd278c0d7a105e3ec9 F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa @@ -416,8 +415,8 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c bbfb74450643cb5372a43ad4f6cffd7e9dfcecb0 -F src/tokenize.c 338bc8f7c9dd103188952cda7964696bacac6d22 -F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce +F src/tokenize.c 5606871a377f390af7040ec3c12e0d183512d785 +F src/treeview.c 78842e90c1f71269e7a73a1d4221b6fe360bab66 F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c c2fff3b60bfcabcb0372acbe8cf6f77c2bb515bc F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c @@ -427,7 +426,7 @@ F src/vdbe.c 9539aa0ccf4844b8b59466ef3c15dbffb479a390 F src/vdbe.h bfe3f80dba435377cdb64fd917f2529f0f48ab77 F src/vdbeInt.h d6ae6e64ad16e213f37306b1735ff72fb98bec69 F src/vdbeapi.c f5eda36a5c85ef578957ab4311e8d9b1f51a3552 -F src/vdbeaux.c 1c5969fa8b04e162a2e893ebb283071bec81a006 +F src/vdbeaux.c 67db9a1c132207f4d6a8f4e76531cea39539fcaa F src/vdbeblob.c b400c25ac822af3c507ef84b5cd93c1583a70321 F src/vdbemem.c 25b6cfd665b5073480452426e84136edd94140c0 F src/vdbesort.c 8b23930a1289526f6d2a3a9f2e965bcc963e4a68 @@ -774,7 +773,7 @@ F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1 F test/fuzz3.test 53fabcd5f0f430f8b221282f6c12c4d0903c21eb F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 -F test/fuzzcheck.c ee926f1d4090d053ed542899720d4e4d30811bcc +F test/fuzzcheck.c 7c61352f20a28429b221f406f3854cf9c912f63b F test/fuzzdata1.db 7ee3227bad0e7ccdeb08a9e6822916777073c664 F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973 F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba @@ -783,6 +782,7 @@ F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 F test/hexlit.test 1d312fa816dfd3650a3bb488093bc09a0c927f67 +F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711 F test/hook.test aa41c095d26822b8a51aa4c82904a14347961be6 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4 F test/ieee754.test 118b665a97a8df0e8f2fbdb07d113e596f4a6b53 @@ -896,7 +896,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f -F test/misc1.test 3f1c479c5a093a6280f378c0fbff1c2701486660 +F test/misc1.test d614a334b777b1aded6873d76a3560329b819fea F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3 @@ -952,7 +952,7 @@ F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff F test/permutations.test 63cb93f915b4056463cef8ad035082e9f1cb524e F test/pragma.test a44253f911e7d50127d4a08f927f47c861a4c772 -F test/pragma2.test b5e2ce4c892afceb308c6ae6163a9099b2a0d8d7 +F test/pragma2.test 00065068eeab2d15ea55465ec0f1e0a70e2c369e F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054 @@ -970,7 +970,7 @@ F test/rbu.test 168573d353cd0fd10196b87b0caa322c144ef736 F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/releasetest.tcl 2d000ceded3115758be96abb9c10a5669fb27862 +F test/releasetest.tcl 622f2381b217facdf429584a5c292cc1fc47e7c0 F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 @@ -1060,6 +1060,7 @@ F test/spellfix.test 0597065ff57042df1f138e6a2611ae19c2698135 F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3 F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5 F test/sqllimits1.test 89b3d5aad05b99f707ee3786bdd4416dccf83304 +F test/sqllog.test a8faa2df39610a037dd372ed872d124260d32953 F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 @@ -1081,7 +1082,7 @@ F test/tclsqlite.test 7179b4e0bf236ddf0bfa6bfaefa76fbe0a23c28a F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl b1f0870442ca012effbf8659e34f9be428990696 +F test/tester.tcl 24d971d001a5bb10ef13c27768caed182eb1566e F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1248,7 +1249,7 @@ F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359 F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83 F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9 -F test/trigger7.test 200dd51e728c9cdc20c72d99d9e9d45c667248f8 +F test/trigger7.test 799c9d2561facef70340cc9e0dee98aee9b5bdfe F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4 F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41 F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332 @@ -1299,7 +1300,7 @@ F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772 F test/wal.test dbfc482e10c7263298833bb1fc60b3ac9d6340a1 F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada -F test/wal3.test 2ab8e490afe0164bfc89b185c8b2572e0d821f23 +F test/wal3.test b1d425f68a1f61d12563f0fa1ee6fca7d5afabf4 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal5.test 88b5d9a6a3d1532497ee9f4296f010d66f07e33c F test/wal6.test 4421cd5a2fa99d29cc91ef12fb23bed171ed3a4c @@ -1350,8 +1351,9 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d -F test/with1.test a1e8660be88e2eb4648f8860f831d1e38b5b5443 +F test/with1.test 05c8fc7f809f178a8a0519f02c21fe430948c895 F test/with2.test 2b40da883658eb74ad8ad06afabe11a408e7fb87 +F test/with3.test 511bacdbe41c49cf34f9fd1bd3245fe1575bca98 F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991 F test/without_rowid1.test 1a7b9bd51b899928d327052df9741d2fe8dbe701 F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99 @@ -1364,9 +1366,10 @@ F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5 F tool/GetTclKit.bat 8606413d3035c05373a0d7fae82ebf59ae9e16c3 -F tool/addopcodes.tcl 26892c394964c194fe96b9a79b8b9f87347c7151 +F tool/addopcodes.tcl 4ca9c3ef196f08da30add5d07ce0c9458dc8c633 F tool/build-all-msvc.bat e42141ca3c3812315432f9813ef9eb78aa8d99c9 x F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367 +F tool/cg_anno.tcl 692ce4b8693d59e3a3de77ca97f4139ecfa641b0 x F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1 @@ -1376,15 +1379,15 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c 799e73e19a33b8dd7767a7fa34618ed2a9c2397d -F tool/lempar.c 3617143ddb9b176c3605defe6a9c798793280120 +F tool/lempar.c 3ec1463a034b37d87d782be5f6b8b10a3b1ecbe7 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh 4bdf61548a143e5977bd86ab93d68b694d10c8fa -F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670 +F tool/mkkeywordhash.c 06ec0b78bd4fa68c12d90ef2bdfe76b039133ff8 F tool/mkopcodec.tcl edde8adc42621b5e598127f8cdc6d52cfe21f52b F tool/mkopcodeh.tcl e04177031532b7aa9379ded50e820231ac4abd6e F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e -F tool/mkpragmatab.tcl 84af2b180484323a2ea22a2279e8bd9e3e1e492e +F tool/mkpragmatab.tcl e94e55d247d4fe3be34f2a4f4edb03fdcd09ce5b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 87240b09c20042999b41d5fabe091b7111287835 F tool/mksqlite3c.tcl a52d7e8c0888f9384fbfa2c6ddd5f357409758b9 @@ -1397,6 +1400,7 @@ F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b F tool/replace.tcl 7727c60a04299b65a92f5e1590896fea0f25b9e0 F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5 +F tool/run-speed-test.sh 0ae485af4fe9f826e2b494be8c81f8ca9e222a4a F tool/showdb.c d4476e000a64eca9f5e2c2f68741e747b9778e8d F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818 F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68 @@ -1410,7 +1414,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c -F tool/sqldiff.c b318efc2eaf7a7fac4d281a0ce736193cb2506df +F tool/sqldiff.c db1232df457fdd4cbf2a919a497fc44bb18fb933 F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43 F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148 @@ -1421,7 +1425,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 0546d1cd1a3402890edade7970c269cc3f17bc98 0f5b147d1fe83c34d0fbeacc7422be94d8441bc1 -R 65016c2c463ac04ecdb2d993caf6bb9d +P 78bc42e664e9fa9ee21ad9762c369f291fcdf5db 126b998cf163dcdd5a222634f1e929f04db3c700 +R d78a5057451ca68f4e40e727fe9ca899 U drh -Z 6ef4d8405632dbe4f4eb27a0771bc5f1 +Z 251138aef0997d710e6be89ddc7546bd diff --git a/manifest.uuid b/manifest.uuid index 5e3b708e1b..77c3b5ff65 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -78bc42e664e9fa9ee21ad9762c369f291fcdf5db \ No newline at end of file +7d6cfc79e7e5534ebacd980479917bc528a638f7 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a61a6edf2f..4a51b01d75 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2556,19 +2556,11 @@ int sqlite3BtreeClose(Btree *p){ } /* -** Change the limit on the number of pages allowed in the cache. -** -** The maximum number of cache pages is set to the absolute -** value of mxPage. If mxPage is negative, the pager will -** operate asynchronously - it will not stop to do fsync()s -** to insure data is written to the disk surface before -** continuing. Transactions still work if synchronous is off, -** and the database cannot be corrupted if this program -** crashes. But if the operating system crashes or there is -** an abrupt power failure when synchronous is off, the database -** could be left in an inconsistent and unrecoverable state. -** Synchronous is on by default so database corruption is not -** normally a worry. +** Change the "soft" limit on the number of pages in the cache. +** Unused and unmodified pages will be recycled when the number of +** pages in the cache exceeds this soft limit. But the size of the +** cache is allowed to grow larger than this limit if it contains +** dirty pages or pages still in active use. */ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ BtShared *pBt = p->pBt; @@ -2579,6 +2571,26 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ return SQLITE_OK; } +/* +** Change the "spill" limit on the number of pages in the cache. +** If the number of pages exceeds this limit during a write transaction, +** the pager might attempt to "spill" pages to the journal early in +** order to free up memory. +** +** The value returned is the current spill size. If zero is passed +** as an argument, no changes are made to the spill size setting, so +** using mxPage of 0 is a way to query the current spill size. +*/ +int sqlite3BtreeSetSpillSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; + int res; + assert( sqlite3_mutex_held(p->db->mutex) ); + sqlite3BtreeEnter(p); + res = sqlite3PagerSetSpillsize(pBt->pPager, mxPage); + sqlite3BtreeLeave(p); + return res; +} + #if SQLITE_MAX_MMAP_SIZE>0 /* ** Change the limit on the amount of the database file that may be diff --git a/src/btree.h b/src/btree.h index 0c15a59c11..09b713f3db 100644 --- a/src/btree.h +++ b/src/btree.h @@ -63,6 +63,7 @@ int sqlite3BtreeOpen( int sqlite3BtreeClose(Btree*); int sqlite3BtreeSetCacheSize(Btree*,int); +int sqlite3BtreeSetSpillSize(Btree*,int); #if SQLITE_MAX_MMAP_SIZE>0 int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64); #endif diff --git a/src/build.c b/src/build.c index 8cb2d44ac7..f928ba3075 100644 --- a/src/build.c +++ b/src/build.c @@ -1049,18 +1049,19 @@ begin_table_error: return; } -/* -** This macro is used to compare two strings in a case-insensitive manner. -** It is slightly faster than calling sqlite3StrICmp() directly, but -** produces larger code. -** -** WARNING: This macro is not compatible with the strcmp() family. It -** returns true if the two strings are equal, otherwise false. +/* Set properties of a table column based on the (magical) +** name of the column. */ -#define STRICMP(x, y) (\ -sqlite3UpperToLower[*(unsigned char *)(x)]== \ -sqlite3UpperToLower[*(unsigned char *)(y)] \ -&& sqlite3StrICmp((x)+1,(y)+1)==0 ) +void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){ +#if SQLITE_ENABLE_HIDDEN_COLUMNS + if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){ + pCol->colFlags |= COLFLAG_HIDDEN; + }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ + pTab->tabFlags |= TF_OOOHidden; + } +#endif +} + /* ** Add a new column to the table currently being constructed. @@ -1086,7 +1087,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ z = sqlite3NameFromToken(db, pName); if( z==0 ) return; for(i=0; inCol; i++){ - if( STRICMP(z, p->aCol[i].zName) ){ + if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; @@ -1104,6 +1105,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ pCol = &p->aCol[p->nCol]; memset(pCol, 0, sizeof(p->aCol[0])); pCol->zName = z; + sqlite3ColumnPropertiesFromName(p, pCol); /* If there is no type specified, columns have the default affinity ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will diff --git a/src/delete.c b/src/delete.c index 506c2af1f2..68c4c4b360 100644 --- a/src/delete.c +++ b/src/delete.c @@ -106,7 +106,8 @@ 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); + pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, + SF_IncludeHidden, 0, 0); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); diff --git a/src/insert.c b/src/insert.c index f4af3391d9..7585a77278 100644 --- a/src/insert.c +++ b/src/insert.c @@ -736,10 +736,8 @@ void sqlite3Insert( /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ - if( IsVirtual(pTab) ){ - for(i=0; inCol; i++){ - nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); - } + for(i=0; inCol; i++){ + nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); } if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, @@ -835,15 +833,14 @@ void sqlite3Insert( /* Create the new column data */ - for(i=0; inCol; i++){ - if( pColumn==0 ){ - j = i; - }else{ + for(i=j=0; inCol; i++){ + if( pColumn ){ for(j=0; jnId; j++){ if( pColumn->a[j].idx==i ) break; } } - if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){ + if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) + || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); @@ -851,6 +848,7 @@ void sqlite3Insert( assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); } + if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++; } /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, @@ -934,7 +932,6 @@ void sqlite3Insert( } if( pColumn==0 ){ if( IsHiddenColumn(&pTab->aCol[i]) ){ - assert( IsVirtual(pTab) ); j = -1; nHidden++; }else{ @@ -1885,7 +1882,7 @@ static int xferOptimization( return 0; /* The result set must have exactly one column */ } assert( pEList->a[0].pExpr ); - if( pEList->a[0].pExpr->op!=TK_ALL ){ + if( pEList->a[0].pExpr->op!=TK_ASTERISK ){ return 0; /* The result set must be the special operator "*" */ } @@ -1921,6 +1918,13 @@ static int xferOptimization( for(i=0; inCol; i++){ Column *pDestCol = &pDest->aCol[i]; Column *pSrcCol = &pSrc->aCol[i]; +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS + if( (db->flags & SQLITE_Vacuum)==0 + && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN + ){ + return 0; /* Neither table may have __hidden__ columns */ + } +#endif if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } diff --git a/src/lempar.c b/src/lempar.c deleted file mode 100644 index 5e5a11aeaa..0000000000 --- a/src/lempar.c +++ /dev/null @@ -1,895 +0,0 @@ -/* Driver template for the LEMON parser generator. -** The author disclaims copyright to this source code. -** -** This version of "lempar.c" is modified, slightly, for use by SQLite. -** The only modifications are the addition of a couple of NEVER() -** macros to disable tests that are needed in the case of a general -** LALR(1) grammar but which are always false in the -** specific grammar used by SQLite. -*/ -/* First off, code is included that follows the "include" declaration -** in the input grammar file. */ -#include -%% -/* Next is all token values, in a form suitable for use by makeheaders. -** This section will be null unless lemon is run with the -m switch. -*/ -/* -** These constants (all generated automatically by the parser generator) -** specify the various kinds of tokens (terminals) that the parser -** understands. -** -** Each symbol here is a terminal symbol in the grammar. -*/ -%% -/* Make sure the INTERFACE macro is defined. -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/* The next thing included is series of defines which control -** various aspects of the generated parser. -** YYCODETYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 terminals -** and nonterminals. "int" is used otherwise. -** YYNOCODE is a number of type YYCODETYPE which corresponds -** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash -** table. -** YYFALLBACK If defined, this indicates that one or more tokens -** have fall-back values which should be used if the -** original value of the token will not parse. -** YYACTIONTYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 rules and -** states combined. "int" is used otherwise. -** ParseTOKENTYPE is the data type used for minor tokens given -** directly to the parser from the tokenizer. -** YYMINORTYPE is the data type used for all minor tokens. -** This is typically a union of many types, one of -** which is ParseTOKENTYPE. The entry in the union -** for base tokens is called "yy0". -** YYSTACKDEPTH is the maximum depth of the parser's stack. If -** zero the stack is dynamically sized using realloc() -** ParseARG_SDECL A static variable declaration for the %extra_argument -** ParseARG_PDECL A parameter declaration for the %extra_argument -** ParseARG_STORE Code to store %extra_argument into yypParser -** ParseARG_FETCH Code to extract %extra_argument from yypParser -** YYERRORSYMBOL is the code number of the error symbol. If not -** defined, then do no error processing. -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar -** YY_MAX_SHIFT Maximum value for shift actions -** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions -** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions -** YY_MIN_REDUCE Maximum value for reduce actions -** YY_ERROR_ACTION The yy_action[] code for syntax error -** YY_ACCEPT_ACTION The yy_action[] code for accept -** YY_NO_ACTION The yy_action[] code for no-op -*/ -%% - -/* The yyzerominor constant is used to initialize instances of -** YYMINORTYPE objects to zero. */ -static const YYMINORTYPE yyzerominor = { 0 }; - -/* Define the yytestcase() macro to be a no-op if is not already defined -** otherwise. -** -** Applications can choose to define yytestcase() in the %include section -** to a macro that can assist in verifying code coverage. For production -** code the yytestcase() macro should be turned off. But it is useful -** for testing. -*/ -#ifndef yytestcase -# define yytestcase(X) -#endif - - -/* Next are the tables used to determine what action to take based on the -** current state and lookahead token. These tables are used to implement -** functions that take a state number and lookahead value and return an -** action integer. -** -** Suppose the action integer is N. Then the action is determined as -** follows -** -** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead -** token onto the stack and goto state N. -** -** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then -** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. -** -** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE -** and YY_MAX_REDUCE - -** N == YY_ERROR_ACTION A syntax error has occurred. -** -** N == YY_ACCEPT_ACTION The parser accepts its input. -** -** N == YY_NO_ACTION No such action. Denotes unused -** slots in the yy_action[] table. -** -** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as -** -** yy_action[ yy_shift_ofst[S] + X ] -** -** If the index value yy_shift_ofst[S]+X is out of range or if the value -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. -** -** The formula above is for computing the action when the lookahead is -** a terminal symbol. If the lookahead is a non-terminal (as occurs after -** a reduce action) then the yy_reduce_ofst[] array is used in place of -** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of -** YY_SHIFT_USE_DFLT. -** -** The following are the tables generated in this section: -** -** yy_action[] A single table containing all actions. -** yy_lookahead[] A table containing the lookahead for each entry in -** yy_action. Used to detect hash collisions. -** yy_shift_ofst[] For each state, the offset into yy_action for -** shifting terminals. -** yy_reduce_ofst[] For each state, the offset into yy_action for -** shifting non-terminals after a reduce. -** yy_default[] Default action for each state. -*/ -%% - -/* The next table maps tokens into fallback tokens. If a construct -** like the following: -** -** %fallback ID X Y Z. -** -** appears in the grammar, then ID becomes a fallback token for X, Y, -** and Z. Whenever one of the tokens X, Y, or Z is input to the parser -** but it does not parse, the type of the token is changed to ID and -** the parse is retried before an error is thrown. -*/ -#ifdef YYFALLBACK -static const YYCODETYPE yyFallback[] = { -%% -}; -#endif /* YYFALLBACK */ - -/* The following structure represents a single element of the -** parser's stack. Information stored includes: -** -** + The state number for the parser at this level of the stack. -** -** + The value of the token stored at this level of the stack. -** (In other words, the "major" token.) -** -** + The semantic value stored at this level of the stack. This is -** the information used by the action routines in the grammar. -** It is sometimes called the "minor" token. -** -** After the "shift" half of a SHIFTREDUCE action, the stateno field -** actually contains the reduce action for the second half of the -** SHIFTREDUCE. -*/ -struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ - YYCODETYPE major; /* The major token value. This is the code - ** number for the token at this stack level */ - YYMINORTYPE minor; /* The user-supplied minor token value. This - ** is the value of the token */ -}; -typedef struct yyStackEntry yyStackEntry; - -/* The state of the parser is completely contained in an instance of -** the following structure */ -struct yyParser { - int yyidx; /* Index of top element in stack */ -#ifdef YYTRACKMAXSTACKDEPTH - int yyidxMax; /* Maximum value of yyidx */ -#endif - int yyerrcnt; /* Shifts left before out of the error */ - ParseARG_SDECL /* A place to hold %extra_argument */ -#if YYSTACKDEPTH<=0 - int yystksz; /* Current side of the stack */ - yyStackEntry *yystack; /* The parser's stack */ -#else - yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ -#endif -}; -typedef struct yyParser yyParser; - -#ifndef NDEBUG -#include -static FILE *yyTraceFILE = 0; -static char *yyTracePrompt = 0; -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* -** Turn parser tracing on by giving a stream to which to write the trace -** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL -** -** Inputs: -**
    -**
  • A FILE* to which trace output should be written. -** If NULL, then tracing is turned off. -**
  • A prefix string written at the beginning of every -** line of trace output. If NULL, then tracing is -** turned off. -**
-** -** Outputs: -** None. -*/ -void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ - yyTraceFILE = TraceFILE; - yyTracePrompt = zTracePrompt; - if( yyTraceFILE==0 ) yyTracePrompt = 0; - else if( yyTracePrompt==0 ) yyTraceFILE = 0; -} -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* For tracing shifts, the names of all terminals and nonterminals -** are required. The following table supplies these names */ -static const char *const yyTokenName[] = { -%% -}; -#endif /* NDEBUG */ - -#ifndef NDEBUG -/* For tracing reduce actions, the names of all rules are required. -*/ -static const char *const yyRuleName[] = { -%% -}; -#endif /* NDEBUG */ - - -#if YYSTACKDEPTH<=0 -/* -** Try to increase the size of the parser stack. -*/ -static void yyGrowStack(yyParser *p){ - int newSize; - yyStackEntry *pNew; - - newSize = p->yystksz*2 + 100; - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); - if( pNew ){ - p->yystack = pNew; - p->yystksz = newSize; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", - yyTracePrompt, p->yystksz); - } -#endif - } -} -#endif - -/* -** This function allocates a new parser. -** The only argument is a pointer to a function which works like -** malloc. -** -** Inputs: -** A pointer to the function used to allocate memory. -** -** Outputs: -** A pointer to a parser. This pointer is used in subsequent calls -** to Parse and ParseFree. -*/ -void *ParseAlloc(void *(*mallocProc)(u64)){ - yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (u64)sizeof(yyParser) ); - if( pParser ){ - pParser->yyidx = -1; -#ifdef YYTRACKMAXSTACKDEPTH - pParser->yyidxMax = 0; -#endif -#if YYSTACKDEPTH<=0 - pParser->yystack = NULL; - pParser->yystksz = 0; - yyGrowStack(pParser); -#endif - } - return pParser; -} - -/* The following function deletes the value associated with a -** symbol. The symbol can be either a terminal or nonterminal. -** "yymajor" is the symbol code, and "yypminor" is a pointer to -** the value. -*/ -static void yy_destructor( - yyParser *yypParser, /* The parser */ - YYCODETYPE yymajor, /* Type code for object to destroy */ - YYMINORTYPE *yypminor /* The object to be destroyed */ -){ - ParseARG_FETCH; - switch( yymajor ){ - /* Here is inserted the actions which take place when a - ** terminal or non-terminal is destroyed. This can happen - ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is - ** being destroyed before it is finished parsing. - ** - ** Note: during a reduce, the only symbols destroyed are those - ** which appear on the RHS of the rule, but which are not used - ** inside the C code. - */ -%% - default: break; /* If no destructor action specified: do nothing */ - } -} - -/* -** Pop the parser's stack once. -** -** If there is a destructor routine associated with the token which -** is popped from the stack, then call it. -** -** Return the major token number for the symbol popped. -*/ -static int yy_pop_parser_stack(yyParser *pParser){ - YYCODETYPE yymajor; - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; - - /* There is no mechanism by which the parser stack can be popped below - ** empty in SQLite. */ - assert( pParser->yyidx>=0 ); -#ifndef NDEBUG - if( yyTraceFILE && pParser->yyidx>=0 ){ - fprintf(yyTraceFILE,"%sPopping %s\n", - yyTracePrompt, - yyTokenName[yytos->major]); - } -#endif - yymajor = yytos->major; - yy_destructor(pParser, yymajor, &yytos->minor); - pParser->yyidx--; - return yymajor; -} - -/* -** Deallocate and destroy a parser. Destructors are all called for -** all stack elements before shutting the parser down. -** -** Inputs: -**
    -**
  • A pointer to the parser. This should be a pointer -** obtained from ParseAlloc. -**
  • A pointer to a function used to reclaim memory obtained -** from malloc. -**
-*/ -void ParseFree( - void *p, /* The parser to be deleted */ - void (*freeProc)(void*) /* Function used to reclaim memory */ -){ - yyParser *pParser = (yyParser*)p; - /* In SQLite, we never try to destroy a parser that was not successfully - ** created in the first place. */ - if( NEVER(pParser==0) ) return; - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); -#if YYSTACKDEPTH<=0 - free(pParser->yystack); -#endif - (*freeProc)((void*)pParser); -} - -/* -** Return the peak depth of the stack for a parser. -*/ -#ifdef YYTRACKMAXSTACKDEPTH -int ParseStackPeak(void *p){ - yyParser *pParser = (yyParser*)p; - return pParser->yyidxMax; -} -#endif - -/* -** Find the appropriate action for a parser given the terminal -** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. -*/ -static int yy_find_shift_action( - yyParser *pParser, /* The parser */ - YYCODETYPE iLookAhead /* The look-ahead token */ -){ - int i; - int stateno = pParser->yystack[pParser->yyidx].stateno; - - if( stateno>=YY_MIN_REDUCE ) return stateno; - assert( stateno <= YY_SHIFT_COUNT ); - i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ -#ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - return yy_find_shift_action(pParser, iFallback); - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( -#if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && -#endif -#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; - } - } -#endif /* YYWILDCARD */ - } - return yy_default[stateno]; - }else{ - return yy_action[i]; - } -} - -/* -** Find the appropriate action for a parser given the non-terminal -** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. -*/ -static int yy_find_reduce_action( - int stateno, /* Current state number */ - YYCODETYPE iLookAhead /* The look-ahead token */ -){ - int i; -#ifdef YYERRORSYMBOL - if( stateno>YY_REDUCE_COUNT ){ - return yy_default[stateno]; - } -#else - assert( stateno<=YY_REDUCE_COUNT ); -#endif - i = yy_reduce_ofst[stateno]; - assert( i!=YY_REDUCE_USE_DFLT ); - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; -#ifdef YYERRORSYMBOL - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - return yy_default[stateno]; - } -#else - assert( i>=0 && iyyidx--; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will execute if the parser - ** stack every overflows */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ -} - -/* -** Print tracing information for a SHIFT action -*/ -#ifndef NDEBUG -static void yyTraceShift(yyParser *yypParser, int yyNewState){ - if( yyTraceFILE ){ - int i; - if( yyNewStateyyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); - }else{ - fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); - } - } -} -#else -# define yyTraceShift(X,Y) -#endif - -/* -** Perform a shift action. Return the number of errors. -*/ -static void yy_shift( - yyParser *yypParser, /* The parser to be shifted */ - int yyNewState, /* The new state to shift in */ - int yyMajor, /* The major token to shift in */ - YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ -){ - yyStackEntry *yytos; - yypParser->yyidx++; -#ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; - } -#endif -#if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH ){ - yyStackOverflow(yypParser, yypMinor); - return; - } -#else - if( yypParser->yyidx>=yypParser->yystksz ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz ){ - yyStackOverflow(yypParser, yypMinor); - return; - } - } -#endif - yytos = &yypParser->yystack[yypParser->yyidx]; - yytos->stateno = (YYACTIONTYPE)yyNewState; - yytos->major = (YYCODETYPE)yyMajor; - yytos->minor = *yypMinor; - yyTraceShift(yypParser, yyNewState); -} - -/* The following table contains information about every rule that -** is used during the reduce. -*/ -static const struct { - YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ - unsigned char nrhs; /* Number of right-hand side symbols in the rule */ -} yyRuleInfo[] = { -%% -}; - -static void yy_accept(yyParser*); /* Forward Declaration */ - -/* -** Perform a reduce action and the shift that must immediately -** follow the reduce. -*/ -static void yy_reduce( - yyParser *yypParser, /* The parser */ - int yyruleno /* Number of the rule by which to reduce */ -){ - int yygoto; /* The next state */ - int yyact; /* The next action */ - YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ - yyStackEntry *yymsp; /* The top of the parser's stack */ - int yysize; /* Amount to pop the stack */ - ParseARG_FETCH; - yymsp = &yypParser->yystack[yypParser->yyidx]; -#ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 - && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - yysize = yyRuleInfo[yyruleno].nrhs; - fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt, - yyRuleName[yyruleno], yymsp[-yysize].stateno); - } -#endif /* NDEBUG */ - - /* Silence complaints from purify about yygotominor being uninitialized - ** in some cases when it is copied into the stack after the following - ** switch. yygotominor is uninitialized when a rule reduces that does - ** not set the value of its left-hand side nonterminal. Leaving the - ** value of the nonterminal uninitialized is utterly harmless as long - ** as the value is never used. So really the only thing this code - ** accomplishes is to quieten purify. - ** - ** 2007-01-16: The wireshark project (www.wireshark.org) reports that - ** without this code, their parser segfaults. I'm not sure what there - ** parser is doing to make this happen. This is the second bug report - ** from wireshark this week. Clearly they are stressing Lemon in ways - ** that it has not been previously stressed... (SQLite ticket #2172) - */ - /*memset(&yygotominor, 0, sizeof(yygotominor));*/ - yygotominor = yyzerominor; - - - switch( yyruleno ){ - /* Beginning here are the reduction cases. A typical example - ** follows: - ** case 0: - ** #line - ** { ... } // User supplied code - ** #line - ** break; - */ -%% - }; - assert( yyruleno>=0 && yyrulenoyyidx -= yysize; - yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - /* If the reduce action popped at least - ** one element off the stack, then we can push the new element back - ** onto the stack here, and skip the stack overflow test in yy_shift(). - ** That gives a significant speed improvement. */ - if( yysize ){ - yypParser->yyidx++; - yymsp -= yysize-1; - yymsp->stateno = (YYACTIONTYPE)yyact; - yymsp->major = (YYCODETYPE)yygoto; - yymsp->minor = yygotominor; - yyTraceShift(yypParser, yyact); - }else{ - yy_shift(yypParser,yyact,yygoto,&yygotominor); - } - }else{ - assert( yyact == YY_ACCEPT_ACTION ); - yy_accept(yypParser); - } -} - -/* -** The following code executes when the parse fails -*/ -#ifndef YYNOERRORRECOVERY -static void yy_parse_failed( - yyParser *yypParser /* The parser */ -){ - ParseARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will be executed whenever the - ** parser fails */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} -#endif /* YYNOERRORRECOVERY */ - -/* -** The following code executes when a syntax error first occurs. -*/ -static void yy_syntax_error( - yyParser *yypParser, /* The parser */ - int yymajor, /* The major type of the error token */ - YYMINORTYPE yyminor /* The minor type of the error token */ -){ - ParseARG_FETCH; -#define TOKEN (yyminor.yy0) -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} - -/* -** The following is executed when the parser accepts -*/ -static void yy_accept( - yyParser *yypParser /* The parser */ -){ - ParseARG_FETCH; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); - } -#endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); - /* Here code is inserted which will be executed whenever the - ** parser accepts */ -%% - ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ -} - -/* The main parser program. -** The first argument is a pointer to a structure obtained from -** "ParseAlloc" which describes the current state of the parser. -** The second argument is the major token number. The third is -** the minor token. The fourth optional argument is whatever the -** user wants (and specified in the grammar) and is available for -** use by the action routines. -** -** Inputs: -**
    -**
  • A pointer to the parser (an opaque structure.) -**
  • The major token number. -**
  • The minor token number. -**
  • An option argument of a grammar-specified type. -**
-** -** Outputs: -** None. -*/ -void Parse( - void *yyp, /* The parser */ - int yymajor, /* The major token code number */ - ParseTOKENTYPE yyminor /* The value for the token */ - ParseARG_PDECL /* Optional %extra_argument parameter */ -){ - YYMINORTYPE yyminorunion; - int yyact; /* The parser action. */ -#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) - int yyendofinput; /* True if we are at the end of input */ -#endif -#ifdef YYERRORSYMBOL - int yyerrorhit = 0; /* True if yymajor has invoked an error */ -#endif - yyParser *yypParser; /* The parser */ - - /* (re)initialize the parser, if necessary */ - yypParser = (yyParser*)yyp; - if( yypParser->yyidx<0 ){ -#if YYSTACKDEPTH<=0 - if( yypParser->yystksz <=0 ){ - /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ - yyminorunion = yyzerominor; - yyStackOverflow(yypParser, &yyminorunion); - return; - } -#endif - yypParser->yyidx = 0; - yypParser->yyerrcnt = -1; - yypParser->yystack[0].stateno = 0; - yypParser->yystack[0].major = 0; - } - yyminorunion.yy0 = yyminor; -#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) - yyendofinput = (yymajor==0); -#endif - ParseARG_STORE; - -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); - } -#endif - - do{ - yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - yy_shift(yypParser,yyact,yymajor,&yyminorunion); - yypParser->yyerrcnt--; - yymajor = YYNOCODE; - }else if( yyact <= YY_MAX_REDUCE ){ - yy_reduce(yypParser,yyact-YY_MIN_REDUCE); - }else{ - assert( yyact == YY_ERROR_ACTION ); -#ifdef YYERRORSYMBOL - int yymx; -#endif -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); - } -#endif -#ifdef YYERRORSYMBOL - /* A syntax error has occurred. - ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". - ** - ** This is what we do if the grammar does define ERROR: - ** - ** * Call the %syntax_error function. - ** - ** * Begin popping the stack until we enter a state where - ** it is legal to shift the error symbol, then shift - ** the error symbol. - ** - ** * Set the error count to three. - ** - ** * Begin accepting and shifting new tokens. No new error - ** processing will occur until three tokens have been - ** shifted successfully. - ** - */ - if( yypParser->yyerrcnt<0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); - } - yymx = yypParser->yystack[yypParser->yyidx].major; - if( yymx==YYERRORSYMBOL || yyerrorhit ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sDiscard input token %s\n", - yyTracePrompt,yyTokenName[yymajor]); - } -#endif - yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - }else{ - while( - yypParser->yyidx >= 0 && - yymx != YYERRORSYMBOL && - (yyact = yy_find_reduce_action( - yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YY_MIN_REDUCE - ){ - yy_pop_parser_stack(yypParser); - } - if( yypParser->yyidx < 0 || yymajor==0 ){ - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yy_parse_failed(yypParser); - yymajor = YYNOCODE; - }else if( yymx!=YYERRORSYMBOL ){ - YYMINORTYPE u2; - u2.YYERRSYMDT = 0; - yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); - } - } - yypParser->yyerrcnt = 3; - yyerrorhit = 1; -#elif defined(YYNOERRORRECOVERY) - /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to - ** do any kind of error recovery. Instead, simply invoke the syntax - ** error routine and continue going as if nothing had happened. - ** - ** Applications can set this macro (for example inside %include) if - ** they intend to abandon the parse upon the first syntax error seen. - */ - yy_syntax_error(yypParser,yymajor,yyminorunion); - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - yymajor = YYNOCODE; - -#else /* YYERRORSYMBOL is not defined */ - /* This is what we do if the grammar does not define ERROR: - ** - ** * Report an error message, and throw away the input token. - ** - ** * If the input token is $, then fail the parse. - ** - ** As before, subsequent error messages are suppressed until - ** three input tokens have been successfully shifted. - */ - if( yypParser->yyerrcnt<=0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); - } - yypParser->yyerrcnt = 3; - yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); - if( yyendofinput ){ - yy_parse_failed(yypParser); - } - yymajor = YYNOCODE; -#endif - } - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); - } -#endif - return; -} diff --git a/src/main.c b/src/main.c index 9d0b478749..f7bab9b0ec 100644 --- a/src/main.c +++ b/src/main.c @@ -220,6 +220,12 @@ int sqlite3_initialize(void){ if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); sqlite3GlobalConfig.inProgress = 1; +#ifdef SQLITE_ENABLE_SQLLOG + { + extern void sqlite3_init_sqllog(void); + sqlite3_init_sqllog(); + } +#endif memset(pHash, 0, sizeof(sqlite3GlobalFunctions)); sqlite3RegisterGlobalFunctions(); if( sqlite3GlobalConfig.isPCacheInit==0 ){ diff --git a/src/os_unix.c b/src/os_unix.c index b322d238e8..3d4524296b 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3349,7 +3349,7 @@ static int unixWrite( } #endif -#if SQLITE_MAX_MMAP_SIZE>0 +#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ @@ -4774,7 +4774,9 @@ static void unixRemapfile( assert( pFd->mmapSizeActual>=pFd->mmapSize ); assert( MAP_FAILED!=0 ); +#ifdef SQLITE_MMAP_READWRITE if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; +#endif if( pOrig ){ #if HAVE_MREMAP diff --git a/src/os_win.c b/src/os_win.c index 251107528b..9ae40e22af 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -2602,7 +2602,7 @@ static int winWrite( "offset=%lld, lock=%d\n", osGetCurrentProcessId(), pFile, pFile->h, pBuf, amt, offset, pFile->locktype)); -#if SQLITE_MAX_MMAP_SIZE>0 +#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0 /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offsetmmapSize ){ @@ -4096,10 +4096,12 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ DWORD flags = FILE_MAP_READ; winUnmapfile(pFd); +#ifdef SQLITE_MMAP_READWRITE if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){ protect = PAGE_READWRITE; flags |= FILE_MAP_WRITE; } +#endif #if SQLITE_OS_WINRT pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); #elif defined(SQLITE_WIN32_HAS_WIDE) diff --git a/src/pager.c b/src/pager.c index b537e9e931..f633a77927 100644 --- a/src/pager.c +++ b/src/pager.c @@ -3392,12 +3392,21 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){ } /* -** Change the maximum number of in-memory pages that are allowed. +** Change the maximum number of in-memory pages that are allowed +** before attempting to recycle clean and unused pages. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } +/* +** Change the maximum number of in-memory pages that are allowed +** before attempting to spill pages to journal. +*/ +int sqlite3PagerSetSpillsize(Pager *pPager, int mxPage){ + return sqlite3PcacheSetSpillsize(pPager->pPCache, mxPage); +} + /* ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap. */ diff --git a/src/pager.h b/src/pager.h index 9d541dede9..22e73f4c76 100644 --- a/src/pager.h +++ b/src/pager.h @@ -123,6 +123,7 @@ void sqlite3PagerAlignReserve(Pager*,Pager*); #endif int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); +int sqlite3PagerSetSpillsize(Pager*, int); void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64); void sqlite3PagerShrink(Pager*); void sqlite3PagerSetFlags(Pager*,unsigned); diff --git a/src/parse.y b/src/parse.y index 797fa9bdeb..6ac2be21f2 100644 --- a/src/parse.y +++ b/src/parse.y @@ -60,6 +60,18 @@ */ #define yytestcase(X) testcase(X) +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENEVERNULL 1 + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + /* ** An instance of this structure holds information about the ** LIMIT clause of a SELECT statement. @@ -162,7 +174,7 @@ create_table_args ::= AS select(S). { sqlite3EndTable(pParse,0,0,0,S); sqlite3SelectDelete(pParse->db, S); } -%type table_options {u8} +%type table_options {int} table_options(A) ::= . {A = 0;} table_options(A) ::= WITHOUT nm(X). { if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ @@ -364,12 +376,12 @@ defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} // default behavior when there is a constraint conflict. // %type onconf {int} -%type orconf {u8} +%type orconf {int} %type resolvetype {int} onconf(A) ::= . {A = OE_Default;} onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;} orconf(A) ::= . {A = OE_Default;} -orconf(A) ::= OR resolvetype(X). {A = (u8)X;} +orconf(A) ::= OR resolvetype(X). {A = X;} resolvetype(A) ::= raisetype(X). {A = X;} resolvetype(A) ::= IGNORE. {A = OE_Ignore;} resolvetype(A) ::= REPLACE. {A = OE_Replace;} @@ -526,7 +538,7 @@ values(A) ::= values(X) COMMA LP exprlist(Y) RP. { // The "distinct" nonterminal is true (1) if the DISTINCT keyword is // present and false (0) if it is not. // -%type distinct {u16} +%type distinct {int} distinct(A) ::= DISTINCT. {A = SF_Distinct;} distinct(A) ::= ALL. {A = SF_All;} distinct(A) ::= . {A = 0;} @@ -534,7 +546,7 @@ distinct(A) ::= . {A = 0;} // selcollist is a list of expressions that are to become the return // values of the SELECT statement. The "*" in statements like // "SELECT * FROM ..." is encoded as a special expression with an -// opcode of TK_ALL. +// opcode of TK_ASTERISK. // %type selcollist {ExprList*} %destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);} @@ -548,11 +560,11 @@ selcollist(A) ::= sclp(P) expr(X) as(Y). { sqlite3ExprListSetSpan(pParse,A,&X); } selcollist(A) ::= sclp(P) STAR. { - Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0); + Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); A = sqlite3ExprListAppend(pParse, P, p); } selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). { - Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &Y); + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &Y); Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); A = sqlite3ExprListAppend(pParse,P, pDot); @@ -639,7 +651,6 @@ dbnm(A) ::= DOT nm(X). {A = X;} fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);} %type joinop {int} -%type joinop2 {int} joinop(X) ::= COMMA|JOIN. { X = JT_INNER; } joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); } joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); } @@ -800,7 +811,7 @@ cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) DEFAULT VALUES. sqlite3Insert(pParse, X, 0, F, R); } -%type insert_cmd {u8} +%type insert_cmd {int} insert_cmd(A) ::= INSERT orconf(R). {A = R;} insert_cmd(A) ::= REPLACE. {A = OE_Replace;} diff --git a/src/pcache.c b/src/pcache.c index e39262cb8c..5ac9d34a1e 100644 --- a/src/pcache.c +++ b/src/pcache.c @@ -21,6 +21,7 @@ struct PCache { PgHdr *pSynced; /* Last synced page in dirty page list */ int nRefSum; /* Sum of ref counts over all pages */ int szCache; /* Configured cache size */ + int szSpill; /* Size before spilling occurs */ int szPage; /* Size of every page in this cache */ int szExtra; /* Size of extra space for each page */ u8 bPurgeable; /* True if pages are on backing store */ @@ -110,10 +111,8 @@ static void pcacheUnpin(PgHdr *p){ } /* -** Compute the number of pages of cache requested. p->szCache is the +** Compute the number of pages of cache requested. p->szCache is the ** cache size requested by the "PRAGMA cache_size" statement. -** -** */ static int numberOfCachePages(PCache *p){ if( p->szCache>=0 ){ @@ -176,6 +175,7 @@ int sqlite3PcacheOpen( p->xStress = xStress; p->pStress = pStress; p->szCache = 100; + p->szSpill = 1; return sqlite3PcacheSetPageSize(p, szPage); } @@ -271,32 +271,33 @@ int sqlite3PcacheFetchStress( PgHdr *pPg; if( pCache->eCreate==2 ) return 0; - - /* Find a dirty page to write-out and recycle. First try to find a - ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC - ** cleared), but if that is not possible settle for any other - ** unreferenced dirty page. - */ - for(pPg=pCache->pSynced; - pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); - pPg=pPg->pDirtyPrev - ); - pCache->pSynced = pPg; - if( !pPg ){ - for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); - } - if( pPg ){ - int rc; + if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){ + /* Find a dirty page to write-out and recycle. First try to find a + ** page that does not require a journal-sync (one with PGHDR_NEED_SYNC + ** cleared), but if that is not possible settle for any other + ** unreferenced dirty page. + */ + for(pPg=pCache->pSynced; + pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC)); + pPg=pPg->pDirtyPrev + ); + pCache->pSynced = pPg; + if( !pPg ){ + for(pPg=pCache->pDirtyTail; pPg && pPg->nRef; pPg=pPg->pDirtyPrev); + } + if( pPg ){ + int rc; #ifdef SQLITE_LOG_CACHE_SPILL - sqlite3_log(SQLITE_FULL, - "spill page %d making room for %d - cache used: %d/%d", - pPg->pgno, pgno, - sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), + sqlite3_log(SQLITE_FULL, + "spill page %d making room for %d - cache used: %d/%d", + pPg->pgno, pgno, + sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache), numberOfCachePages(pCache)); #endif - rc = pCache->xStress(pCache->pStress, pPg); - if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - return rc; + rc = pCache->xStress(pCache->pStress, pPg); + if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ + return rc; + } } } *ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2); @@ -641,6 +642,25 @@ void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ numberOfCachePages(pCache)); } +/* +** Set the suggested cache-spill value. Make no changes if if the +** argument is zero. Return the effective cache-spill size, which will +** be the larger of the szSpill and szCache. +*/ +int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){ + int res; + assert( p->pCache!=0 ); + if( mxPage ){ + if( mxPage<0 ){ + mxPage = (int)((-1024*(i64)mxPage)/(p->szPage+p->szExtra)); + } + p->szSpill = mxPage; + } + res = numberOfCachePages(p); + if( resszSpill ) res = p->szSpill; + return res; +} + /* ** Free up as much memory as possible from the page cache. */ diff --git a/src/pcache.h b/src/pcache.h index a0724df22f..42c44cf7ba 100644 --- a/src/pcache.h +++ b/src/pcache.h @@ -146,6 +146,13 @@ void sqlite3PcacheSetCachesize(PCache *, int); int sqlite3PcacheGetCachesize(PCache *); #endif +/* Set or get the suggested spill-size for the specified pager-cache. +** +** The spill-size is the minimum number of pages in cache before the cache +** will attempt to spill dirty pages by calling xStress. +*/ +int sqlite3PcacheSetSpillsize(PCache *, int); + /* Free up as much memory as possible from the page cache */ void sqlite3PcacheShrink(PCache*); diff --git a/src/pragma.c b/src/pragma.c index 14c4811746..0d48057d21 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -279,7 +279,7 @@ const char *sqlite3JournalModename(int eMode){ ** ** Pragmas are of this form: ** -** PRAGMA [database.]id [= value] +** 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 @@ -291,8 +291,8 @@ const char *sqlite3JournalModename(int eMode){ */ void sqlite3Pragma( Parse *pParse, - Token *pId1, /* First part of [database.]id field */ - Token *pId2, /* Second part of [database.]id field, or NULL */ + Token *pId1, /* First part of [schema.]id field */ + Token *pId2, /* Second part of [schema.]id field, or NULL */ Token *pValue, /* Token for , or NULL */ int minusFlag /* True if a '-' sign preceded */ ){ @@ -313,7 +313,7 @@ void sqlite3Pragma( sqlite3VdbeRunOnlyOnce(v); pParse->nMem = 2; - /* Interpret the [database.] part of the pragma statement. iDb is the + /* 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; @@ -402,8 +402,8 @@ void sqlite3Pragma( #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) /* - ** PRAGMA [database.]default_cache_size - ** PRAGMA [database.]default_cache_size=N + ** PRAGMA [schema.]default_cache_size + ** PRAGMA [schema.]default_cache_size=N ** ** The first form reports the current persistent setting for the ** page cache size. The value returned is the maximum number of @@ -454,8 +454,8 @@ void sqlite3Pragma( #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) /* - ** PRAGMA [database.]page_size - ** PRAGMA [database.]page_size=N + ** PRAGMA [schema.]page_size + ** PRAGMA [schema.]page_size=N ** ** The first form reports the current setting for the ** database page size in bytes. The second form sets the @@ -481,8 +481,8 @@ void sqlite3Pragma( } /* - ** PRAGMA [database.]secure_delete - ** PRAGMA [database.]secure_delete=ON/OFF + ** PRAGMA [schema.]secure_delete + ** PRAGMA [schema.]secure_delete=ON/OFF ** ** The first form reports the current setting for the ** secure_delete flag. The second form changes the secure_delete @@ -507,8 +507,8 @@ void sqlite3Pragma( } /* - ** PRAGMA [database.]max_page_count - ** PRAGMA [database.]max_page_count=N + ** PRAGMA [schema.]max_page_count + ** PRAGMA [schema.]max_page_count=N ** ** The first form reports the current setting for the ** maximum number of pages in the database file. The @@ -519,7 +519,7 @@ void sqlite3Pragma( ** change. The only purpose is to provide an easy way to test ** the sqlite3AbsInt32() function. ** - ** PRAGMA [database.]page_count + ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ @@ -540,8 +540,8 @@ void sqlite3Pragma( } /* - ** PRAGMA [database.]locking_mode - ** PRAGMA [database.]locking_mode = (normal|exclusive) + ** PRAGMA [schema.]locking_mode + ** PRAGMA [schema.]locking_mode = (normal|exclusive) */ case PragTyp_LOCKING_MODE: { const char *zRet = "normal"; @@ -586,8 +586,8 @@ void sqlite3Pragma( } /* - ** PRAGMA [database.]journal_mode - ** PRAGMA [database.]journal_mode = + ** PRAGMA [schema.]journal_mode + ** PRAGMA [schema.]journal_mode = ** (delete|persist|off|truncate|memory|wal|off) */ case PragTyp_JOURNAL_MODE: { @@ -627,8 +627,8 @@ void sqlite3Pragma( } /* - ** PRAGMA [database.]journal_size_limit - ** PRAGMA [database.]journal_size_limit=N + ** PRAGMA [schema.]journal_size_limit + ** PRAGMA [schema.]journal_size_limit=N ** ** Get or set the size limit on rollback journal files. */ @@ -647,8 +647,8 @@ void sqlite3Pragma( #endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* - ** PRAGMA [database.]auto_vacuum - ** PRAGMA [database.]auto_vacuum=N + ** PRAGMA [schema.]auto_vacuum + ** PRAGMA [schema.]auto_vacuum=N ** ** Get or set the value of the database 'auto-vacuum' parameter. ** The value is one of: 0 NONE 1 FULL 2 INCREMENTAL @@ -699,7 +699,7 @@ void sqlite3Pragma( #endif /* - ** PRAGMA [database.]incremental_vacuum(N) + ** PRAGMA [schema.]incremental_vacuum(N) ** ** Do N steps of incremental vacuuming on a database. */ @@ -722,8 +722,8 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* - ** PRAGMA [database.]cache_size - ** PRAGMA [database.]cache_size=N + ** PRAGMA [schema.]cache_size + ** PRAGMA [schema.]cache_size=N ** ** The first form reports the current local setting for the ** page cache size. The second form sets the local @@ -735,19 +735,60 @@ void sqlite3Pragma( case PragTyp_CACHE_SIZE: { assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( !zRight ){ - if( sqlite3ReadSchema(pParse) ) goto pragma_out; returnSingleInt(v, "cache_size", pDb->pSchema->cache_size); }else{ int size = sqlite3Atoi(zRight); pDb->pSchema->cache_size = size; sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); - if( sqlite3ReadSchema(pParse) ) goto pragma_out; } break; } /* - ** PRAGMA [database.]mmap_size(N) + ** PRAGMA [schema.]cache_spill + ** PRAGMA cache_spill=BOOLEAN + ** PRAGMA [schema.]cache_spill=N + ** + ** The first form reports the current local setting for the + ** page cache spill size. The second form turns cache spill on + ** or off. When turnning cache spill on, the size is set to the + ** current cache_size. The third form sets a spill size that + ** may be different form the cache size. + ** If N is positive then that is the + ** number of pages in the cache. If N is negative, then the + ** number of pages is adjusted so that the cache uses -N kibibytes + ** of memory. + ** + ** If the number of cache_spill pages is less then the number of + ** cache_size pages, no spilling occurs until the page count exceeds + ** the number of cache_size pages. + ** + ** The cache_spill=BOOLEAN setting applies to all attached schemas, + ** not just the schema specified. + */ + case PragTyp_CACHE_SPILL: { + assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); + if( !zRight ){ + returnSingleInt(v, "cache_spill", + (db->flags & SQLITE_CacheSpill)==0 ? 0 : + sqlite3BtreeSetSpillSize(pDb->pBt,0)); + }else{ + int size = 1; + if( sqlite3GetInt32(zRight, &size) ){ + sqlite3BtreeSetSpillSize(pDb->pBt, size); + } + if( sqlite3GetBoolean(zRight, size!=0) ){ + db->flags |= SQLITE_CacheSpill; + }else{ + db->flags &= ~SQLITE_CacheSpill; + } + setAllPagerFlags(db); + } + break; + } + + /* + ** PRAGMA [schema.]mmap_size(N) ** ** Used to set mapping size limit. The mapping size limit is ** used to limit the aggregate size of all memory mapped regions of the @@ -891,8 +932,8 @@ void sqlite3Pragma( #if SQLITE_ENABLE_LOCKING_STYLE /* - ** PRAGMA [database.]lock_proxy_file - ** PRAGMA [database.]lock_proxy_file = ":auto:"|"lock_file_path" + ** PRAGMA [schema.]lock_proxy_file + ** PRAGMA [schema.]lock_proxy_file = ":auto:"|"lock_file_path" ** ** Return or set the value of the lock_proxy_file flag. Changing ** the value sets a specific file to be used for database access locks. @@ -927,8 +968,8 @@ void sqlite3Pragma( #endif /* SQLITE_ENABLE_LOCKING_STYLE */ /* - ** PRAGMA [database.]synchronous - ** PRAGMA [database.]synchronous=OFF|ON|NORMAL|FULL + ** PRAGMA [schema.]synchronous + ** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL ** ** Return or set the local value of the synchronous flag. Changing ** the local value does not make changes to the disk file and the @@ -1324,7 +1365,7 @@ void sqlite3Pragma( case PragTyp_PARSER_TRACE: { if( zRight ){ if( sqlite3GetBoolean(zRight, 0) ){ - sqlite3ParserTrace(stderr, "parser: "); + sqlite3ParserTrace(stdout, "parser: "); }else{ sqlite3ParserTrace(0, 0); } @@ -1644,16 +1685,16 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS /* - ** PRAGMA [database.]schema_version - ** PRAGMA [database.]schema_version = + ** PRAGMA [schema.]schema_version + ** PRAGMA [schema.]schema_version = ** - ** PRAGMA [database.]user_version - ** PRAGMA [database.]user_version = + ** PRAGMA [schema.]user_version + ** PRAGMA [schema.]user_version = ** - ** PRAGMA [database.]freelist_count = + ** PRAGMA [schema.]freelist_count = ** - ** PRAGMA [database.]application_id - ** PRAGMA [database.]application_id = + ** PRAGMA [schema.]application_id + ** PRAGMA [schema.]application_id = ** ** The pragma's schema_version and user_version are used to set or get ** the value of the schema-version and user-version, respectively. Both @@ -1728,7 +1769,7 @@ void sqlite3Pragma( #ifndef SQLITE_OMIT_WAL /* - ** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate + ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ diff --git a/src/pragma.h b/src/pragma.h index 9e206dac49..24a6c9d710 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -8,43 +8,44 @@ #define PragTyp_FLAG 2 #define PragTyp_BUSY_TIMEOUT 3 #define PragTyp_CACHE_SIZE 4 -#define PragTyp_CASE_SENSITIVE_LIKE 5 -#define PragTyp_COLLATION_LIST 6 -#define PragTyp_COMPILE_OPTIONS 7 -#define PragTyp_DATA_STORE_DIRECTORY 8 -#define PragTyp_DATABASE_LIST 9 -#define PragTyp_DEFAULT_CACHE_SIZE 10 -#define PragTyp_ENCODING 11 -#define PragTyp_FOREIGN_KEY_CHECK 12 -#define PragTyp_FOREIGN_KEY_LIST 13 -#define PragTyp_INCREMENTAL_VACUUM 14 -#define PragTyp_INDEX_INFO 15 -#define PragTyp_INDEX_LIST 16 -#define PragTyp_INTEGRITY_CHECK 17 -#define PragTyp_JOURNAL_MODE 18 -#define PragTyp_JOURNAL_SIZE_LIMIT 19 -#define PragTyp_LOCK_PROXY_FILE 20 -#define PragTyp_LOCKING_MODE 21 -#define PragTyp_PAGE_COUNT 22 -#define PragTyp_MMAP_SIZE 23 -#define PragTyp_PAGE_SIZE 24 -#define PragTyp_SECURE_DELETE 25 -#define PragTyp_SHRINK_MEMORY 26 -#define PragTyp_SOFT_HEAP_LIMIT 27 -#define PragTyp_STATS 28 -#define PragTyp_SYNCHRONOUS 29 -#define PragTyp_TABLE_INFO 30 -#define PragTyp_TEMP_STORE 31 -#define PragTyp_TEMP_STORE_DIRECTORY 32 -#define PragTyp_THREADS 33 -#define PragTyp_WAL_AUTOCHECKPOINT 34 -#define PragTyp_WAL_CHECKPOINT 35 -#define PragTyp_ACTIVATE_EXTENSIONS 36 -#define PragTyp_HEXKEY 37 -#define PragTyp_KEY 38 -#define PragTyp_REKEY 39 -#define PragTyp_LOCK_STATUS 40 -#define PragTyp_PARSER_TRACE 41 +#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_INCREMENTAL_VACUUM 15 +#define PragTyp_INDEX_INFO 16 +#define PragTyp_INDEX_LIST 17 +#define PragTyp_INTEGRITY_CHECK 18 +#define PragTyp_JOURNAL_MODE 19 +#define PragTyp_JOURNAL_SIZE_LIMIT 20 +#define PragTyp_LOCK_PROXY_FILE 21 +#define PragTyp_LOCKING_MODE 22 +#define PragTyp_PAGE_COUNT 23 +#define PragTyp_MMAP_SIZE 24 +#define PragTyp_PAGE_SIZE 25 +#define PragTyp_SECURE_DELETE 26 +#define PragTyp_SHRINK_MEMORY 27 +#define PragTyp_SOFT_HEAP_LIMIT 28 +#define PragTyp_STATS 29 +#define PragTyp_SYNCHRONOUS 30 +#define PragTyp_TABLE_INFO 31 +#define PragTyp_TEMP_STORE 32 +#define PragTyp_TEMP_STORE_DIRECTORY 33 +#define PragTyp_THREADS 34 +#define PragTyp_WAL_AUTOCHECKPOINT 35 +#define PragTyp_WAL_CHECKPOINT 36 +#define PragTyp_ACTIVATE_EXTENSIONS 37 +#define PragTyp_HEXKEY 38 +#define PragTyp_KEY 39 +#define PragTyp_REKEY 40 +#define PragTyp_LOCK_STATUS 41 +#define PragTyp_PARSER_TRACE 42 #define PragFlag_NeedSchema 0x01 #define PragFlag_ReadOnly 0x02 static const struct sPragmaNames { @@ -86,14 +87,14 @@ static const struct sPragmaNames { #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) { /* zName: */ "cache_size", /* ePragTyp: */ PragTyp_CACHE_SIZE, - /* ePragFlag: */ 0, + /* ePragFlag: */ PragFlag_NeedSchema, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) { /* zName: */ "cache_spill", - /* ePragTyp: */ PragTyp_FLAG, + /* ePragTyp: */ PragTyp_CACHE_SPILL, /* ePragFlag: */ 0, - /* iArg: */ SQLITE_CacheSpill }, + /* iArg: */ 0 }, #endif { /* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, diff --git a/src/printf.c b/src/printf.c index dba928d102..9caeef8ff7 100644 --- a/src/printf.c +++ b/src/printf.c @@ -726,7 +726,7 @@ void sqlite3VXPrintf( if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' '); if( zExtra ){ - sqlite3_free(zExtra); + sqlite3DbFree(pAccum->db, zExtra); zExtra = 0; } }/* End for loop over the format string */ diff --git a/src/select.c b/src/select.c index 8db983891f..3d69dfb03a 100644 --- a/src/select.c +++ b/src/select.c @@ -118,7 +118,7 @@ Select *sqlite3SelectNew( memset(pNew, 0, sizeof(*pNew)); } if( pEList==0 ){ - pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0)); + pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); } pNew->pEList = pEList; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); @@ -1596,13 +1596,15 @@ int sqlite3ColumnsFromExprList( ){ sqlite3 *db = pParse->db; /* Database connection */ int i, j; /* Loop counters */ - int cnt; /* Index added to make the name unique */ + u32 cnt; /* Index added to make the name unique */ Column *aCol, *pCol; /* For looping over result columns */ int nCol; /* Number of columns in the result set */ Expr *p; /* Expression for a single result column */ char *zName; /* Column name */ int nName; /* Size of name in zName[] */ + Hash ht; /* Hash table of column names */ + sqlite3HashInit(&ht); if( pEList ){ nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); @@ -1614,13 +1616,12 @@ int sqlite3ColumnsFromExprList( *pnCol = nCol; *paCol = aCol; - for(i=0, pCol=aCol; imallocFailed; i++, pCol++){ /* Get an appropriate name for the column */ p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS " phrase, use as the name */ - zName = sqlite3DbStrDup(db, zName); }else{ Expr *pColExpr = p; /* The expression that is the result column name */ Table *pTab; /* Table associated with this expression */ @@ -1633,41 +1634,37 @@ int sqlite3ColumnsFromExprList( int iCol = pColExpr->iColumn; pTab = pColExpr->pTab; if( iCol<0 ) iCol = pTab->iPKey; - zName = sqlite3MPrintf(db, "%s", - iCol>=0 ? pTab->aCol[iCol].zName : "rowid"); + zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; }else if( pColExpr->op==TK_ID ){ assert( !ExprHasProperty(pColExpr, EP_IntValue) ); - zName = sqlite3MPrintf(db, "%s", pColExpr->u.zToken); + zName = pColExpr->u.zToken; }else{ /* Use the original text of the column expression as its name */ - zName = sqlite3MPrintf(db, "%s", pEList->a[i].zSpan); + zName = pEList->a[i].zSpan; } } - if( db->mallocFailed ){ - sqlite3DbFree(db, zName); - break; - } + zName = sqlite3MPrintf(db, "%s", zName); /* Make sure the column name is unique. If the name is not unique, ** append an integer to the name so that it becomes unique. */ - nName = sqlite3Strlen30(zName); - for(j=cnt=0; j1 && sqlite3Isdigit(zName[k]); k--){} - if( k>=0 && zName[k]==':' ) nName = k; - zName[nName] = 0; - zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); - sqlite3DbFree(db, zName); - zName = zNewName; - j = -1; - if( zName==0 ) break; + cnt = 0; + while( zName && sqlite3HashFind(&ht, zName)!=0 ){ + nName = sqlite3Strlen30(zName); + if( nName>0 ){ + for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){} + if( zName[j]==':' ) nName = j; } + zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt); + if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt); } pCol->zName = zName; + sqlite3ColumnPropertiesFromName(0, pCol); + if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){ + db->mallocFailed = 1; + } } + sqlite3HashClear(&ht); if( db->mallocFailed ){ for(j=0; jpSrc = pNewSrc; - p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0)); + p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); p->op = TK_SELECT; p->pWhere = 0; pNew->pGroupBy = 0; @@ -3972,7 +3969,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ ** object that the returned CTE belongs to. */ static struct Cte *searchWith( - With *pWith, /* Current outermost WITH clause */ + With *pWith, /* Current innermost WITH clause */ struct SrcList_item *pItem, /* FROM clause element to resolve */ With **ppContext /* OUT: WITH clause return value belongs to */ ){ @@ -4003,11 +4000,12 @@ static struct Cte *searchWith( ** statement with which it is associated. */ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ - assert( bFree==0 || pParse->pWith==0 ); + assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) ); if( pWith ){ + assert( pParse->pWith!=pWith ); pWith->pOuter = pParse->pWith; pParse->pWith = pWith; - pParse->bFreeWith = bFree; + if( bFree ) pParse->pWithToFree = pWith; } } @@ -4100,6 +4098,7 @@ static int withExpand( pSavedWith = pParse->pWith; pParse->pWith = pWith; sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel); + pParse->pWith = pWith; for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; @@ -4280,19 +4279,20 @@ static int selectExpander(Walker *pWalker, Select *p){ /* For every "*" that occurs in the column list, insert the names of ** all columns in all tables. And for every TABLE.* insert the names ** of all columns in TABLE. The parser inserted a special expression - ** with the TK_ALL operator for each "*" that it found in the column list. - ** The following code just has to locate the TK_ALL expressions and expand - ** each one to the list of all columns in all tables. + ** with the TK_ASTERISK operator for each "*" that it found in the column + ** list. The following code just has to locate the TK_ASTERISK + ** expressions and expand each one to the list of all columns in + ** all tables. ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; knExpr; k++){ pE = pEList->a[k].pExpr; - if( pE->op==TK_ALL ) break; + if( pE->op==TK_ASTERISK ) break; assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); - if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break; + if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break; } if( knExpr ){ /* @@ -4310,7 +4310,9 @@ static int selectExpander(Walker *pWalker, Select *p){ pE = a[k].pExpr; pRight = pE->pRight; assert( pE->op!=TK_DOT || pRight!=0 ); - if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){ + if( pE->op!=TK_ASTERISK + && (pE->op!=TK_DOT || pRight->op!=TK_ASTERISK) + ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); @@ -4362,12 +4364,13 @@ static int selectExpander(Walker *pWalker, Select *p){ continue; } - /* If a column is marked as 'hidden' (currently only possible - ** for virtual tables), do not include it in the expanded - ** result-set list. + /* If a column is marked as 'hidden', omit it from the expanded + ** result-set list unless the SELECT has the SF_IncludeHidden + ** bit set. */ - if( IsHiddenColumn(&pTab->aCol[j]) ){ - assert(IsVirtual(pTab)); + if( (p->selFlags & SF_IncludeHidden)==0 + && IsHiddenColumn(&pTab->aCol[j]) + ){ continue; } tableSeen = 1; diff --git a/src/shell.c b/src/shell.c index ec76eeea95..7822919ecd 100644 --- a/src/shell.c +++ b/src/shell.c @@ -165,7 +165,7 @@ static sqlite3_int64 timeOfDay(void){ static sqlite3_vfs *clockVfs = 0; sqlite3_int64 t; if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); - if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ + if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){ clockVfs->xCurrentTimeInt64(clockVfs, &t); }else{ double r; @@ -2649,7 +2649,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){ { "schema size:", "SELECT total(length(sql)) FROM %s" }, }; - sqlite3_file *pFile; + sqlite3_file *pFile = 0; int i; char *zSchemaTab; char *zDb = nArg>=2 ? azArg[1] : "main"; @@ -4882,10 +4882,10 @@ int SQLITE_CDECL main(int argc, char **argv){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz>70000 ) sz = 70000; - if( sz<800 ) sz = 800; + if( sz<0 ) sz = 0; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); - if( n<10 ) n = 10; - sqlite3_config(SQLITE_CONFIG_PAGECACHE, malloc(n*sz+1), sz, n); + sqlite3_config(SQLITE_CONFIG_PAGECACHE, + (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n); data.shellFlgs |= SHFLG_Pagecache; }else if( strcmp(z,"-lookaside")==0 ){ int n, sz; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ff5cf27ec1..c0bed1336c 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -1599,29 +1599,34 @@ struct sqlite3_mem_methods { ** ** ** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
-**
^The SQLITE_CONFIG_PAGECACHE option specifies a static memory buffer +**
^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool ** that SQLite can use for the database page cache with the default page ** cache implementation. -** This configuration should not be used if an application-define page -** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2] -** configuration option. +** This configuration option is a no-op if an application-define page +** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]. ** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to -** 8-byte aligned -** memory, the size of each page buffer (sz), and the number of pages (N). +** 8-byte aligned memory (pMem), the size of each page cache line (sz), +** and the number of cache lines (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 65536) plus some extra bytes for each ** page header. ^The number of extra bytes needed by the page header -** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option -** to [sqlite3_config()]. +** can be determined using [SQLITE_CONFIG_PCACHE_HDRSZ]. ** ^It is harmless, apart from the wasted memory, -** for the sz parameter to be larger than necessary. The first -** argument should pointer to an 8-byte aligned block of memory that -** is at least sz*N bytes of memory, otherwise subsequent behavior is -** undefined. -** ^SQLite will use the memory provided by the first argument to satisfy its -** memory needs for the first N pages that it adds to cache. ^If additional -** page cache memory is needed beyond what is provided by this option, then -** SQLite goes to [sqlite3_malloc()] for the additional storage space.
+** for the sz parameter to be larger than necessary. The pMem +** argument must be either a NULL pointer or a pointer to an 8-byte +** aligned block of memory of at least sz*N bytes, otherwise +** subsequent behavior is undefined. +** ^When pMem is not NULL, SQLite will strive to use the memory provided +** to satisfy page cache needs, falling back to [sqlite3_malloc()] if +** a page cache line is larger than sz bytes or if all of the pMem buffer +** is exhausted. +** ^If pMem is NULL and N is non-zero, then each database connection +** does an initial bulk allocation for page cache memory +** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or +** of -1024*N bytes if N is negative, . ^If additional +** page cache memory is needed beyond what is provided by the initial +** allocation, then SQLite goes to [sqlite3_malloc()] separately for each +** additional cache line. ** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
**
^The SQLITE_CONFIG_HEAP option specifies a static memory buffer diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3b86e49edb..0f02c5052f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -527,7 +527,6 @@ # define SQLITE_DEFAULT_PCACHE_INITSZ 100 #endif - /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. @@ -1682,7 +1681,7 @@ struct Table { /* ** Allowed values for Table.tabFlags. ** -** TF_OOOHidden applies to virtual tables that have hidden columns that are +** TF_OOOHidden applies to tables or view that have hidden columns that are ** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING ** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden, ** the TF_OOOHidden attribute would apply in this case. Such tables require @@ -1705,12 +1704,28 @@ struct Table { */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0) -# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) #else # define IsVirtual(X) 0 -# define IsHiddenColumn(X) 0 #endif +/* +** Macros to determine if a column is hidden. IsOrdinaryHiddenColumn() +** only works for non-virtual tables (ordinary tables and views) and is +** always false unless SQLITE_ENABLE_HIDDEN_COLUMNS is defined. The +** IsHiddenColumn() macro is general purpose. +*/ +#if defined(SQLITE_ENABLE_HIDDEN_COLUMNS) +# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +# define IsOrdinaryHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +#elif !defined(SQLITE_OMIT_VIRTUALTABLE) +# define IsHiddenColumn(X) (((X)->colFlags & COLFLAG_HIDDEN)!=0) +# define IsOrdinaryHiddenColumn(X) 0 +#else +# define IsHiddenColumn(X) 0 +# define IsOrdinaryHiddenColumn(X) 0 +#endif + + /* Does the table have a rowid */ #define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0) #define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0) @@ -2504,6 +2519,7 @@ struct Select { #define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x2000 /* The recursive part of a recursive CTE */ #define SF_Converted 0x4000 /* By convertCompoundSelectToSubquery() */ +#define SF_IncludeHidden 0x8000 /* Include hidden columns in output */ /* @@ -2762,7 +2778,6 @@ struct Parse { 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() */ @@ -2789,6 +2804,7 @@ 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 */ + With *pWithToFree; /* Free this WITH object at the end of the parse */ }; /* @@ -3283,6 +3299,7 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list); void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); void sqlite3TreeViewSelect(TreeView*, const Select*, u8); + void sqlite3TreeViewWith(TreeView*, const With*, u8); #endif @@ -3326,6 +3343,7 @@ void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); +void sqlite3ColumnPropertiesFromName(Table*, Column*); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int); diff --git a/src/test1.c b/src/test1.c index 7ce4ed5a5a..186e4e4684 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2226,6 +2226,49 @@ static int test_stmt_scanstatus_reset( } #endif +#ifdef SQLITE_ENABLE_SQLLOG +/* +** Usage: sqlite3_config_sqllog +** +** Zero the SQLITE_CONFIG_SQLLOG configuration +*/ +static int test_config_sqllog( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + if( objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0); + return TCL_OK; +} +#endif + +/* +** Usage: vfs_current_time_int64 +** +** Return the value returned by the default VFS's xCurrentTimeInt64 method. +*/ +static int vfsCurrentTimeInt64( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + i64 t; + sqlite3_vfs *pVfs = sqlite3_vfs_find(0); + if( objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + pVfs->xCurrentTimeInt64(pVfs, &t); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t)); + return TCL_OK; +} + /* ** Usage: sqlite3_next_stmt DB STMT ** @@ -7036,7 +7079,10 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_stmt_scanstatus", test_stmt_scanstatus, 0 }, { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset, 0 }, #endif - +#ifdef SQLITE_ENABLE_SQLLOG + { "sqlite3_config_sqllog", test_config_sqllog, 0 }, +#endif + { "vfs_current_time_int64", vfsCurrentTimeInt64, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; static int longdouble_size = sizeof(LONGDOUBLE_TYPE); diff --git a/src/test_config.c b/src/test_config.c index 23db433c93..a5c42f30d5 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -125,6 +125,12 @@ static void set_options(Tcl_Interp *interp){ Tcl_SetVar2(interp, "sqlite_options", "cursorhints", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS + Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "hiddencolumns", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_ENABLE_MEMSYS3 Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY); #else @@ -669,6 +675,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "0", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_SQLLOG + Tcl_SetVar2(interp, "sqlite_options", "sqllog", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "sqllog", "0", TCL_GLOBAL_ONLY); +#endif + #define LINKVAR(x) { \ static const int cv_ ## x = SQLITE_ ## x; \ Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \ diff --git a/src/test_sqllog.c b/src/test_sqllog.c index 6c0bf954ba..31d5ad2f5b 100644 --- a/src/test_sqllog.c +++ b/src/test_sqllog.c @@ -46,6 +46,12 @@ ** separate copy is taken each time the database file is opened or attached) ** by setting the environment variable SQLITE_SQLLOG_REUSE_FILES to 0. ** +** If the environment variable SQLITE_SQLLOG_CONDITIONAL is defined, then +** logging is only done for database connections if a file named +** "-sqllog" exists in the same directly as the main database +** file when it is first opened ("" is replaced by the actual +** name of the main database file). +** ** OUTPUT: ** ** The SQLITE_SQLLOG_DIR is populated with three types of files: @@ -88,6 +94,7 @@ static int getProcessId(void){ /* Names of environment variables to be used */ #define ENVIRONMENT_VARIABLE1_NAME "SQLITE_SQLLOG_DIR" #define ENVIRONMENT_VARIABLE2_NAME "SQLITE_SQLLOG_REUSE_FILES" +#define ENVIRONMENT_VARIABLE3_NAME "SQLITE_SQLLOG_CONDITIONAL" /* Assume that all database and database file names are shorted than this. */ #define SQLLOG_NAMESZ 512 @@ -116,6 +123,7 @@ static struct SLGlobal { int nConn; /* Size of aConn[] array */ /* Protected by SLGlobal.mutex */ + int bConditional; /* Only trace if *-sqllog file is present */ int bReuse; /* True to avoid extra copies of db files */ char zPrefix[SQLLOG_NAMESZ]; /* Prefix for all created files */ char zIdx[SQLLOG_NAMESZ]; /* Full path to *.idx file */ @@ -215,7 +223,7 @@ static char *sqllogFindFile(const char *zFile){ } static int sqllogFindAttached( - struct SLConn *p, /* Database connection */ + sqlite3 *db, /* Database connection */ const char *zSearch, /* Name to search for (or NULL) */ char *zName, /* OUT: Name of attached database */ char *zFile /* OUT: Name of attached file */ @@ -228,7 +236,7 @@ static int sqllogFindAttached( ** described by the last row returned. */ assert( sqllogglobal.bRec==0 ); sqllogglobal.bRec = 1; - rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); + rc = sqlite3_prepare_v2(db, "PRAGMA database_list", -1, &pStmt, 0); if( rc==SQLITE_OK ){ while( SQLITE_ROW==sqlite3_step(pStmt) ){ const char *zVal1; int nVal1; @@ -236,7 +244,9 @@ static int sqllogFindAttached( zVal1 = (const char*)sqlite3_column_text(pStmt, 1); nVal1 = sqlite3_column_bytes(pStmt, 1); - memcpy(zName, zVal1, nVal1+1); + if( zName ){ + memcpy(zName, zVal1, nVal1+1); + } zVal2 = (const char*)sqlite3_column_text(pStmt, 2); nVal2 = sqlite3_column_bytes(pStmt, 2); @@ -285,7 +295,7 @@ static void sqllogCopydb(struct SLConn *p, const char *zSearch, int bLog){ char *zInit = 0; int rc; - rc = sqllogFindAttached(p, zSearch, zName, zFile); + rc = sqllogFindAttached(p->db, zSearch, zName, zFile); if( rc!=SQLITE_OK ) return; if( zFile[0]=='\0' ){ @@ -405,6 +415,35 @@ static void testSqllogStmt(struct SLConn *p, const char *zSql){ } } +/* +** The database handle passed as the only argument has just been opened. +** Return true if this module should log initial databases and SQL +** statements for this connection, or false otherwise. +** +** If an error occurs, sqlite3_log() is invoked to report it to the user +** and zero returned. +*/ +static int sqllogTraceDb(sqlite3 *db){ + int bRet = 1; + if( sqllogglobal.bConditional ){ + char zFile[SQLLOG_NAMESZ]; /* Attached database name */ + int rc = sqllogFindAttached(db, "main", 0, zFile); + if( rc==SQLITE_OK ){ + int nFile = strlen(zFile); + if( (SQLLOG_NAMESZ-nFile)<8 ){ + sqlite3_log(SQLITE_IOERR, + "sqllogTraceDb(): database name too long (%d bytes)", nFile + ); + bRet = 0; + }else{ + memcpy(&zFile[nFile], "-sqllog", 8); + bRet = !access(zFile, F_OK); + } + } + } + return bRet; +} + /* ** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog(). ** @@ -439,15 +478,19 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ if( sqllogglobal.mutex==0 ){ sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); } - p = &sqllogglobal.aConn[sqllogglobal.nConn++]; - p->fd = 0; - p->db = db; - p->iLog = sqllogglobal.iNextLog++; sqlite3_mutex_leave(master); - /* Open the log and take a copy of the main database file */ sqlite3_mutex_enter(sqllogglobal.mutex); - if( sqllogglobal.bRec==0 ){ + if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){ + + sqlite3_mutex_enter(master); + p = &sqllogglobal.aConn[sqllogglobal.nConn++]; + p->fd = 0; + p->db = db; + p->iLog = sqllogglobal.iNextLog++; + sqlite3_mutex_leave(master); + + /* Open the log and take a copy of the main database file */ sqllogOpenlog(p); if( p->fd ) sqllogCopydb(p, "main", 0); } @@ -461,20 +504,21 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ p = &sqllogglobal.aConn[i]; if( p->db==db ) break; } - if( i==sqllogglobal.nConn ) return; /* A database handle close command */ if( eType==2 ){ sqlite3_mutex_enter(master); - if( p->fd ) fclose(p->fd); - p->db = 0; - p->fd = 0; + if( ifd ) fclose(p->fd); + p->db = 0; + p->fd = 0; + sqllogglobal.nConn--; + } - sqllogglobal.nConn--; if( sqllogglobal.nConn==0 ){ sqlite3_mutex_free(sqllogglobal.mutex); sqllogglobal.mutex = 0; - }else{ + }else if( i0 ){ memmove(p, &p[1], nShift*sizeof(struct SLConn)); @@ -483,7 +527,7 @@ static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){ sqlite3_mutex_leave(master); /* An ordinary SQL command. */ - }else if( p->fd ){ + }else if( ifd ){ sqlite3_mutex_enter(sqllogglobal.mutex); if( sqllogglobal.bRec==0 ){ testSqllogStmt(p, zSql); @@ -504,6 +548,9 @@ void sqlite3_init_sqllog(void){ if( SQLITE_OK==sqlite3_config(SQLITE_CONFIG_SQLLOG, testSqllog, 0) ){ memset(&sqllogglobal, 0, sizeof(sqllogglobal)); sqllogglobal.bReuse = 1; + if( getenv(ENVIRONMENT_VARIABLE3_NAME) ){ + sqllogglobal.bConditional = 1; + } } } } diff --git a/src/tokenize.c b/src/tokenize.c index 9c1403bb29..b85e35dc10 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -369,8 +369,8 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ break; } for(i=1; IdChar(z[i]); i++){} - *tokenType = keywordCode((char*)z, i); - return i; + *tokenType = TK_ID; + return keywordCode((char*)z, i, tokenType); } } *tokenType = TK_ILLEGAL; @@ -416,7 +416,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ assert( pParse->azVar==0 ); enableLookaside = db->lookaside.bEnabled; if( db->lookaside.pStart ) db->lookaside.bEnabled = 1; - while( !db->mallocFailed && zSql[i]!=0 ){ + while( zSql[i]!=0 ){ assert( i>=0 ); pParse->sLastToken.z = &zSql[i]; pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); @@ -425,35 +425,25 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ pParse->rc = SQLITE_TOOBIG; break; } - switch( tokenType ){ - case TK_SPACE: { - if( db->u1.isInterrupted ){ - sqlite3ErrorMsg(pParse, "interrupt"); - pParse->rc = SQLITE_INTERRUPT; - goto abort_parse; - } + if( tokenType>=TK_SPACE ){ + assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL ); + if( db->u1.isInterrupted ){ + sqlite3ErrorMsg(pParse, "interrupt"); + pParse->rc = SQLITE_INTERRUPT; break; } - case TK_ILLEGAL: { + if( tokenType==TK_ILLEGAL ){ sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &pParse->sLastToken); - goto abort_parse; - } - case TK_SEMI: { - pParse->zTail = &zSql[i]; - /* Fall thru into the default case */ - } - default: { - sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); - lastTokenParsed = tokenType; - if( pParse->rc!=SQLITE_OK ){ - goto abort_parse; - } break; } + }else{ + if( tokenType==TK_SEMI ) pParse->zTail = &zSql[i]; + sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse); + lastTokenParsed = tokenType; + if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break; } } -abort_parse: assert( nErr==0 ); if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ assert( zSql[i]==0 ); @@ -510,7 +500,7 @@ abort_parse: sqlite3DeleteTable(db, pParse->pNewTable); } - if( pParse->bFreeWith ) sqlite3WithDelete(db, pParse->pWith); + sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DeleteTrigger(db, pParse->pNewTrigger); for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]); sqlite3DbFree(db, pParse->azVar); diff --git a/src/treeview.c b/src/treeview.c index 971de4e8bc..a26e9e2b9f 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -79,6 +79,45 @@ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ sqlite3TreeViewLine(p, "%s", zLabel); } +/* +** Generate a human-readable description of a WITH clause. +*/ +void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ + int i; + if( pWith==0 ) return; + if( pWith->nCte==0 ) return; + if( pWith->pOuter ){ + sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); + }else{ + sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); + } + if( pWith->nCte>0 ){ + pView = sqlite3TreeViewPush(pView, 1); + for(i=0; inCte; i++){ + StrAccum x; + char zLine[1000]; + const struct Cte *pCte = &pWith->a[i]; + sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); + sqlite3XPrintf(&x, 0, "%s", pCte->zName); + if( pCte->pCols && pCte->pCols->nExpr>0 ){ + char cSep = '('; + int j; + for(j=0; jpCols->nExpr; j++){ + sqlite3XPrintf(&x, 0, "%c%s", cSep, pCte->pCols->a[j].zName); + cSep = ','; + } + sqlite3XPrintf(&x, 0, ")"); + } + sqlite3XPrintf(&x, 0, " AS"); + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, inCte-1); + sqlite3TreeViewSelect(pView, pCte->pSelect, 0); + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); + } +} + /* ** Generate a human-readable description of a the Select object. @@ -87,6 +126,11 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); + if( p->pWith ){ + sqlite3TreeViewWith(pView, p->pWith, 1); + cnt = 1; + sqlite3TreeViewPush(pView, 1); + } do{ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7e89229be6..86099e1bb4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -158,6 +158,12 @@ static void test_addop_breakpoint(void){ ** the sqlite3VdbeChangeP4() function to change the value of the P4 ** operand. */ +static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){ + assert( p->pParse->nOpAlloc<=p->nOp ); + if( growOpArray(p, 1) ) return 1; + assert( p->pParse->nOpAlloc>p->nOp ); + return sqlite3VdbeAddOp3(p, op, p1, p2, p3); +} int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ int i; VdbeOp *pOp; @@ -166,9 +172,7 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){ assert( p->magic==VDBE_MAGIC_INIT ); assert( op>0 && op<0xff ); if( p->pParse->nOpAlloc<=i ){ - if( growOpArray(p, 1) ){ - return 1; - } + return growOp3(p, op, p1, p2, p3); } p->nOp++; pOp = &p->aOp[i]; diff --git a/test/fuzzcheck.c b/test/fuzzcheck.c index 19995684e4..32690dc466 100644 --- a/test/fuzzcheck.c +++ b/test/fuzzcheck.c @@ -838,6 +838,7 @@ int main(int argc, char **argv){ int nMem = 0; /* Memory limit */ char *zExpDb = 0; /* Write Databases to files in this directory */ char *zExpSql = 0; /* Write SQL to files in this directory */ + void *pHeap = 0; /* Heap for use by SQLite */ iBegin = timeOfDay(); #ifdef __unix__ @@ -1085,7 +1086,6 @@ int main(int argc, char **argv){ /* Limit available memory, if requested */ if( nMem>0 ){ - void *pHeap; sqlite3_shutdown(); pHeap = malloc(nMem); if( pHeap==0 ){ @@ -1184,5 +1184,6 @@ int main(int argc, char **argv){ sqlite3_libversion(), sqlite3_sourceid()); } free(azSrcDb); + free(pHeap); return 0; } diff --git a/test/hidden.test b/test/hidden.test new file mode 100644 index 0000000000..1db2cad12e --- /dev/null +++ b/test/hidden.test @@ -0,0 +1,153 @@ +# 2015 November 18 +# +# 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. +# +#*********************************************************************** +# +# Test the __hidden__ hack. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix hidden + +ifcapable !hiddencolumns { + finish_test + return +} + +do_execsql_test 1.1 { + CREATE TABLE t1(__hidden__a, b); + INSERT INTO t1 VALUES('1'); + INSERT INTO t1(__hidden__a, b) VALUES('x', 'y'); +} {} + +do_execsql_test 1.2 { + SELECT * FROM t1; +} {1 y} + +do_execsql_test 1.3 { + SELECT __hidden__a, * FROM t1; +} {{} 1 x y} + +foreach {tn view} { + 1 { CREATE VIEW v1(a, b, __hidden__c) AS SELECT a, b, c FROM x1 } + 2 { CREATE VIEW v1 AS SELECT a, b, c AS __hidden__c FROM x1 } +} { + do_execsql_test 2.$tn.1 { + DROP TABLE IF EXISTS x1; + CREATE TABLE x1(a, b, c); + INSERT INTO x1 VALUES(1, 2, 3); + } + + catchsql { DROP VIEW v1 } + execsql $view + + do_execsql_test 2.$tn.2 { + SELECT a, b, __hidden__c FROM v1; + } {1 2 3} + + do_execsql_test 2.$tn.3 { + SELECT * FROM v1; + } {1 2} + + do_execsql_test 2.$tn.4 { + CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN + INSERT INTO x1 VALUES(new.a, new.b, new.__hidden__c); + END; + + INSERT INTO v1 VALUES(4, 5); + SELECT * FROM x1; + } {1 2 3 4 5 {}} + + do_execsql_test 2.$tn.5 { + INSERT INTO v1(a, b, __hidden__c) VALUES(7, 8, 9); + SELECT * FROM x1; + } {1 2 3 4 5 {} 7 8 9} +} + +#------------------------------------------------------------------------- +# Test INSERT INTO ... SELECT ... statements that write to tables with +# hidden columns. +# +do_execsql_test 3.1 { + CREATE TABLE t4(a, __hidden__b, c); + INSERT INTO t4 SELECT 1, 2; + SELECT a, __hidden__b, c FROM t4; +} {1 {} 2} + +do_execsql_test 3.2.1 { + CREATE TABLE t5(__hidden__a, b, c); + CREATE TABLE t6(__hidden__a, b, c); + INSERT INTO t6(__hidden__a, b, c) VALUES(1, 2, 3); + INSERT INTO t6(__hidden__a, b, c) VALUES(4, 5, 6); + INSERT INTO t6(__hidden__a, b, c) VALUES(7, 8, 9); +} + +do_execsql_test 3.2.2 { + INSERT INTO t5 SELECT * FROM t6; + SELECT * FROM t5; +} {2 3 5 6 8 9} + +do_execsql_test 3.2.3 { + SELECT __hidden__a FROM t5; +} {{} {} {}} + + +do_execsql_test 3.3.1 { + CREATE TABLE t5a(a, b, __hidden__c); + CREATE TABLE t6a(a, b, __hidden__c); + INSERT INTO t6a(a, b, __hidden__c) VALUES(1, 2, 3); + INSERT INTO t6a(a, b, __hidden__c) VALUES(4, 5, 6); + INSERT INTO t6a(a, b, __hidden__c) VALUES(7, 8, 9); +} + +do_execsql_test 3.3.2 { + INSERT INTO t5a SELECT * FROM t6a; + SELECT * FROM t5a; +} {1 2 4 5 7 8} + +do_execsql_test 3.3.3 { + SELECT __hidden__c FROM t5a; +} {{} {} {}} + +do_execsql_test 3.4.1 { + CREATE TABLE t5b(a, __hidden__b, c); + CREATE TABLE t6b(a, b, __hidden__c); + INSERT INTO t6b(a, b, __hidden__c) VALUES(1, 2, 3); + INSERT INTO t6b(a, b, __hidden__c) VALUES(4, 5, 6); + INSERT INTO t6b(a, b, __hidden__c) VALUES(7, 8, 9); +} + +do_execsql_test 3.4.2 { + INSERT INTO t5b SELECT * FROM t6b; + SELECT * FROM t5b; +} {1 2 4 5 7 8} + +do_execsql_test 3.4.3 { + SELECT __hidden__b FROM t5b; +} {{} {} {}} + +#------------------------------------------------------------------------- +# Test VACUUM +# +reset_db +do_execsql_test 4.1 { + CREATE TABLE t1(a, __hidden__b, c UNIQUE); + INSERT INTO t1(a, __hidden__b, c) VALUES(1, 2, 3); + INSERT INTO t1(a, __hidden__b, c) VALUES(4, 5, 6); + INSERT INTO t1(a, __hidden__b, c) VALUES(7, 8, 9); + DELETE FROM t1 WHERE __hidden__b = 5; + SELECT rowid, a, __hidden__b, c FROM t1; +} {1 1 2 3 3 7 8 9} +do_execsql_test 4.2 { + VACUUM; + SELECT rowid, a, __hidden__b, c FROM t1; +} {1 1 2 3 3 7 8 9} + +finish_test diff --git a/test/misc1.test b/test/misc1.test index 25e9bd813e..6e0abcd108 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -701,4 +701,13 @@ do_test misc1-24.0 { list [catch { sqlite3_prepare_v2 db ! -1 dummy } msg] $msg } {1 {(1) unrecognized token: "!}} +# The following query (provided by Kostya Serebryany) used to take 25 +# minutes to prepare. This has been speeded up to about 250 milliseconds. +# +do_catchsql_test misc1-25.0 { +SELECT-1 UNION SELECT 5 UNION SELECT 0 UNION SElECT*from(SELECT-5) UNION SELECT*from(SELECT-0) UNION SELECT:SELECT-0 UNION SELECT-1 UNION SELECT 1 UNION SELECT 1 ORDER BY S in(WITH K AS(WITH K AS(select'CREINDERcharREADEVIRTUL5TABLECONFLICT !1 USIN'' MFtOR(b38q,eWITH K AS(selectCREATe TABLE t0(a,b,c,d,e, PRIMARY KEY(a,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,b,c,d,c,a,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d'CEIl,k'',ab, g, a,b,o11b, i'nEX/charREDE IVT LR!VABLt5SG',N ,N in rement,l_vacuum,M&U,'te3(''5l' a,bB,b,l*e)SELECT:SELECT, *,*,*from(( SELECT +$group,:conc ap0,1)fro,(select"",:PBAG,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d, foreign_keysc,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,a,b,d,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,c,a,b,b,c,d,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,d,c,e,d,d,c,a,b,b,c,c,a,b,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,bb,b,E,d,c,d,c,b,c,d,c,d,c,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,a,b,c,e,d,d,c,a,b,b,c,d,d,c,a,b,c,e,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,c,d,c,a,b,d,d,c,a,a,b,d,d,c,a,b,b,c,d,c,a,b,e,e,d,b,c,d,c,a,b,b,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,c,a,b,c,e,d,d,c,a,b,b,c,d,c,d,c,a,b,c,e,c,d,c,a,b,b,c,d,MAato_aecSELEC,+?b," "O,"i","a",""b ,5 ))KEY)SELECT*FROM((k()reaC,k,K) eA,k '' )t ,K M); +} {1 {too many columns in result set}} + + finish_test diff --git a/test/pragma2.test b/test/pragma2.test index e2c87019eb..64b396bd1f 100644 --- a/test/pragma2.test +++ b/test/pragma2.test @@ -135,10 +135,12 @@ delete_file test.db test.db-journal delete_file test2.db test2.db-journal sqlite3 db test.db do_execsql_test pragma2-4.1 { + PRAGMA main.cache_size=2000; + PRAGMA temp.cache_size=2000; PRAGMA cache_spill; PRAGMA main.cache_spill; PRAGMA temp.cache_spill; -} {1 1 1} +} {2000 2000 2000} do_execsql_test pragma2-4.2 { PRAGMA cache_spill=OFF; PRAGMA cache_spill; @@ -178,21 +180,56 @@ do_test pragma2-4.4 { PRAGMA lock_status; } } {main exclusive temp unknown} ;# EXCLUSIVE lock due to cache spill -do_test pragma2-4.5 { +do_test pragma2-4.5.1 { db eval { - COMMIT; + ROLLBACK; PRAGMA cache_spill=OFF; + PRAGMA Cache_Spill; BEGIN; - UPDATE t1 SET c=c-1; + UPDATE t1 SET c=c+1; PRAGMA lock_status; } -} {main reserved temp unknown} ;# No cache spill, so no exclusive lock +} {0 main reserved temp unknown} ;# No cache spill, so no exclusive lock +do_test pragma2-4.5.2 { + db eval { + ROLLBACK; + PRAGMA cache_spill=100000; + PRAGMA cache_spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } +} {100000 main reserved temp unknown} ;# Big spill threshold -> no excl lock +ifcapable !memorymanage { + do_test pragma2-4.5.3 { + db eval { + ROLLBACK; + PRAGMA cache_spill=25; + PRAGMA main.cache_spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } + } {50 main exclusive temp unknown} ;# Small cache spill -> exclusive lock + do_test pragma2-4.5.4 { + db eval { + ROLLBACK; + PRAGMA cache_spill(-25); + PRAGMA main.cache_spill; + BEGIN; + UPDATE t1 SET c=c+1; + PRAGMA lock_status; + } + } {50 main exclusive temp unknown} ;# Small cache spill -> exclusive lock +} + # Verify that newly attached databases inherit the cache_spill=OFF # setting. # do_execsql_test pragma2-4.6 { - COMMIT; + ROLLBACK; + PRAGMA cache_spill=OFF; ATTACH 'test2.db' AS aux1; PRAGMA aux1.cache_size=50; BEGIN; @@ -209,6 +246,26 @@ do_execsql_test pragma2-4.8 { UPDATE t2 SET c=c-1; PRAGMA lock_status; } {main unlocked temp unknown aux1 exclusive} +db close +forcedelete test.db +sqlite3 db test.db + +breakpoint +do_execsql_test pragma2-5.1 { + PRAGMA page_size=16384; + CREATE TABLE t1(x); + PRAGMA cache_size=2; + PRAGMA cache_spill=YES; + PRAGMA cache_spill; +} {2} +do_execsql_test pragma2-5.2 { + PRAGMA cache_spill=NO; + PRAGMA cache_spill; +} {0} +do_execsql_test pragma2-5.3 { + PRAGMA cache_spill(-51); + PRAGMA cache_spill; +} {3} test_restore_config_pagecache finish_test diff --git a/test/releasetest.tcl b/test/releasetest.tcl index 2e67aabae2..7f53fd1523 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -119,6 +119,7 @@ array set ::Configs [strip_comments { -DSQLITE_ENABLE_MEMSYS3=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 -DSQLITE_ENABLE_STAT4 + -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_MAX_ATTACHED=125 } "Fast-One" { @@ -145,6 +146,7 @@ array set ::Configs [strip_comments { -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_OMIT_PROGRESS_CALLBACK=1 -DSQLITE_OMIT_VIRTUALTABLE=1 + -DSQLITE_ENABLE_HIDDEN_COLUMNS -DSQLITE_TEMP_STORE=3 --enable-json1 } @@ -213,6 +215,7 @@ array set ::Configs [strip_comments { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE + -DSQLITE_ENABLE_HIDDEN_COLUMNS --enable-json1 } @@ -306,22 +309,39 @@ foreach {key value} [array get ::Platforms] { } } -# Output log +# Output log. Disabled for slave interpreters. # -set LOG [open releasetest-out.txt w] -proc PUTS {args} { - if {[llength $args]==2} { - puts [lindex $args 0] [lindex $args 1] - puts $::LOG [lindex $args 1] - } else { - puts [lindex $args 0] - puts $::LOG [lindex $args 0] +if {[lindex $argv end]!="--slave"} { + set LOG [open releasetest-out.txt w] + proc PUTS {txt} { + puts $txt + puts $::LOG $txt + flush $::LOG + } + proc PUTSNNL {txt} { + puts -nonewline $txt + puts -nonewline $::LOG $txt + flush $::LOG + } + proc PUTSERR {txt} { + puts stderr $txt + puts $::LOG $txt + flush $::LOG + } + puts $LOG "$argv0 $argv" + set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] + puts $LOG "start-time: $tm0 UTC" +} else { + proc PUTS {txt} { + puts $txt + } + proc PUTSNNL {txt} { + puts -nonewline $txt + } + proc PUTSERR {txt} { + puts stderr $txt } - flush $::LOG } -puts $LOG "$argv0 $argv" -set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] -puts $LOG "start-time: $tm0 UTC" # Open the file $logfile and look for a report on the number of errors # and the number of test cases run. Add these values to the global @@ -422,6 +442,7 @@ proc run_slave_test {} { foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} # Create and switch to the test directory. + set ::env(SQLITE_TMPDIR) [file normalize $dir] trace_cmd file mkdir $dir trace_cmd cd $dir catch {file delete core} @@ -809,8 +830,8 @@ proc process_options {argv} { } default { - PUTS stderr "" - PUTS stderr [string trim $::USAGE_MESSAGE] + PUTSERR stderr "" + PUTSERR stderr [string trim $::USAGE_MESSAGE] exit -1 } } @@ -818,7 +839,7 @@ proc process_options {argv} { if {0==[info exists ::Platforms($platform)]} { PUTS "Unknown platform: $platform" - PUTS -nonewline "Set the -platform option to " + PUTSNNL "Set the -platform option to " set print [list] foreach p [array names ::Platforms] { lappend print "\"$p\"" @@ -844,16 +865,16 @@ proc process_options {argv} { } PUTS "Running the following test configurations for $platform:" PUTS " [string trim $::CONFIGLIST]" - PUTS -nonewline "Flags:" - if {$::PROGRESS_MSGS} {PUTS -nonewline " --progress"} - if {$::DRYRUN} {PUTS -nonewline " --dryrun"} - if {$::BUILDONLY} {PUTS -nonewline " --buildonly"} - if {$::MSVC} {PUTS -nonewline " --msvc"} + PUTSNNL "Flags:" + if {$::PROGRESS_MSGS} {PUTSNNL " --progress"} + if {$::DRYRUN} {PUTSNNL " --dryrun"} + if {$::BUILDONLY} {PUTSNNL " --buildonly"} + if {$::MSVC} {PUTSNNL " --msvc"} switch -- $::QUICK { - 1 {PUTS -nonewline " --quick"} - 2 {PUTS -nonewline " --veryquick"} + 1 {PUTSNNL " --quick"} + 2 {PUTSNNL " --veryquick"} } - if {$::JOBS>1} {PUTS -nonewline " --jobs $::JOBS"} + if {$::JOBS>1} {PUTSNNL " --jobs $::JOBS"} PUTS "" } diff --git a/test/sqllog.test b/test/sqllog.test new file mode 100644 index 0000000000..dca5781dbd --- /dev/null +++ b/test/sqllog.test @@ -0,0 +1,116 @@ +# 2015 November 13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the test_sqllog.c module. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix sqllog + +ifcapable !sqllog { + finish_test + return +} + +proc readfile {f} { + set fd [open $f] + set txt [read $fd] + close $fd + set txt +} + +proc delete_all_sqllog_files {} { + forcedelete {*}[glob -nocomplain sqllog_*.sql] + forcedelete {*}[glob -nocomplain sqllog_*.db] + forcedelete {*}[glob -nocomplain sqllog_*.idx] +} + +proc touch {f} { + set fd [open $f w+] + close $fd +} + +db close +sqlite3_shutdown +set ::env(SQLITE_SQLLOG_DIR) [pwd] + +delete_all_sqllog_files + +sqlite3 db test.db +set a a +set b b +do_execsql_test 1.0 { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t1 VALUES($a, $b); + SELECT * FROM t1; +} {1 2 a b} +db close + +do_test 1.1 { + readfile [lindex [glob sqllog_*.sql] 0] +} [string trimleft { +/-- Main database is '.*/sqllog_.*_0.db' +CREATE TABLE t1\(x, y\);; -- clock=0 +INSERT INTO t1 VALUES\(1, 2\);; -- clock=1 +INSERT INTO t1 VALUES\('a', 'b'\);; -- clock=2 +SELECT . FROM t1;; -- clock=3 +/}] + +do_test 1.2 { + file size [lindex [glob sqllog_*_0.db] 0] +} 1024 + +#------------------------------------------------------------------------- +catch { db close } +sqlite3_shutdown +delete_all_sqllog_files +forcedelete test.db-sqllog + +set ::env(SQLITE_SQLLOG_CONDITIONAL) 1 +sqlite3 db test.db +do_execsql_test 2.1 { + INSERT INTO t1 VALUES(4, 5); + SELECT * FROM t1; +} {1 2 a b 4 5} + +do_test 2.2 { + glob -nocomplain sqllog_* +} {} + +db close +touch test.db-sqllog +sqlite3 db test.db +do_execsql_test 2.3 { + INSERT INTO t1 VALUES(6, 7); + SELECT * FROM t1; +} {1 2 a b 4 5 6 7} +db close + +do_test 2.4 { + readfile [lindex [glob sqllog_*.sql] 0] +} [string trimleft { +/-- Main database is '.*/sqllog_.*_0.db' +INSERT INTO t1 VALUES\(6, 7\);; -- clock=0 +SELECT . FROM t1;; -- clock=1 +/}] + +catch { db close } +sqlite3_shutdown +unset ::env(SQLITE_SQLLOG_DIR) +unset ::env(SQLITE_SQLLOG_CONDITIONAL) +sqlite3_config_sqllog +sqlite3_initialize +breakpoint +finish_test + + diff --git a/test/tester.tcl b/test/tester.tcl index 4f6c1d9b73..4cb4a3dd16 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -746,8 +746,8 @@ proc do_test {name cmd expected} { # if {![info exists ::testprefix] || $::testprefix eq ""} { # error "no test prefix" # } - output2_if_no_verbose -nonewline $name... - output2 "\nExpected: \[$expected\]\n Got: \[$result\]" + output1 "" + output2 "! $name expected: \[$expected\]\n! $name got: \[$result\]" fail_test $name } else { output1 " Ok" @@ -1037,7 +1037,7 @@ proc finalize_testing {} { output2 "$nErr errors out of $nTest tests" } if {$nErr>$nKnown} { - output2 -nonewline "Failures on these tests:" + output2 -nonewline "!Failures on these tests:" foreach x [set_test_counter fail_list] { if {![info exists known_error($x)]} {output2 -nonewline " $x"} } @@ -1053,7 +1053,7 @@ proc finalize_testing {} { foreach {rec} [lsort $omitList] { if {$rec==$prec} continue set prec $rec - output2 [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]] + output2 [format {. %-12s %s} [lindex $rec 0] [lindex $rec 1]] } } if {$nErr>0 && ![working_64bit_int]} { diff --git a/test/trigger7.test b/test/trigger7.test index 221962406b..847d78cd7a 100644 --- a/test/trigger7.test +++ b/test/trigger7.test @@ -21,7 +21,6 @@ ifcapable {!trigger} { return } - # Error messages resulting from qualified trigger names. # do_test trigger7-1.1 { diff --git a/test/wal3.test b/test/wal3.test index bd312b349c..9ee8a99458 100644 --- a/test/wal3.test +++ b/test/wal3.test @@ -275,9 +275,9 @@ proc lock_callback {method filename handle lock} { if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK } -puts " Warning: This next test case causes SQLite to call xSleep(1) 100 times." -puts " Normally this equates to a 100ms delay, but if SQLite is built on unix" -puts " without HAVE_USLEEP defined, it may be 100 seconds." +puts "# Warning: This next test case causes SQLite to call xSleep(1) 100 times." +puts "# Normally this equates to a 100ms delay, but if SQLite is built on unix" +puts "# without HAVE_USLEEP defined, it may be 100 seconds." do_test wal3-4.3 { db close set ::locks [list] @@ -285,7 +285,7 @@ do_test wal3-4.3 { catchsql { SELECT * FROM x } } {1 {locking protocol}} -puts " Warning: Same again!" +puts "# Warning: Same again!" proc lock_callback {method filename handle lock} { if {$lock == "0 1 lock exclusive"} { return SQLITE_BUSY } return SQLITE_OK diff --git a/test/with1.test b/test/with1.test index 71eec61e7d..d98f33dfb0 100644 --- a/test/with1.test +++ b/test/with1.test @@ -865,4 +865,114 @@ do_catchsql_test 16.1 { SELECT * FROM i; } {1 {recursive aggregate queries not supported}} +#------------------------------------------------------------------------- +do_execsql_test 17.1 { + WITH x(a) AS ( + WITH y(b) AS (SELECT 10) + SELECT 9 UNION ALL SELECT * FROM y + ) + SELECT * FROM x +} {9 10} + +do_execsql_test 17.2 { + WITH x AS ( + WITH y(b) AS (SELECT 10) + SELECT * FROM y UNION ALL SELECT * FROM y + ) + SELECT * FROM x +} {10 10} + +do_test 17.2 { + db eval { + WITH x AS ( + WITH y(b) AS (SELECT 10) + SELECT * FROM y UNION ALL SELECT * FROM y + ) + SELECT * FROM x + } A { + # no op + } + set A(*) +} {b} + +do_catchsql_test 17.3 { + WITH i AS ( + WITH j AS (SELECT 5) + SELECT 5 FROM i UNION SELECT 8 FROM i + ) + SELECT * FROM i; +} {1 {circular reference: i}} + +do_catchsql_test 17.4 { + WITH i AS ( + WITH j AS (SELECT 5) + SELECT 5 FROM t1 UNION SELECT 8 FROM t11 + ) + SELECT * FROM i; +} {1 {no such table: t11}} + +do_execsql_test 17.5 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT * FROM x1), + x3 AS ( + WITH x1 AS (SELECT 11) + SELECT * FROM x2 UNION ALL SELECT * FROM x2 + ) + SELECT * FROM x3; +} {10 10} + +do_execsql_test 17.6 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT * FROM x1), + x3 AS ( + WITH x1 AS (SELECT 11) + SELECT * FROM x2 UNION ALL SELECT * FROM x1 + ) + SELECT * FROM x3; +} {10 11} + +do_execsql_test 17.7 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT * FROM x1), + x3 AS ( + WITH + x1 AS ( SELECT 11 ), + x4 AS ( SELECT * FROM x2 ) + SELECT * FROM x4 UNION ALL SELECT * FROM x1 + ) + SELECT * FROM x3; +} {10 11} + +do_execsql_test 17.8 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT * FROM x1), + x3 AS ( + WITH + x1 AS ( SELECT 11 ), + x4 AS ( SELECT * FROM x2 ) + SELECT * FROM x4 UNION ALL SELECT * FROM x1 + ) + SELECT * FROM x3; +} {10 11} + +do_execsql_test 17.9 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT 11), + x3 AS ( + SELECT * FROM x1 UNION ALL SELECT * FROM x2 + ), + x4 AS ( + WITH + x1 AS (SELECT 12), + x2 AS (SELECT 13) + SELECT * FROM x3 + ) + SELECT * FROM x4; +} {10 11} + finish_test diff --git a/test/with3.test b/test/with3.test new file mode 100644 index 0000000000..62e88441ab --- /dev/null +++ b/test/with3.test @@ -0,0 +1,64 @@ +# 2015-11-07 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the WITH clause. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix with3 + +ifcapable {!cte} { + finish_test + return +} + +# Test problems found by Kostya Serebryany using +# LibFuzzer. (http://llvm.org/docs/LibFuzzer.html) +# +do_catchsql_test 1.0 { + WITH i(x) AS ( + WITH j AS (SELECT 10) + SELECT 5 FROM t0 UNION SELECT 8 FROM m + ) + SELECT * FROM i; +} {1 {no such table: m}} + +# Additional test cases that came out of the work to +# fix for Kostya's problem. +# +do_execsql_test 2.0 { + WITH + x1 AS (SELECT 10), + x2 AS (SELECT 11), + x3 AS ( + SELECT * FROM x1 UNION ALL SELECT * FROM x2 + ), + x4 AS ( + WITH + x1 AS (SELECT 12), + x2 AS (SELECT 13) + SELECT * FROM x3 + ) + SELECT * FROM x4; + +} {10 11} + +do_execsql_test 2.1 { + CREATE TABLE t1(x); + WITH + x1(a) AS (values(100)) + INSERT INTO t1(x) + SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2); + SELECT * FROM t1; +} {200} + +finish_test diff --git a/tool/addopcodes.tcl b/tool/addopcodes.tcl index c5c3525ad4..84e3994ce8 100644 --- a/tool/addopcodes.tcl +++ b/tool/addopcodes.tcl @@ -18,7 +18,8 @@ while {![eof $in]} { } close $in -# The following are the extra token codes to be added +# The following are the extra token codes to be added. SPACE and +# ILLEGAL *must* be the last two token codes and they must be in that order. # set extras { TO_TEXT @@ -28,8 +29,6 @@ set extras { TO_REAL ISNOT END_OF_FILE - ILLEGAL - SPACE UNCLOSED_STRING FUNCTION COLUMN @@ -38,6 +37,13 @@ set extras { UMINUS UPLUS REGISTER + ASTERISK + SPACE + ILLEGAL +} +if {[lrange $extras end-1 end]!="SPACE ILLEGAL"} { + error "SPACE and ILLEGAL must be the last two token codes and they\ + must be in that order" } foreach x $extras { incr max diff --git a/tool/cg_anno.tcl b/tool/cg_anno.tcl new file mode 100755 index 0000000000..f806c5a5af --- /dev/null +++ b/tool/cg_anno.tcl @@ -0,0 +1,24 @@ +#!/usr/bin/tclsh +# +# A wrapper around cg_annotate that sets appropriate command-line options +# and rearranges the output so that annotated files occur in a consistent +# sorted order. Used by the run-speed-test.tcl script. +# + +set in [open "|cg_annotate --show=Ir --auto=yes --context=40 $argv" r] +set dest ! +set out(!) {} +while {![eof $in]} { + set line [string map {\t { }} [gets $in]] + if {[regexp {^-- Auto-annotated source: (.*)} $line all name]} { + set dest $name + } elseif {[regexp {^-- line \d+ ------} $line]} { + set line [lreplace $line 2 2 {#}] + } elseif {[regexp {^The following files chosen for } $line]} { + set dest ! + } + append out($dest) $line\n +} +foreach x [lsort [array names out]] { + puts $out($x) +} diff --git a/tool/lempar.c b/tool/lempar.c index cdf4ca5a1a..312507e5f1 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -1,49 +1,67 @@ -/* Driver template for the LEMON parser generator. -** The author disclaims copyright to this source code. -*/ -/* First off, code is included that follows the "include" declaration -** in the input grammar file. */ -#include -%% -/* Next is all token values, in a form suitable for use by makeheaders. -** This section will be null unless lemon is run with the -m switch. -*/ -/* -** These constants (all generated automatically by the parser generator) -** specify the various kinds of tokens (terminals) that the parser -** understands. +/* +** 2000-05-29 ** -** Each symbol here is a terminal symbol in the grammar. +** 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. +** +************************************************************************* +** Driver template for the LEMON parser generator. +** +** The "lemon" program processes an LALR(1) input grammar file, then uses +** this template to construct a parser. The "lemon" program inserts text +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** interstitial "-" characters) contained in this template is changed into +** the value of the %name directive from the grammar. Otherwise, the content +** of this template is copied straight through into the generate parser +** source file. +** +** The following is the concatenation of all %include directives from the +** input grammar file: */ +#include +/************ Begin %include sections from the grammar ************************/ %% -/* Make sure the INTERFACE macro is defined. -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/* The next thing included is series of defines which control +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols +** in a format understandable to "makeheaders". This section is blank unless +** "lemon" is run with the "-m" command-line option. +***************** Begin makeheaders token definitions *************************/ +%% +/**************** End makeheaders token definitions ***************************/ + +/* The next sections is a series of control #defines. ** various aspects of the generated parser. -** YYCODETYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 terminals -** and nonterminals. "int" is used otherwise. -** YYNOCODE is a number of type YYCODETYPE which corresponds -** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash -** table. +** YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** YYNOCODE is a number of type YYCODETYPE that is not used for +** any terminal or nonterminal symbol. ** YYFALLBACK If defined, this indicates that one or more tokens -** have fall-back values which should be used if the -** original value of the token will not parse. -** YYACTIONTYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 rules and -** states combined. "int" is used otherwise. -** ParseTOKENTYPE is the data type used for minor tokens given -** directly to the parser from the tokenizer. -** YYMINORTYPE is the data type used for all minor tokens. +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** ParseTOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** YYMINORTYPE is the data type used for all minor types. ** This is typically a union of many types, one of ** which is ParseTOKENTYPE. The entry in the union -** for base tokens is called "yy0". +** for terminal symbols is called "yy0". ** YYSTACKDEPTH is the maximum depth of the parser's stack. If ** zero the stack is dynamically sized using realloc() ** ParseARG_SDECL A static variable declaration for the %extra_argument @@ -62,7 +80,12 @@ ** YY_ACCEPT_ACTION The yy_action[] code for accept ** YY_NO_ACTION The yy_action[] code for no-op */ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ %% +/************* End control #defines *******************************************/ /* The yyzerominor constant is used to initialize instances of ** YYMINORTYPE objects to zero. */ @@ -131,11 +154,13 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. -*/ +** +*********** Begin parsing tables **********************************************/ %% +/********** End of lemon-generated parsing tables *****************************/ -/* The next table maps tokens into fallback tokens. If a construct -** like the following: +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: ** ** %fallback ID X Y Z. ** @@ -143,6 +168,10 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. +** +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { @@ -265,6 +294,15 @@ static void yyGrowStack(yyParser *p){ } #endif +/* Datatype of the argument to the memory allocated passed as the +** second argument to ParseAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. +*/ +#ifndef YYMALLOCARGTYPE +# define YYMALLOCARGTYPE size_t +#endif + /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like @@ -277,9 +315,9 @@ static void yyGrowStack(yyParser *p){ ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ -void *ParseAlloc(void *(*mallocProc)(size_t)){ +void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH @@ -294,10 +332,12 @@ void *ParseAlloc(void *(*mallocProc)(size_t)){ return pParser; } -/* The following function deletes the value associated with a -** symbol. The symbol can be either a terminal or nonterminal. -** "yymajor" is the symbol code, and "yypminor" is a pointer to -** the value. +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. */ static void yy_destructor( yyParser *yypParser, /* The parser */ @@ -313,10 +353,12 @@ static void yy_destructor( ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those - ** which appear on the RHS of the rule, but which are not used + ** which appear on the RHS of the rule, but which are *not* used ** inside the C code. */ +/********* Begin destructor definitions ***************************************/ %% +/********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } } @@ -326,45 +368,37 @@ static void yy_destructor( ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. -** -** Return the major token number for the symbol popped. */ -static int yy_pop_parser_stack(yyParser *pParser){ - YYCODETYPE yymajor; - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; - - if( pParser->yyidx<0 ) return 0; +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yyidx>=0 ); + yytos = &pParser->yystack[pParser->yyidx--]; #ifndef NDEBUG - if( yyTraceFILE && pParser->yyidx>=0 ){ + if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif - yymajor = yytos->major; - yy_destructor(pParser, yymajor, &yytos->minor); - pParser->yyidx--; - return yymajor; + yy_destructor(pParser, yytos->major, &yytos->minor); } /* -** Deallocate and destroy a parser. Destructors are all called for +** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. ** -** Inputs: -**
    -**
  • A pointer to the parser. This should be a pointer -** obtained from ParseAlloc. -**
  • A pointer to a function used to reclaim memory obtained -** from malloc. -**
+** If the YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. */ void ParseFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; +#ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; +#endif while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 free(pParser->yystack); @@ -385,10 +419,6 @@ int ParseStackPeak(void *p){ /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. */ static int yy_find_shift_action( yyParser *pParser, /* The parser */ @@ -396,64 +426,65 @@ static int yy_find_shift_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - - if( stateno>=YY_MIN_REDUCE ) return stateno; + + if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); - i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ + do{ + i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - return yy_find_shift_action(pParser, iFallback); - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( -#if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && -#endif -#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; } -#endif /* NDEBUG */ - return yy_action[j]; } - } #endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; } - return yy_default[stateno]; - }else{ - return yy_action[i]; - } + }while(1); } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. */ static int yy_find_reduce_action( int stateno, /* Current state number */ @@ -496,7 +527,9 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ %% +/******** End %stack_overflow code ********************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } @@ -506,15 +539,13 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ #ifndef NDEBUG static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ - int i; if( yyNewStateyyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); + fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n", + yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major], + yyNewState); }else{ - fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); + fprintf(yyTraceFILE,"%sShift '%s'\n", + yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]); } } } @@ -523,7 +554,7 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState){ #endif /* -** Perform a shift action. Return the number of errors. +** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ @@ -590,29 +621,12 @@ static void yy_reduce( if( yyTraceFILE && yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; - fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt, + fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ - - /* Silence complaints from purify about yygotominor being uninitialized - ** in some cases when it is copied into the stack after the following - ** switch. yygotominor is uninitialized when a rule reduces that does - ** not set the value of its left-hand side nonterminal. Leaving the - ** value of the nonterminal uninitialized is utterly harmless as long - ** as the value is never used. So really the only thing this code - ** accomplishes is to quieten purify. - ** - ** 2007-01-16: The wireshark project (www.wireshark.org) reports that - ** without this code, their parser segfaults. I'm not sure what there - ** parser is doing to make this happen. This is the second bug report - ** from wireshark this week. Clearly they are stressing Lemon in ways - ** that it has not been previously stressed... (SQLite ticket #2172) - */ - /*memset(&yygotominor, 0, sizeof(yygotominor));*/ yygotominor = yyzerominor; - switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: @@ -622,8 +636,11 @@ static void yy_reduce( ** #line ** break; */ +/********** Begin reduce actions **********************************************/ %% +/********** End reduce actions ************************************************/ }; + assert( yyruleno>=0 && yyrulenoyyidx -= yysize; @@ -666,7 +683,9 @@ static void yy_parse_failed( while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ +/************ Begin %parse_failure code ***************************************/ %% +/************ End %parse_failure code *****************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } #endif /* YYNOERRORRECOVERY */ @@ -681,7 +700,9 @@ static void yy_syntax_error( ){ ParseARG_FETCH; #define TOKEN (yyminor.yy0) +/************ Begin %syntax_error code ****************************************/ %% +/************ End %syntax_error code ******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -700,7 +721,9 @@ static void yy_accept( while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ %% +/*********** End %parse_accept code *******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -731,7 +754,9 @@ void Parse( ){ YYMINORTYPE yyminorunion; int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ +#endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif @@ -752,14 +777,22 @@ void Parse( yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n", + yyTracePrompt); + } +#endif } yyminorunion.yy0 = yyminor; +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); +#endif ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); } #endif @@ -873,7 +906,12 @@ void Parse( }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); + int i; + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', + yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"]\n"); } #endif return; diff --git a/tool/mkkeywordhash.c b/tool/mkkeywordhash.c index 721611f5a3..003ed7d66e 100644 --- a/tool/mkkeywordhash.c +++ b/tool/mkkeywordhash.c @@ -277,27 +277,8 @@ static Keyword aKeywordTable[] = { /* Number of keywords */ static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0])); -/* An array to map all upper-case characters into their corresponding -** lower-case character. -*/ -const unsigned char sqlite3UpperToLower[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, - 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107, - 108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, - 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, - 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, - 180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, - 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, - 216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233, - 234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251, - 252,253,254,255 -}; -#define UpperToLower sqlite3UpperToLower +/* Map all alphabetic characters into the same case */ +#define charMap(X) (0x20|(X)) /* ** Comparision function for two Keyword records @@ -372,8 +353,8 @@ int main(int argc, char **argv){ assert( p->lenzOrigName) ); memcpy(p->zOrigName, p->zName, p->len+1); totalLen += p->len; - p->hash = (UpperToLower[(int)p->zName[0]]*4) ^ - (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len; + p->hash = (charMap(p->zName[0])*4) ^ + (charMap(p->zName[p->len-1])*3) ^ (p->len*1); p->id = i+1; } @@ -481,7 +462,7 @@ int main(int argc, char **argv){ /* Begin generating code */ printf("%s", zHdr); printf("/* Hash score: %d */\n", bestCount); - printf("static int keywordCode(const char *z, int n){\n"); + printf("static int keywordCode(const char *z, int n, int *pType){\n"); printf(" /* zText[] encodes %d bytes of keywords in %d bytes */\n", totalLen + nKeyword, nChar+1 ); for(i=j=k=0; i=0; i=((int)aNext[i])-1){\n"); - printf(" if( aLen[i]==n &&" - " sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){\n"); + printf(" if( n>=2 ){\n"); + printf(" h = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n", + bestSize); + printf(" for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n"); + printf(" if( aLen[i]==n &&" + " sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){\n"); for(i=0; i&1 | tee -a summary-$NAME.txt +size sqlite3.o | tee -a summary-$NAME.txt +wc sqlite3.c +cg_anno.tcl cachegrind.out.* >cout-$NAME.txt +./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt diff --git a/tool/sqldiff.c b/tool/sqldiff.c index 9f0b705c40..0f406d8a03 100644 --- a/tool/sqldiff.c +++ b/tool/sqldiff.c @@ -558,7 +558,7 @@ static void diff_one_table(const char *zTab, FILE *out){ az = columnNames("main", zTab, &nPk, 0); az2 = columnNames("aux", zTab, &nPk2, 0); if( az && az2 ){ - for(n=0; az[n]; n++){ + for(n=0; az[n] && az2[n]; n++){ if( sqlite3_stricmp(az[n],az2[n])!=0 ) break; } } @@ -568,13 +568,15 @@ static void diff_one_table(const char *zTab, FILE *out){ || az[n] ){ /* Schema mismatch */ - fprintf(out, "DROP TABLE %s;\n", zId); + fprintf(out, "DROP TABLE %s; -- due to schema mismatch\n", zId); dump_table(zTab, out); goto end_diff_one_table; } /* Build the comparison query */ - for(n2=n; az[n2]; n2++){} + for(n2=n; az2[n2]; n2++){ + fprintf(out, "ALTER TABLE %s ADD COLUMN %s;\n", zId, safeId(az2[n2])); + } nQ = nPk2+1+2*(n2-nPk2); if( n2>nPk2 ){ zSep = "SELECT "; @@ -585,7 +587,12 @@ static void diff_one_table(const char *zTab, FILE *out){ strPrintf(&sql, ", 1%s -- changed row\n", nPk==n ? "" : ","); while( az[i] ){ strPrintf(&sql, " A.%s IS NOT B.%s, B.%s%s\n", - az[i], az[i], az[i], i==n2-1 ? "" : ","); + az[i], az2[i], az2[i], az2[i+1]==0 ? "" : ","); + i++; + } + while( az2[i] ){ + strPrintf(&sql, " B.%s IS NOT NULL, B.%s%s\n", + az2[i], az2[i], az2[i+1]==0 ? "" : ","); i++; } strPrintf(&sql, " FROM main.%s A, aux.%s B\n", zId, zId); @@ -597,7 +604,13 @@ static void diff_one_table(const char *zTab, FILE *out){ zSep = "\n AND ("; while( az[i] ){ strPrintf(&sql, "%sA.%s IS NOT B.%s%s\n", - zSep, az[i], az[i], i==n2-1 ? ")" : ""); + zSep, az[i], az2[i], az2[i+1]==0 ? ")" : ""); + zSep = " OR "; + i++; + } + while( az2[i] ){ + strPrintf(&sql, "%sB.%s IS NOT NULL%s\n", + zSep, az2[i], az2[i+1]==0 ? ")" : ""); zSep = " OR "; i++; } @@ -609,7 +622,7 @@ static void diff_one_table(const char *zTab, FILE *out){ zSep = ", "; } strPrintf(&sql, ", 2%s -- deleted row\n", nPk==n ? "" : ","); - while( az[i] ){ + while( az2[i] ){ strPrintf(&sql, " NULL, NULL%s\n", i==n2-1 ? "" : ","); i++; } @@ -628,7 +641,7 @@ static void diff_one_table(const char *zTab, FILE *out){ } strPrintf(&sql, ", 3%s -- inserted row\n", nPk==n ? "" : ","); while( az2[i] ){ - strPrintf(&sql, " 1, B.%s%s\n", az[i], i==n2-1 ? "" : ","); + strPrintf(&sql, " 1, B.%s%s\n", az2[i], az2[i+1]==0 ? "" : ","); i++; } strPrintf(&sql, " FROM aux.%s B\n", zId); @@ -689,7 +702,7 @@ static void diff_one_table(const char *zTab, FILE *out){ for(i=0; i