Compare commits
632 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a1bb3f616 | |||
| 480620c713 | |||
| 3b9f154bb7 | |||
| 541ef2c36c | |||
| 45248de39a | |||
| 871f45441c | |||
| 7a43100afb | |||
| 1d9ea27f7e | |||
| 054a081555 | |||
| 7576a68c8c | |||
| c39b121a95 | |||
| f05dd03a6e | |||
| e6a85962e7 | |||
| 43e862723e | |||
| 4b3282d8a0 | |||
| aa0696ee9a | |||
| 2d99f95721 | |||
| b3120fdf5b | |||
| 4047bdfd2c | |||
| d44390c8c5 | |||
| 85f2c76cf9 | |||
| 47f8ef32a0 | |||
| 2e52a9c611 | |||
| c59b4acf5d | |||
| a96a69b7db | |||
| c415d91007 | |||
| 4db7ab53f9 | |||
| fb99e388ec | |||
| 91654b2016 | |||
| 892edb69c4 | |||
| 3e42b99175 | |||
| 218da8c6f1 | |||
| b1243a6d9c | |||
| 97ccc1bd11 | |||
| 95b395901a | |||
| cdbb28154e | |||
| 8e9297fb79 | |||
| 74a07986ce | |||
| f7f6dbf501 | |||
| 7d76fad8eb | |||
| 31f170f396 | |||
| 465c2b8964 | |||
| 2c3629e1c9 | |||
| 62b6e1d042 | |||
| 2aee514b4c | |||
| 00bd55e1ae | |||
| ec8e689a20 | |||
| 589c787620 | |||
| f0a2172d1d | |||
| 91a23dc299 | |||
| 553948e514 | |||
| 14c98a4f40 | |||
| ba25c7e29f | |||
| 576d0a9fd9 | |||
| 2267a7fa87 | |||
| 9b258c54e4 | |||
| 38dfbdae8a | |||
| 8d5cea6b61 | |||
| e7375bfa72 | |||
| 5cf1b611a2 | |||
| 24e399038b | |||
| 0c76e892d9 | |||
| 088489e8d9 | |||
| afa1ecac9b | |||
| ccb3781673 | |||
| 45dc9ca46b | |||
| ed5e66881e | |||
| db9cb17dc7 | |||
| 0ea2d42ac3 | |||
| 42a630b1da | |||
| 4cf2121e1c | |||
| f5cfe6f2c4 | |||
| d346fe0ab5 | |||
| b3f0d92b91 | |||
| 39b3bcf8ef | |||
| a2ec2e4843 | |||
| 7f05d52c4c | |||
| 0a21ea997d | |||
| 4a3a3eb3d7 | |||
| 2826918d10 | |||
| 9e5ecdc172 | |||
| be284e4ece | |||
| 67e2bb92df | |||
| 47a60d4518 | |||
| df97d43930 | |||
| a8781d9d93 | |||
| f575c1cf06 | |||
| f06cdde2cf | |||
| 35d3cb80c4 | |||
| 2ed1b0e753 | |||
| 0990c415f6 | |||
| cea1951e80 | |||
| 5c19346451 | |||
| 89efac94fd | |||
| e8c4f03266 | |||
| 8a64d62d31 | |||
| 5f69512404 | |||
| 1cfee74a28 | |||
| 4b9e736898 | |||
| 4defdddc31 | |||
| 0184a256e3 | |||
| 78d1d225d8 | |||
| bf48ce49f7 | |||
| ac9e184e1f | |||
| fdfd45aef3 | |||
| ab7fdca2ee | |||
| 0ba3621592 | |||
| 77c9b3ccb3 | |||
| efdba1a8b3 | |||
| 41aa442cf4 | |||
| df9b5cab93 | |||
| b6664744c0 | |||
| dc4f6fc099 | |||
| b48c0d59fa | |||
| c84ad31851 | |||
| 0de19cac43 | |||
| c879c4eac0 | |||
| 5bdad79f01 | |||
| fcbc673752 | |||
| 2a74006087 | |||
| 3cdc820544 | |||
| 92a27f7bf2 | |||
| 40d1db8d20 | |||
| 51f37b2bb8 | |||
| 081ce2042c | |||
| 9dce0ef4ca | |||
| d7b10d74e1 | |||
| 745befd13f | |||
| 1eac966076 | |||
| 7aedd5d70b | |||
| d03f77ae46 | |||
| 759e9cc064 | |||
| 48118e4060 | |||
| ffd3fd0c30 | |||
| 9ca9a53a42 | |||
| 02a95eb9bb | |||
| 925ab5c17e | |||
| fbfd113365 | |||
| 4b2f45be34 | |||
| b9f2e5f777 | |||
| 562fd18b9d | |||
| f54f105446 | |||
| 532b0d23fd | |||
| 9a3bdeba3e | |||
| 8122c6e9be | |||
| 78b5220328 | |||
| 1a3220ace6 | |||
| d0add948ea | |||
| 8c812f98a3 | |||
| 7d2a1be84b | |||
| 70a32703ac | |||
| 39ef8b31fb | |||
| 988af251d8 | |||
| cbf1c8c25b | |||
| be03cc9fcf | |||
| 4b86e20485 | |||
| 38e14fbd5f | |||
| 76a1fce53b | |||
| fe7046044c | |||
| f71eb2091f | |||
| a01fda7113 | |||
| 591711751e | |||
| cea7b5d57e | |||
| 1ee02a1ce5 | |||
| 2d58b7f40f | |||
| 929a940678 | |||
| ef9f719d0b | |||
| 915530dcc8 | |||
| a369d98b9a | |||
| d1eb23cd26 | |||
| be0330e853 | |||
| 1d7d8c8f74 | |||
| 39df24a3f0 | |||
| 7db212a70b | |||
| 7d07a5f4e0 | |||
| b5f0e40578 | |||
| be22a85406 | |||
| 05e8c5407f | |||
| 299b102b93 | |||
| c1f73e29bf | |||
| 76c1206845 | |||
| a14de91367 | |||
| c6b2f9e323 | |||
| 3c867026c0 | |||
| 3b8eb08b17 | |||
| d8df36bd4e | |||
| ca7d3e1d42 | |||
| ffe4d4a2d5 | |||
| cdfadc7948 | |||
| 8080403e44 | |||
| 8875b9e7b5 | |||
| b2fe5a7c35 | |||
| e5f8801044 | |||
| 2e22579dea | |||
| bebce86cde | |||
| 32d184e049 | |||
| 7be5e3dd4c | |||
| fbb6e9ff48 | |||
| b84fda37ef | |||
| 51ebd5fa14 | |||
| 3858be3e59 | |||
| b0c4ef711f | |||
| 32266a1072 | |||
| 05b32ee3c0 | |||
| 014fff20ad | |||
| 2eeca2046e | |||
| 0dfa5255bc | |||
| 15f3eacfc0 | |||
| 6d35956c86 | |||
| b7e519956a | |||
| 19ca76af38 | |||
| 87969b2a11 | |||
| ded33ccea4 | |||
| 4a62581b32 | |||
| f8f76d672b | |||
| c9301e6e7c | |||
| 97bffe674f | |||
| 2b1c2aad9f | |||
| 3f68142b82 | |||
| 406dfcb843 | |||
| b77da374ab | |||
| 46d987405c | |||
| 42925d1f1a | |||
| 262efe4a43 | |||
| cbae3f8c7d | |||
| 1402b8e5b6 | |||
| 5ca06329c9 | |||
| 2e26a602a3 | |||
| 65cdae00ec | |||
| b592d47a81 | |||
| 9e10f9ab05 | |||
| 2928a15b3c | |||
| 628b1a3f9e | |||
| 67c826536f | |||
| 337ca519e1 | |||
| 0ad4f792a9 | |||
| 2e5beddb34 | |||
| 17aceebab7 | |||
| 664d80bbf7 | |||
| 56ea69bf0e | |||
| 64f7ee0219 | |||
| 6f2180d21a | |||
| 74ebaadcdd | |||
| af23236660 | |||
| f6ea97ea3d | |||
| 4549a3b8cb | |||
| b2b61bb61f | |||
| 6fe63b4ee7 | |||
| e5cf3e990a | |||
| 79d5bc80c7 | |||
| 4be621e1ba | |||
| c4ad849921 | |||
| e455e3acf0 | |||
| 3b76c45a7f | |||
| 0d21eae099 | |||
| 9a20ea9b5b | |||
| 9ee00200ef | |||
| 4c983b2f86 | |||
| 607dd6e608 | |||
| 90996885fc | |||
| aa328b6ab1 | |||
| 0cbec59c8b | |||
| e1f49b8850 | |||
| 618ee33614 | |||
| 24d35e409c | |||
| 9fc1b9af36 | |||
| 378ca1eab3 | |||
| 0c4f82051c | |||
| 6b559f3033 | |||
| 1b39aab08d | |||
| 3aef2fb1b4 | |||
| 9f3e6fadde | |||
| 4cbd847a91 | |||
| 22e95fbd74 | |||
| 52f11b885a | |||
| 629b88c683 | |||
| 36e678bc39 | |||
| 2a83c10072 | |||
| fc705da15d | |||
| 4ea562ee70 | |||
| aef8167421 | |||
| 171c50ec38 | |||
| 25c4296bd9 | |||
| 6d67aff0e3 | |||
| 51676fab72 | |||
| b945bcdaf1 | |||
| 64de2a5f7b | |||
| 1e732787da | |||
| cf014f6cbd | |||
| 5f6a2ed7f2 | |||
| 02ff747bc0 | |||
| 70d6b8327a | |||
| 0b973c8bff | |||
| 2b173b93fc | |||
| 8d95ed789e | |||
| 9d41af23a4 | |||
| 2b6e670f73 | |||
| 7b14b65d20 | |||
| be3da24134 | |||
| 997d7434b7 | |||
| 4adb1d0000 | |||
| a4b2df5ce2 | |||
| 51f2b1719c | |||
| f1bb31e219 | |||
| 118efd1626 | |||
| cacdf20771 | |||
| 29368eabc5 | |||
| cfcf4de4a6 | |||
| 6411d656aa | |||
| 7505123fe5 | |||
| 409f3370af | |||
| 43526f4ada | |||
| 5d59102a91 | |||
| 9a1f2e4853 | |||
| b97f3532f5 | |||
| d9670abb58 | |||
| ad5f157791 | |||
| a6c1a71cde | |||
| b4b3630657 | |||
| e3735bf466 | |||
| 6473ba95a0 | |||
| 431704375e | |||
| d8d2fb9222 | |||
| 09bee5743d | |||
| 5e484cb3eb | |||
| fce8165ec6 | |||
| 8d7f44c03a | |||
| fe2a3f1d24 | |||
| d3ee3ad12f | |||
| e752040c09 | |||
| fa53284777 | |||
| 0bb7af44a3 | |||
| 96e8eebf96 | |||
| 0b12613a00 | |||
| aaa5ba0609 | |||
| e86f3402ac | |||
| a9ebfe2030 | |||
| b44fec68a5 | |||
| c7a5ff45b9 | |||
| 4fcce747e2 | |||
| a194d3152c | |||
| 3fee9de239 | |||
| 84d17bdaa7 | |||
| 4eac5f04ab | |||
| c26e78d275 | |||
| 34da2a4806 | |||
| 22c04f8199 | |||
| 1e490c4ca6 | |||
| d8f2d46cbc | |||
| 5f0dfc00de | |||
| 192cf36de6 | |||
| e2478dfa43 | |||
| a2d50283db | |||
| 1d24a53125 | |||
| 2811ea6be7 | |||
| 7edce5ecc0 | |||
| 0af6ddd3ca | |||
| 3d8e7a2f97 | |||
| 13d7950267 | |||
| 4799488e16 | |||
| 5d762b2d1d | |||
| 6e827fa27d | |||
| d262c2db8f | |||
| 6c1c85ca48 | |||
| db1954be0a | |||
| 9524a7ea9f | |||
| 69843342de | |||
| 7a1d7c3968 | |||
| e88af0179e | |||
| f4f31df02d | |||
| b0cbcd0edf | |||
| ed0c34857a | |||
| 67b9ba1732 | |||
| a513e591ae | |||
| 879f1a1ea6 | |||
| 42ae633ab9 | |||
| e99cb2da5f | |||
| 5d73272340 | |||
| 8cc8feae7e | |||
| 8c7715d1cc | |||
| 40e9c8328e | |||
| 394aa710f2 | |||
| b2ab3dcff0 | |||
| 73b21382d4 | |||
| 1548d5276f | |||
| 0e5ce8029d | |||
| 8428b3b437 | |||
| 6ad0e25fa4 | |||
| 8654186b02 | |||
| 34ab941e5b | |||
| 54d501092d | |||
| 59c5679691 | |||
| 3e5f7fef33 | |||
| c29af653e6 | |||
| 396afe6f6a | |||
| 6e1c45ef2e | |||
| a7648f02e0 | |||
| 8c72afaf33 | |||
| 94649b6159 | |||
| 50efa58600 | |||
| 75e95e1fcd | |||
| 646975c521 | |||
| 4dad7ed532 | |||
| d35bdd6c09 | |||
| 95866af326 | |||
| 7e3f135c62 | |||
| 75f1076885 | |||
| 99670abb82 | |||
| aac30f9b50 | |||
| 5be1b20aec | |||
| e3a4f2cf77 | |||
| 0f1fa5de04 | |||
| d335bc40a6 | |||
| e6068027ca | |||
| ee5b6dd393 | |||
| 2e2c8819f1 | |||
| 0d98598507 | |||
| 4ec4dd701f | |||
| 85d9411c09 | |||
| c4938ea2ba | |||
| cbb9da337e | |||
| 1b47c9c98e | |||
| c947d6a4dc | |||
| 41cee66848 | |||
| 0225d819c4 | |||
| 20d6c1fe1b | |||
| 77318a3c3f | |||
| 115d663c05 | |||
| 3ecc05bc3f | |||
| ce678c297b | |||
| d4dae75f79 | |||
| a1ca00edd5 | |||
| 31046a9f1f | |||
| e94006eb42 | |||
| 8e8c88964c | |||
| c075c505f3 | |||
| db5ed35609 | |||
| b5f6243f6d | |||
| 0a8764ad7a | |||
| 2bc5cf9ae9 | |||
| 0824d5b9a5 | |||
| 926f796e8f | |||
| ebd70eedd5 | |||
| 7a9698456d | |||
| 38096961c7 | |||
| c19e22f397 | |||
| bf9d0996b9 | |||
| 29cdbadf8a | |||
| c7a046e282 | |||
| 7fe2fc0dcb | |||
| 5102cf8df5 | |||
| 0a64ddbe76 | |||
| 39593e4f09 | |||
| e5748a5502 | |||
| c6b24ab1b1 | |||
| b6c947251b | |||
| 6c903845cd | |||
| 05fbfd827c | |||
| cb224ab139 | |||
| e6dc1e5b70 | |||
| 348d7f64f2 | |||
| 674a9b3425 | |||
| a634c9e653 | |||
| d63b69b8a2 | |||
| 8f4076223d | |||
| 8aa706e748 | |||
| f68bf5fbe6 | |||
| fcc057db25 | |||
| 0232dade79 | |||
| d79967adbe | |||
| 22e6f67c51 | |||
| ca7a26b5a1 | |||
| 61cb4ed7f1 | |||
| 1417c2f77f | |||
| 2ecf928ea9 | |||
| 2bbcaee833 | |||
| 51690f26bc | |||
| fe03dac236 | |||
| 597f1eb195 | |||
| baa3458920 | |||
| fe293347ac | |||
| a2f142d079 | |||
| 62be2dc753 | |||
| 0f31327eee | |||
| 7e88d6364c | |||
| 5281864f0c | |||
| 22de8357df | |||
| ec123e1301 | |||
| 73bacb7f93 | |||
| e59c562b3f | |||
| c398c65bee | |||
| cd30064bd5 | |||
| 7dc76d8ba0 | |||
| 522ebfa7ce | |||
| 57f7ece784 | |||
| 9c9c70920b | |||
| 6637332988 | |||
| 83420823af | |||
| 70d1a1a3ed | |||
| 594b124f21 | |||
| cde342df70 | |||
| 012b15e2d7 | |||
| ad84bd849e | |||
| 4a4c1bf856 | |||
| 3c161e07af | |||
| dc96192eef | |||
| 3c904885b1 | |||
| 0933aad72c | |||
| 804725a6b9 | |||
| 13a8f203d9 | |||
| 3e72bdb5fe | |||
| 19d4175d65 | |||
| ac801803a5 | |||
| feb5dcf1a6 | |||
| fd6bf04bba | |||
| c72f2fb7fe | |||
| 94febb3a77 | |||
| 3a5f9bc49c | |||
| 527cbd4a10 | |||
| 070ae3beea | |||
| d0c51d1a04 | |||
| 47bcc34271 | |||
| 5710f1ad48 | |||
| 8103a03607 | |||
| 195a843691 | |||
| 31999c5cac | |||
| 803f06bf62 | |||
| 39d1a2a100 | |||
| 01d1801cab | |||
| ba01634cd3 | |||
| b88eaf1619 | |||
| dbf1c4ba8a | |||
| d2c40e9310 | |||
| 746461f1b8 | |||
| 4c8056079f | |||
| a3b75e982a | |||
| 48eb03bd0e | |||
| 9576802dba | |||
| 12bf712707 | |||
| 675f73bcab | |||
| 46a31cdf6b | |||
| ff1032e5c2 | |||
| 1e7c00e695 | |||
| 4e8e533bf7 | |||
| dfa15270c4 | |||
| bde3a4f680 | |||
| 4fb24c82cd | |||
| b1129c423f | |||
| 06fc24555f | |||
| 6c68d7592f | |||
| db535390db | |||
| 0383661414 | |||
| 089c4bc2e2 | |||
| 39b30a7d6b | |||
| 978256f3d8 | |||
| 9c6a92982f | |||
| bc4974c81b | |||
| f2b9d7c605 | |||
| dc2e331ab2 | |||
| 1a9082f6d7 | |||
| b1c479b61d | |||
| f09a14fbc3 | |||
| e7d9814fe4 | |||
| bd0f0eb037 | |||
| ff37c40787 | |||
| 29974f7b91 | |||
| 04307c8a3f | |||
| d493353e99 | |||
| 20cee7d0bb | |||
| 920cf596e6 | |||
| 9ee94147f0 | |||
| 66c48907a2 | |||
| f4658b68fa | |||
| b6d861e523 | |||
| 2c40a3eb35 | |||
| 9930cfe878 | |||
| 0f28e1bdd9 | |||
| 76baf799a2 | |||
| a0e16a2261 | |||
| 1231b4773d | |||
| c34f05cca7 | |||
| a88c8c1ae4 | |||
| cbda9c7ac7 | |||
| d3c468b758 | |||
| a015d3c82f | |||
| 166bc383e2 | |||
| d901b168b5 | |||
| 0660884ea0 | |||
| a407eccb61 | |||
| db561bceda | |||
| 1b22c1b816 | |||
| 4485ac1a25 | |||
| ef2df8f343 | |||
| c7476735c9 | |||
| 06baba54b4 | |||
| 035f6d909f | |||
| 31269a9f5f | |||
| 269d322de2 | |||
| 6ab61d7052 | |||
| ab0992f022 | |||
| a1a01ffb5e | |||
| e70fa7feba | |||
| 7b8ab230dc | |||
| f4b1d8dc17 | |||
| 7e7fd73b25 | |||
| 427b96aedf | |||
| 6b910364bb | |||
| f5f1915d59 | |||
| dd6cc9b52a | |||
| c5f808d85e | |||
| b9bcf7ca60 | |||
| f95909c764 | |||
| 4102deb962 | |||
| 8e10d74b21 | |||
| 6df9c4b990 | |||
| 01ef55e0f5 | |||
| 463e76ff8f | |||
| 9942ef0d95 | |||
| 0b0b3a95d0 | |||
| d4cd292c2a | |||
| c143114460 | |||
| ae3977a8f3 | |||
| 8a53ce2ff8 | |||
| 676fa25a0f | |||
| ab3c5f26ab | |||
| ab45fc0413 | |||
| c27ea2ae8d | |||
| 7e508f1ee2 | |||
| 81f7b37270 | |||
| 007ba6457e | |||
| 1df339ba75 | |||
| 10c0e7115b |
+4
-3
@@ -1052,7 +1052,7 @@ parse.h: parse.c
|
||||
|
||||
parse.c: $(TOP)/src/parse.y lemon$(BEXE)
|
||||
cp $(TOP)/src/parse.y .
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y
|
||||
|
||||
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
|
||||
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
|
||||
@@ -1069,6 +1069,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/misc/uint.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
@@ -1177,10 +1178,10 @@ FTS5_SRC = \
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon$(BEXE) $(OPTS) fts5parse.y
|
||||
./lemon$(BEXE) $(OPTS) -S fts5parse.y
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
|
||||
+17
-3
@@ -248,6 +248,12 @@ OPTIMIZATIONS = 2
|
||||
SESSION = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to non-0 to enable support for the rbu extension.
|
||||
#
|
||||
!IFNDEF RBU
|
||||
RBU = 0
|
||||
!ENDIF
|
||||
|
||||
# Set the source code file to be used by executables and libraries when
|
||||
# they need the amalgamation.
|
||||
#
|
||||
@@ -364,6 +370,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
!IF $(RBU)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -1742,7 +1755,7 @@ $(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
|
||||
sqlite3.def: libsqlite3.lib
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all libsqlite3.lib \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \
|
||||
| sort >> sqlite3.def
|
||||
# <</block2>>
|
||||
|
||||
@@ -2141,7 +2154,7 @@ parse.h: parse.c
|
||||
parse.c: $(TOP)\src\parse.y lemon.exe
|
||||
del /Q parse.y parse.h parse.h.temp 2>NUL
|
||||
copy $(TOP)\src\parse.y .
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) parse.y
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
|
||||
|
||||
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
|
||||
@@ -2169,6 +2182,7 @@ SHELL_SRC = \
|
||||
$(TOP)\ext\misc\shathree.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\completion.c \
|
||||
$(TOP)\ext\misc\uint.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
@@ -2301,7 +2315,7 @@ LSM1_SRC = \
|
||||
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
|
||||
copy $(TOP)\ext\fts5\fts5parse.y .
|
||||
del /Q fts5parse.h 2>NUL
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S fts5parse.y
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
|
||||
+14
-1
@@ -210,6 +210,12 @@ OPTIMIZATIONS = 2
|
||||
SESSION = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this to non-0 to enable support for the rbu extension.
|
||||
#
|
||||
!IFNDEF RBU
|
||||
RBU = 0
|
||||
!ENDIF
|
||||
|
||||
# Set the source code file to be used by executables and libraries when
|
||||
# they need the amalgamation.
|
||||
#
|
||||
@@ -295,6 +301,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
!IF $(RBU)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
@@ -977,7 +990,7 @@ Replace.exe:
|
||||
sqlite3.def: Replace.exe $(LIBOBJ)
|
||||
echo EXPORTS > sqlite3.def
|
||||
dumpbin /all $(LIBOBJ) \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| .\Replace.exe "^\s+/EXPORT:_?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@,]*)(?:@\d+|,DATA)?$$" $$1 true \
|
||||
| sort >> sqlite3.def
|
||||
|
||||
$(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLITE3H)
|
||||
|
||||
@@ -161,7 +161,7 @@ AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
|
||||
[--enable-rtree], [include rtree support [default=yes]])],
|
||||
[], [enable_rtree=yes])
|
||||
if test x"$enable_rtree" = "xyes"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE"
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
|
||||
fi
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
|
||||
# so you can encode the package version directly into the source files.
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
AC_INIT([sqlite], [3.7.4])
|
||||
AC_INIT([sqlite], [3.32.0])
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
|
||||
|
||||
@@ -153,7 +153,7 @@ Please `cd` to its location first.
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
PROJECT = sqlite3
|
||||
PROJECT = tclsqlite3
|
||||
!include "rules.vc"
|
||||
|
||||
# nmakehelp -V <file> <tag> will search the file for tag, skips until a
|
||||
@@ -162,18 +162,15 @@ PROJECT = sqlite3
|
||||
|
||||
!if [echo REM = This file is generated from Makefile.vc > versions.vc]
|
||||
!endif
|
||||
# get project version from row "AC_INIT([sqlite], [3.7.14])"
|
||||
# get project version from row "AC_INIT([sqlite], [3.x.y])"
|
||||
!if [echo DOTVERSION = \>> versions.vc] \
|
||||
&& [nmakehlp -V ..\configure.in AC_INIT >> versions.vc]
|
||||
&& [nmakehlp -V ..\configure.ac AC_INIT >> versions.vc]
|
||||
!endif
|
||||
!include "versions.vc"
|
||||
|
||||
VERSION = $(DOTVERSION:.=)
|
||||
STUBPREFIX = $(PROJECT)stub
|
||||
|
||||
DLLOBJS = \
|
||||
$(TMP_DIR)\tclsqlite3.obj
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Target names and paths ( shouldn't need changing )
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -182,7 +179,7 @@ BINROOT = .
|
||||
ROOT = ..
|
||||
|
||||
PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
|
||||
PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
|
||||
PRJLIBNAME = $(PROJECT).$(EXT)
|
||||
PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
|
||||
|
||||
PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
|
||||
@@ -204,6 +201,17 @@ DOCDIR = $(ROOT)\doc
|
||||
TOOLSDIR = $(ROOT)\tools
|
||||
COMPATDIR = $(ROOT)\compat
|
||||
|
||||
### Figure out where the primary source code file(s) is/are.
|
||||
!if exist("$(ROOT)\..\..\sqlite3.c") && exist("$(ROOT)\..\..\src\tclsqlite.c")
|
||||
SQL_INCLUDES = -I"$(ROOT)\..\.."
|
||||
SQLITE_SRCDIR = $(ROOT)\..\..
|
||||
TCLSQLITE_SRCDIR = $(ROOT)\..\..\src
|
||||
DLLOBJS = $(TMP_DIR)\sqlite3.obj $(TMP_DIR)\tclsqlite.obj
|
||||
!else
|
||||
TCLSQLITE_SRCDIR = $(ROOT)\generic
|
||||
DLLOBJS = $(TMP_DIR)\tclsqlite3.obj
|
||||
!endif
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Compile flags
|
||||
#---------------------------------------------------------------------
|
||||
@@ -223,7 +231,7 @@ cdebug = -Z7 -WX -Od -GZ
|
||||
!endif
|
||||
|
||||
### Declarations common to all compiler options
|
||||
cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\
|
||||
cflags = -nologo -c -W3 -D_CRT_SECURE_NO_WARNINGS -YX -Fp$(TMP_DIR)^\
|
||||
|
||||
!if $(MSVCRT)
|
||||
!if $(DEBUG)
|
||||
@@ -239,8 +247,8 @@ crt = -MT
|
||||
!endif
|
||||
!endif
|
||||
|
||||
INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" \
|
||||
-I"$(ROOT)\.."
|
||||
INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \
|
||||
-I"$(GENERICDIR)" -I"$(ROOT)\.."
|
||||
BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \
|
||||
-DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \
|
||||
-DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1
|
||||
@@ -341,20 +349,17 @@ $(PRJSTUBLIB): $(PRJSTUBOBJS)
|
||||
# Implicit rules
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
{$(WINDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
$(TMP_DIR)\sqlite3.obj: $(SQLITE_SRCDIR)\sqlite3.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(SQLITE_SRCDIR)\sqlite3.c
|
||||
|
||||
{$(GENERICDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
$(TMP_DIR)\tclsqlite.obj: $(TCLSQLITE_SRCDIR)\tclsqlite.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(TCLSQLITE_SRCDIR)\tclsqlite.c
|
||||
|
||||
{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<<
|
||||
$<
|
||||
<<
|
||||
$(TMP_DIR)\tclsqlite3.obj: $(TCLSQLITE_SRCDIR)\tclsqlite3.c
|
||||
$(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
|
||||
-c $(TCLSQLITE_SRCDIR)\tclsqlite3.c
|
||||
|
||||
{$(WINDIR)}.rc{$(TMP_DIR)}.res:
|
||||
$(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.31.0.
|
||||
# Generated by GNU Autoconf 2.69 for sqlite 3.32.0.
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||
@@ -726,8 +726,8 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.31.0'
|
||||
PACKAGE_STRING='sqlite 3.31.0'
|
||||
PACKAGE_VERSION='3.32.0'
|
||||
PACKAGE_STRING='sqlite 3.32.0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -906,6 +906,7 @@ enable_amalgamation
|
||||
enable_load_extension
|
||||
enable_memsys5
|
||||
enable_memsys3
|
||||
enable_all
|
||||
enable_fts3
|
||||
enable_fts4
|
||||
enable_fts5
|
||||
@@ -1466,7 +1467,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.31.0 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.32.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1531,7 +1532,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.31.0:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.32.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1559,6 +1560,7 @@ Optional Features:
|
||||
Disable loading of external extensions
|
||||
--enable-memsys5 Enable MEMSYS5
|
||||
--enable-memsys3 Enable MEMSYS3
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
--enable-fts3 Enable the FTS3 extension
|
||||
--enable-fts4 Enable the FTS4 extension
|
||||
--enable-fts5 Enable the FTS5 extension
|
||||
@@ -1657,7 +1659,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.31.0
|
||||
sqlite configure 3.32.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -2076,7 +2078,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.31.0, which was
|
||||
It was created by sqlite $as_me 3.32.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3934,13 +3936,13 @@ if ${lt_cv_nm_interface+:} false; then :
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3937: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3939: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3943: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3945: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -5146,7 +5148,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5149 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5151 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6671,11 +6673,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:6674: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6676: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6678: \$? = $ac_status" >&5
|
||||
echo "$as_me:6680: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7010,11 +7012,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7013: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7015: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7017: \$? = $ac_status" >&5
|
||||
echo "$as_me:7019: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7115,11 +7117,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7118: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7120: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7122: \$? = $ac_status" >&5
|
||||
echo "$as_me:7124: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -7170,11 +7172,11 @@ else
|
||||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:7173: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7175: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7177: \$? = $ac_status" >&5
|
||||
echo "$as_me:7179: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -9550,7 +9552,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9553 "configure"
|
||||
#line 9555 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -9646,7 +9648,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9649 "configure"
|
||||
#line 9651 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -11450,6 +11452,15 @@ else
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
# Check whether --enable-all was given.
|
||||
if test "${enable_all+set}" = set; then :
|
||||
enableval=$enable_all;
|
||||
fi
|
||||
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
# Check whether --enable-fts3 was given.
|
||||
@@ -11465,7 +11476,7 @@ if test "${enable_fts4+set}" = set; then :
|
||||
enableval=$enable_fts4;
|
||||
fi
|
||||
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11529,7 +11540,7 @@ if test "${enable_fts5+set}" = set; then :
|
||||
enableval=$enable_fts5;
|
||||
fi
|
||||
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
|
||||
$as_echo_n "checking for library containing log... " >&6; }
|
||||
@@ -11596,7 +11607,7 @@ if test "${enable_json1+set}" = set; then :
|
||||
enableval=$enable_json1;
|
||||
fi
|
||||
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
@@ -11621,7 +11632,7 @@ else
|
||||
enable_geopoly=no
|
||||
fi
|
||||
|
||||
if test "${enable_geopoly}" = "yes" ; then
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
fi
|
||||
@@ -11644,7 +11655,7 @@ if test "${enable_session+set}" = set; then :
|
||||
enableval=$enable_session;
|
||||
fi
|
||||
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
@@ -12232,7 +12243,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.31.0, which was
|
||||
This file was extended by sqlite $as_me 3.32.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -12298,7 +12309,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.31.0
|
||||
sqlite config.status 3.32.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+11
-5
@@ -613,6 +613,12 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
########
|
||||
# The --enable-extensions argument is short-hand to enable
|
||||
# multiple extensions.
|
||||
AC_ARG_ENABLE(all, AC_HELP_STRING([--enable-all],
|
||||
[Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions]))
|
||||
|
||||
#########
|
||||
# See whether we should enable Full Text Search extensions
|
||||
AC_ARG_ENABLE(fts3, AC_HELP_STRING([--enable-fts3],
|
||||
@@ -622,13 +628,13 @@ if test "${enable_fts3}" = "yes" ; then
|
||||
fi
|
||||
AC_ARG_ENABLE(fts4, AC_HELP_STRING([--enable-fts4],
|
||||
[Enable the FTS4 extension]))
|
||||
if test "${enable_fts4}" = "yes" ; then
|
||||
if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5],
|
||||
[Enable the FTS5 extension]))
|
||||
if test "${enable_fts5}" = "yes" ; then
|
||||
if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
|
||||
AC_SEARCH_LIBS([log],[m])
|
||||
fi
|
||||
@@ -636,7 +642,7 @@ fi
|
||||
#########
|
||||
# See whether we should enable JSON1
|
||||
AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension]))
|
||||
if test "${enable_json1}" = "yes" ; then
|
||||
if test "${enable_json1}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1"
|
||||
fi
|
||||
|
||||
@@ -654,7 +660,7 @@ fi
|
||||
AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly],
|
||||
[Enable the GEOPOLY extension]),
|
||||
[enable_geopoly=yes],[enable_geopoly=no])
|
||||
if test "${enable_geopoly}" = "yes" ; then
|
||||
if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
|
||||
enable_rtree=yes
|
||||
fi
|
||||
@@ -671,7 +677,7 @@ fi
|
||||
# See whether we should enable the SESSION extension
|
||||
AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session],
|
||||
[Enable the SESSION extension]))
|
||||
if test "${enable_session}" = "yes" ; then
|
||||
if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
|
||||
fi
|
||||
|
||||
+6
-6
@@ -123,7 +123,7 @@ Suppress generation of the report file.
|
||||
<li><b>-r</b>
|
||||
Do not sort or renumber the parser states as part of optimization.
|
||||
<li><b>-s</b>
|
||||
Show parser statistics before existing.
|
||||
Show parser statistics before exiting.
|
||||
<li><b>-T<i>file</i></b>
|
||||
Use <i>file</i> as the template for the generated C-code parser implementation.
|
||||
<li><b>-x</b>
|
||||
@@ -488,7 +488,7 @@ is an error.</p>
|
||||
The precedence of a grammar rule is equal to the precedence of the
|
||||
left-most terminal symbol in the rule for which a precedence is
|
||||
defined. This is normally what you want, but in those cases where
|
||||
you want to precedence of a grammar rule to be something different,
|
||||
you want the precedence of a grammar rule to be something different,
|
||||
you can specify an alternative precedence symbol by putting the
|
||||
symbol in square braces after the period at the end of the rule and
|
||||
before any C-code. For example:</p>
|
||||
@@ -689,7 +689,7 @@ on Parse().
|
||||
<a name='extractx'></a>
|
||||
<h4>The <tt>%extra_context</tt> directive</h4>
|
||||
|
||||
The <tt>%extra_context</tt> directive instructs Lemon to add a 2th parameter
|
||||
The <tt>%extra_context</tt> directive instructs Lemon to add a 2nd parameter
|
||||
to the parameter list of the ParseAlloc() and ParseInif() functions. Lemon
|
||||
doesn't do anything itself with these extra argument, but it does
|
||||
store the value make it available to C-code action routines, destructors,
|
||||
@@ -699,9 +699,9 @@ and so forth. For example, if the grammar file contains:</p>
|
||||
%extra_context { MyStruct *pAbc }
|
||||
</pre></p>
|
||||
|
||||
<p>Then the ParseAlloc() and ParseInit() functions will have an 2th parameter
|
||||
<p>Then the ParseAlloc() and ParseInit() functions will have an 2nd parameter
|
||||
of type "MyStruct*" and all action routines will have access to
|
||||
a variable named "pAbc" that is the value of that 2th parameter.</p>
|
||||
a variable named "pAbc" that is the value of that 2nd parameter.</p>
|
||||
|
||||
<p>The <tt>%extra_argument</tt> directive works the same except that it
|
||||
is passed in on the Parse() routine instead of on ParseAlloc()/ParseInit().
|
||||
@@ -996,7 +996,7 @@ on the parser's stack associated with terminal and non-terminal
|
||||
symbols. The values of all terminal symbols must be of the same
|
||||
type. This turns out to be the same data type as the 3rd parameter
|
||||
to the Parse() function generated by Lemon. Typically, you will
|
||||
make the value of a terminal symbol by a pointer to some kind of
|
||||
make the value of a terminal symbol be a pointer to some kind of
|
||||
token structure. Like this:</p>
|
||||
|
||||
<p><pre>
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# The new-security-options branch
|
||||
|
||||
## The problem that the [new-security-options](/timeline?r=new-security-options) branch tries to solve
|
||||
|
||||
An attacker might modify the schema of an SQLite database by adding
|
||||
structures that cause code to run when some other application opens and
|
||||
reads the database. For example, the attacker might replace a table
|
||||
definition with a view. Or the attacker might add triggers to tables
|
||||
or views, or add new CHECK constraints or generated columns or indexes
|
||||
with expressions in the index list or in the WHERE clause. If the
|
||||
added features invoke SQL functions or virtual tables with side effects,
|
||||
that might cause harm to the system if run by a high-privilege victim.
|
||||
Or, the added features might exfiltrate information if the database is
|
||||
read by a high-privilege victim.
|
||||
|
||||
The changes in this branch strive to make it easier for high-privilege
|
||||
applications to safely read SQLite database files that might have been
|
||||
maliciously corrupted by an attacker.
|
||||
|
||||
## Overview of changes in [new-security-options](/timeline?r=new-security-options)
|
||||
|
||||
The basic idea is to tag every SQL function and virtual table with one
|
||||
of three risk levels:
|
||||
|
||||
1. Innocuous
|
||||
2. Normal
|
||||
3. Direct-Only
|
||||
|
||||
Innocuous functions/vtabs are safe and can be used at any time.
|
||||
Direct-only elements, in contrast, might have cause side-effects and
|
||||
should only be used from top-level SQL, not from within triggers or views nor
|
||||
in elements of the schema such as CHECK constraint, DEFAULT values,
|
||||
generated columns, index expressions, or in the WHERE clause of a
|
||||
partial index that are potentially under the control of an attacker.
|
||||
Normal elements behave like Innocuous if TRUSTED\_SCHEMA=on
|
||||
and behave like direct-only if TRUSTED\_SCHEMA=off.
|
||||
|
||||
Application-defined functions and virtual tables go in as Normal unless
|
||||
the application takes deliberate steps to change the risk level.
|
||||
|
||||
For backwards compatibility, the default is TRUSTED\_SCHEMA=on. Documentation
|
||||
will be updated to recommend applications turn TRUSTED\_SCHEMA to off.
|
||||
|
||||
An innocuous function or virtual table is one that can only read content
|
||||
from the database file in which it resides, and can only alter the database
|
||||
in which it resides. Most SQL functions are innocuous. For example, there
|
||||
is no harm in an attacker running the abs() function.
|
||||
|
||||
Direct-only elements that have side-effects that go outside the database file
|
||||
in which it lives, or return information from outside of the database file.
|
||||
Examples of direct-only elements include:
|
||||
|
||||
1. The fts3\_tokenizer() function
|
||||
2. The writefile() function
|
||||
3. The readfile() function
|
||||
4. The zipvfs virtual table
|
||||
5. The csv virtual table
|
||||
|
||||
We do not want an attacker to be able to add these kinds of things to
|
||||
the database schema and possibly trick a high-privilege application
|
||||
from performing any of these actions. Therefore, functions and vtabs
|
||||
with side-effects are marked as Direct-Only.
|
||||
|
||||
Legacy applications might add other risky functions or vtabs. Those will
|
||||
go in as "Normal" by default. For optimal security, we want those risky
|
||||
app-defined functions and vtabs to be direct-only, but making that the
|
||||
default might break some legacy applications. Hence, all app-defined
|
||||
functions and vtabs go in as Normal, but the application can switch them
|
||||
over to "Direct-Only" behavior using a single pragma.
|
||||
|
||||
The restrictions on the use of functions and virtual tables do not apply
|
||||
to TEMP. A TEMP VIEW or a TEMP TRIGGER can use any valid SQL function
|
||||
or virtual table. The idea is that TEMP views and triggers must be
|
||||
directly created by the application and are thus under the control of the
|
||||
application. TEMP views and triggers cannot be created by an attacker who
|
||||
corrupts the schema of a persistent database file. Hence TEMP views and
|
||||
triggers are safe.
|
||||
|
||||
## Specific changes
|
||||
|
||||
1. New sqlite3\_db\_config() option SQLITE\_DBCONFIG\_TRUSTED\_SCHEMA for
|
||||
turning TRUSTED\_SCHEMA on and off. It defaults to ON.
|
||||
|
||||
2. Compile-time option -DSQLITE\_TRUSTED\_SCHEMA=0 causes the default
|
||||
TRUSTED\_SCHEMA setting to be off.
|
||||
|
||||
3. New pragma "PRAGMA trusted\_schema=(ON\|OFF);". This provides access
|
||||
to the TRUSTED_SCHEMA setting for application coded using scripting
|
||||
languages or other secondary languages where they are unable to make
|
||||
calls to sqlite3\_db\_config().
|
||||
|
||||
4. New options for the "enc" parameter to sqlite3\_create\_function() and
|
||||
its kin:
|
||||
<ol type="a">
|
||||
<li> _SQLITE\_INNOCUOUS_ → tags the new functions as Innocuous
|
||||
<li> _SQLITE\_DIRECTONLY_ → tags the new functions as Direct-Only
|
||||
</ol>
|
||||
|
||||
5. New options to sqlite3\_vtab\_config():
|
||||
<ol type="a">
|
||||
<li> _SQLITE\_VTAB\_INNOCUOUS_ → tags the vtab as Innocuous
|
||||
<li> _SQLITE\_VTAB\_DIRECTONLY_ → tags the vtab as Direct-Only
|
||||
</ol>
|
||||
|
||||
6. Change many of the functions and virtual tables in the SQLite source
|
||||
tree to use one of the tags above.
|
||||
|
||||
7. Enhanced PRAGMA function\_list and virtual-table "pragma\_function\_list"
|
||||
with additional columns. The columns now are:
|
||||
<ul>
|
||||
<li> _name_ → Name of the function
|
||||
<li> _builtin_ → 1 for built-in functions. 0 otherwise.
|
||||
<li> _type_ → 's'=Scalar, 'a'=Aggregate, 'w'=Window
|
||||
<li> _enc_ → 'utf8', 'utf16le', or 'utf16be'
|
||||
<li> _narg_ → number of argument
|
||||
<li> _flags_ → Bitmask of SQLITE\_INNOCUOUS, SQLITE\_DIRECTONLY,
|
||||
SQLITE\_DETERMINISTIC, SQLITE\_SUBTYPE, and
|
||||
SQLITE\_FUNC\_INTERNAL flags.
|
||||
</ul>
|
||||
<p>The last four columns are new.
|
||||
|
||||
8. The function\_list PRAGMA now also shows all entries for each function.
|
||||
So, for example, if a function can take either 2 or 3 arguments,
|
||||
there are separate rows for the 2-argument and 3-argument versions of
|
||||
the function.
|
||||
|
||||
## Additional Notes
|
||||
|
||||
The function_list enhancements allow the application to query the set
|
||||
of SQL functions that meet various criteria. For example, to see all
|
||||
SQL functions that are never allowed to be used in the schema or in
|
||||
trigger or views:
|
||||
|
||||
~~~
|
||||
SELECT DISTINCT name FROM pragma_function_list
|
||||
WHERE (flags & 0x80000)!=0
|
||||
ORDER BY name;
|
||||
~~~
|
||||
|
||||
Doing the same is not possible for virtual tables, as a virtual table
|
||||
might be Innocuous, Normal, or Direct-Only depending on the arguments
|
||||
passed into the xConnect method.
|
||||
+11
-4
@@ -37,6 +37,9 @@ proc squish {txt} {
|
||||
|
||||
proc do_setup_rec_test {tn setup sql res} {
|
||||
reset_db
|
||||
if {[info exists ::set_main_db_name]} {
|
||||
dbconfig_maindbname_icecube db
|
||||
}
|
||||
db eval $setup
|
||||
uplevel [list do_rec_test $tn $sql $res]
|
||||
}
|
||||
@@ -76,6 +79,10 @@ foreach {tn setup} {
|
||||
}
|
||||
}
|
||||
3 {
|
||||
if {[info commands sqlite3_expert_new]==""} { continue }
|
||||
set ::set_main_db_name 1
|
||||
}
|
||||
4 {
|
||||
if {![file executable $CLI]} { continue }
|
||||
|
||||
proc do_rec_test {tn sql res} {
|
||||
@@ -336,7 +343,7 @@ proc do_candidates_test {tn sql res} {
|
||||
|
||||
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
do_execsql_test 5.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
|
||||
@@ -346,7 +353,7 @@ do_execsql_test 4.0 {
|
||||
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
|
||||
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
|
||||
}
|
||||
do_candidates_test 4.1 {
|
||||
do_candidates_test 5.1 {
|
||||
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
|
||||
} {
|
||||
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
|
||||
@@ -355,14 +362,14 @@ do_candidates_test 4.1 {
|
||||
CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5
|
||||
}
|
||||
|
||||
do_candidates_test 4.2 {
|
||||
do_candidates_test 5.2 {
|
||||
SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=?
|
||||
} {
|
||||
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 17
|
||||
CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
do_execsql_test 5.3 {
|
||||
CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50
|
||||
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
|
||||
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 16
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(SQLITEEXPERT_H)
|
||||
#define SQLITEEXPERT_H 1
|
||||
#include "sqlite3.h"
|
||||
|
||||
typedef struct sqlite3expert sqlite3expert;
|
||||
@@ -165,4 +165,4 @@ const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
|
||||
*/
|
||||
void sqlite3_expert_destroy(sqlite3expert*);
|
||||
|
||||
|
||||
#endif /* !defined(SQLITEEXPERT_H) */
|
||||
|
||||
+101
-42
@@ -308,18 +308,6 @@
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following are copied from sqliteInt.h.
|
||||
**
|
||||
** Constants for the largest and smallest possible 64-bit signed integers.
|
||||
** These macros are designed to work correctly on both 32-bit and 64-bit
|
||||
** compilers.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
||||
# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
static int fts3EvalNext(Fts3Cursor *pCsr);
|
||||
static int fts3EvalStart(Fts3Cursor *pCsr);
|
||||
static int fts3TermSegReaderCursor(
|
||||
@@ -364,12 +352,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
v = (*ptr++); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
|
||||
const unsigned char *p = (const unsigned char*)pBuf;
|
||||
const unsigned char *pStart = p;
|
||||
u32 a;
|
||||
@@ -391,6 +374,41 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
return (int)(p - pStart);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
||||
return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0] and
|
||||
** not extending past pEnd[-1].
|
||||
** Return the number of bytes read, or 0 on error.
|
||||
** The value is stored in *v.
|
||||
*/
|
||||
int sqlite3Fts3GetVarintBounded(
|
||||
const char *pBuf,
|
||||
const char *pEnd,
|
||||
sqlite_int64 *v
|
||||
){
|
||||
const unsigned char *p = (const unsigned char*)pBuf;
|
||||
const unsigned char *pStart = p;
|
||||
const unsigned char *pX = (const unsigned char*)pEnd;
|
||||
u64 b = 0;
|
||||
int shift;
|
||||
for(shift=0; shift<=63; shift+=7){
|
||||
u64 c = p<pX ? *p : 0;
|
||||
p++;
|
||||
b += (c&0x7F) << shift;
|
||||
if( (c & 0x80)==0 ) break;
|
||||
}
|
||||
*v = b;
|
||||
return (int)(p - pStart);
|
||||
}
|
||||
|
||||
/*
|
||||
** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
||||
** a non-negative 32-bit integer before it is returned.
|
||||
@@ -1486,6 +1504,10 @@ static int fts3InitVtab(
|
||||
fts3DatabasePageSize(&rc, p);
|
||||
p->nNodeSize = p->nPgsz-35;
|
||||
|
||||
#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST)
|
||||
p->nMergeCount = FTS3_MERGE_COUNT;
|
||||
#endif
|
||||
|
||||
/* Declare the table schema to SQLite. */
|
||||
fts3DeclareVtab(&rc, p);
|
||||
|
||||
@@ -1581,6 +1603,10 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
||||
int iDocidLe = -1; /* Index of docid<=x constraint, if present */
|
||||
int iIdx;
|
||||
|
||||
if( p->bLock ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* By default use a full table scan. This is an expensive option,
|
||||
** so search through the constraints to see if a more efficient
|
||||
** strategy is possible.
|
||||
@@ -1779,7 +1805,11 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
|
||||
}else{
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v3(p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
|
||||
p->bLock++;
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
|
||||
@@ -1797,11 +1827,15 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
if( pCsr->isRequireSeek ){
|
||||
rc = fts3CursorSeekStmt(pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
|
||||
pTab->bLock++;
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
|
||||
pCsr->isRequireSeek = 0;
|
||||
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
|
||||
pTab->bLock--;
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
pTab->bLock--;
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
|
||||
/* If no row was found and no error has occurred, then the %_content
|
||||
@@ -1850,6 +1884,7 @@ static int fts3ScanInteriorNode(
|
||||
i64 nAlloc = 0; /* Size of allocated buffer */
|
||||
int isFirstTerm = 1; /* True when processing first term on page */
|
||||
sqlite3_int64 iChild; /* Block id of child node to descend to */
|
||||
int nBuffer = 0; /* Total term size */
|
||||
|
||||
/* Skip over the 'height' varint that occurs at the start of every
|
||||
** interior node. Then load the blockid of the left-child of the b-tree
|
||||
@@ -1874,12 +1909,15 @@ static int fts3ScanInteriorNode(
|
||||
int cmp; /* memcmp() result */
|
||||
int nSuffix; /* Size of term suffix */
|
||||
int nPrefix = 0; /* Size of term prefix */
|
||||
int nBuffer; /* Total term size */
|
||||
|
||||
/* Load the next term on the node into zBuffer. Use realloc() to expand
|
||||
** the size of zBuffer if required. */
|
||||
if( !isFirstTerm ){
|
||||
zCsr += fts3GetVarint32(zCsr, &nPrefix);
|
||||
if( nPrefix>nBuffer ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
goto finish_scan;
|
||||
}
|
||||
}
|
||||
isFirstTerm = 0;
|
||||
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
||||
@@ -1973,7 +2011,7 @@ static int fts3SelectLeaf(
|
||||
|
||||
fts3GetVarint32(zNode, &iHeight);
|
||||
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
|
||||
assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
|
||||
assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
|
||||
|
||||
if( rc==SQLITE_OK && iHeight>1 ){
|
||||
char *zBlob = 0; /* Blob read from %_segments table */
|
||||
@@ -1993,7 +2031,13 @@ static int fts3SelectLeaf(
|
||||
rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
|
||||
int iNewHeight = 0;
|
||||
fts3GetVarint32(zBlob, &iNewHeight);
|
||||
if( iNewHeight>=iHeight ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}else{
|
||||
rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
|
||||
}
|
||||
}
|
||||
sqlite3_free(zBlob);
|
||||
}
|
||||
@@ -2448,12 +2492,12 @@ static void fts3GetDeltaVarint3(
|
||||
if( *pp>=pEnd ){
|
||||
*pp = 0;
|
||||
}else{
|
||||
sqlite3_int64 iVal;
|
||||
*pp += sqlite3Fts3GetVarint(*pp, &iVal);
|
||||
u64 iVal;
|
||||
*pp += sqlite3Fts3GetVarintU(*pp, &iVal);
|
||||
if( bDescIdx ){
|
||||
*pVal -= iVal;
|
||||
*pVal = (i64)((u64)*pVal - iVal);
|
||||
}else{
|
||||
*pVal += iVal;
|
||||
*pVal = (i64)((u64)*pVal + iVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2480,15 +2524,16 @@ static void fts3PutDeltaVarint3(
|
||||
int *pbFirst, /* IN/OUT: True after first int written */
|
||||
sqlite3_int64 iVal /* Write this value to the list */
|
||||
){
|
||||
sqlite3_int64 iWrite;
|
||||
sqlite3_uint64 iWrite;
|
||||
if( bDescIdx==0 || *pbFirst==0 ){
|
||||
iWrite = iVal - *piPrev;
|
||||
assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
|
||||
iWrite = (u64)iVal - (u64)*piPrev;
|
||||
}else{
|
||||
iWrite = *piPrev - iVal;
|
||||
assert_fts3_nc( *piPrev>=iVal );
|
||||
iWrite = (u64)*piPrev - (u64)iVal;
|
||||
}
|
||||
assert( *pbFirst || *piPrev==0 );
|
||||
assert_fts3_nc( *pbFirst==0 || iWrite>0 );
|
||||
assert( *pbFirst==0 || iWrite>=0 );
|
||||
*pp += sqlite3Fts3PutVarint(*pp, iWrite);
|
||||
*piPrev = iVal;
|
||||
*pbFirst = 1;
|
||||
@@ -2504,7 +2549,8 @@ static void fts3PutDeltaVarint3(
|
||||
** Using this makes it easier to write code that can merge doclists that are
|
||||
** sorted in either ascending or descending order.
|
||||
*/
|
||||
#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
|
||||
/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
|
||||
#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
|
||||
|
||||
/*
|
||||
** This function does an "OR" merge of two doclists (output contains all
|
||||
@@ -2918,7 +2964,7 @@ static int fts3SegReaderCursor(
|
||||
** Fts3SegReaderPending might segfault, as the data structures used by
|
||||
** fts4aux are not completely populated. So it's easiest to filter these
|
||||
** calls out here. */
|
||||
if( iLevel<0 && p->aIndex ){
|
||||
if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
|
||||
Fts3SegReader *pSeg = 0;
|
||||
rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
|
||||
if( rc==SQLITE_OK && pSeg ){
|
||||
@@ -3181,6 +3227,8 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
int rc;
|
||||
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
|
||||
if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
|
||||
Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
|
||||
pTab->bLock++;
|
||||
if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
|
||||
pCsr->isEof = 1;
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
@@ -3188,6 +3236,7 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
pTab->bLock--;
|
||||
}else{
|
||||
rc = fts3EvalNext((Fts3Cursor *)pCursor);
|
||||
}
|
||||
@@ -3248,6 +3297,10 @@ static int fts3FilterMethod(
|
||||
UNUSED_PARAMETER(idxStr);
|
||||
UNUSED_PARAMETER(nVal);
|
||||
|
||||
if( p->bLock ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
eSearch = (idxNum & 0x0000FFFF);
|
||||
assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
|
||||
assert( p->pSegments==0 );
|
||||
@@ -3319,7 +3372,11 @@ static int fts3FilterMethod(
|
||||
);
|
||||
}
|
||||
if( zSql ){
|
||||
rc = sqlite3_prepare_v3(p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0);
|
||||
p->bLock++;
|
||||
rc = sqlite3_prepare_v3(
|
||||
p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
|
||||
);
|
||||
p->bLock--;
|
||||
sqlite3_free(zSql);
|
||||
}else{
|
||||
rc = SQLITE_NOMEM;
|
||||
@@ -4336,7 +4393,7 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
||||
int bIncrOk = (bOptOk
|
||||
&& pCsr->bDesc==pTab->bDescIdx
|
||||
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
|
||||
#ifdef SQLITE_TEST
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
&& pTab->bNoIncrDoclist==0
|
||||
#endif
|
||||
);
|
||||
@@ -4478,15 +4535,16 @@ static void fts3EvalDlPhraseNext(
|
||||
u8 *pbEof
|
||||
){
|
||||
char *pIter; /* Used to iterate through aAll */
|
||||
char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
|
||||
char *pEnd; /* 1 byte past end of aAll */
|
||||
|
||||
if( pDL->pNextDocid ){
|
||||
pIter = pDL->pNextDocid;
|
||||
assert( pDL->aAll!=0 || pIter==0 );
|
||||
}else{
|
||||
pIter = pDL->aAll;
|
||||
}
|
||||
|
||||
if( pIter>=pEnd ){
|
||||
if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){
|
||||
/* We have already reached the end of this doclist. EOF. */
|
||||
*pbEof = 1;
|
||||
}else{
|
||||
@@ -4858,12 +4916,13 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
||||
rc = sqlite3Fts3SelectDoctotal(p, &pStmt);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
assert( a );
|
||||
|
||||
pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarint(a, &nByte);
|
||||
testcase( a==0 ); /* If %_stat.value set to X'' */
|
||||
if( a ){
|
||||
pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
|
||||
while( a<pEnd ){
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nByte);
|
||||
}
|
||||
}
|
||||
if( nDoc==0 || nByte==0 ){
|
||||
sqlite3_reset(pStmt);
|
||||
|
||||
+17
-1
@@ -196,6 +196,9 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
||||
# define TESTONLY(X)
|
||||
#endif
|
||||
|
||||
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -239,6 +242,7 @@ struct Fts3Table {
|
||||
char *zLanguageid; /* languageid=xxx option, or NULL */
|
||||
int nAutoincrmerge; /* Value configured by 'automerge' */
|
||||
u32 nLeafAdd; /* Number of leaf blocks added this trans */
|
||||
int bLock; /* Used to prevent recursive content= tbls */
|
||||
|
||||
/* Precompiled statements used by the implementation. Each of these
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
@@ -297,13 +301,23 @@ struct Fts3Table {
|
||||
int mxSavepoint; /* Largest valid xSavepoint integer */
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
/* True to disable the incremental doclist optimization. This is controled
|
||||
** by special insert command 'test-no-incr-doclist'. */
|
||||
int bNoIncrDoclist;
|
||||
|
||||
/* Number of segments in a level */
|
||||
int nMergeCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Macro to find the number of segments to merge */
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
# define MergeCount(P) ((P)->nMergeCount)
|
||||
#else
|
||||
# define MergeCount(P) FTS3_MERGE_COUNT
|
||||
#endif
|
||||
|
||||
/*
|
||||
** When the core wants to read from the virtual table, it creates a
|
||||
** virtual table cursor (an instance of the following structure) using
|
||||
@@ -567,6 +581,8 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
|
||||
void sqlite3Fts3ErrMsg(char**,const char*,...);
|
||||
int sqlite3Fts3PutVarint(char *, sqlite3_int64);
|
||||
int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
|
||||
int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
|
||||
int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
|
||||
int sqlite3Fts3GetVarint32(const char *, int *);
|
||||
int sqlite3Fts3VarintLen(sqlite3_uint64);
|
||||
void sqlite3Fts3Dequote(char *);
|
||||
|
||||
+31
-9
@@ -560,7 +560,7 @@ static int fts3BestSnippet(
|
||||
/* Set the *pmSeen output variable. */
|
||||
for(i=0; i<nList; i++){
|
||||
if( sIter.aPhrase[i].pHead ){
|
||||
*pmSeen |= (u64)1 << i;
|
||||
*pmSeen |= (u64)1 << (i%64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1038,11 +1038,15 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
Fts3Table *pTab,
|
||||
sqlite3_stmt **ppStmt,
|
||||
sqlite3_int64 *pnDoc,
|
||||
const char **paLen
|
||||
const char **paLen,
|
||||
const char **ppEnd
|
||||
){
|
||||
sqlite3_stmt *pStmt;
|
||||
const char *a;
|
||||
const char *pEnd;
|
||||
sqlite3_int64 nDoc;
|
||||
int n;
|
||||
|
||||
|
||||
if( !*ppStmt ){
|
||||
int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
|
||||
@@ -1051,12 +1055,20 @@ static int fts3MatchinfoSelectDoctotal(
|
||||
pStmt = *ppStmt;
|
||||
assert( sqlite3_data_count(pStmt)==1 );
|
||||
|
||||
n = sqlite3_column_bytes(pStmt, 0);
|
||||
a = sqlite3_column_blob(pStmt, 0);
|
||||
a += sqlite3Fts3GetVarint(a, &nDoc);
|
||||
if( nDoc==0 ) return FTS_CORRUPT_VTAB;
|
||||
*pnDoc = (u32)nDoc;
|
||||
if( a==0 ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
pEnd = a + n;
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
|
||||
if( nDoc<=0 || a>pEnd ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
*pnDoc = nDoc;
|
||||
|
||||
if( paLen ) *paLen = a;
|
||||
if( ppEnd ) *ppEnd = pEnd;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -1237,7 +1249,7 @@ static int fts3MatchinfoValues(
|
||||
case FTS3_MATCHINFO_NDOC:
|
||||
if( bGlobal ){
|
||||
sqlite3_int64 nDoc = 0;
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0);
|
||||
pInfo->aMatchinfo[0] = (u32)nDoc;
|
||||
}
|
||||
break;
|
||||
@@ -1246,14 +1258,19 @@ static int fts3MatchinfoValues(
|
||||
if( bGlobal ){
|
||||
sqlite3_int64 nDoc; /* Number of rows in table */
|
||||
const char *a; /* Aggregate column length array */
|
||||
const char *pEnd; /* First byte past end of length array */
|
||||
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd);
|
||||
if( rc==SQLITE_OK ){
|
||||
int iCol;
|
||||
for(iCol=0; iCol<pInfo->nCol; iCol++){
|
||||
u32 iVal;
|
||||
sqlite3_int64 nToken;
|
||||
a += sqlite3Fts3GetVarint(a, &nToken);
|
||||
if( a>pEnd ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
|
||||
pInfo->aMatchinfo[iCol] = iVal;
|
||||
}
|
||||
@@ -1267,9 +1284,14 @@ static int fts3MatchinfoValues(
|
||||
if( rc==SQLITE_OK ){
|
||||
int iCol;
|
||||
const char *a = sqlite3_column_blob(pSelectDocsize, 0);
|
||||
const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0);
|
||||
for(iCol=0; iCol<pInfo->nCol; iCol++){
|
||||
sqlite3_int64 nToken;
|
||||
a += sqlite3Fts3GetVarint(a, &nToken);
|
||||
a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken);
|
||||
if( a>pEnd ){
|
||||
rc = SQLITE_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
pInfo->aMatchinfo[iCol] = (u32)nToken;
|
||||
}
|
||||
}
|
||||
@@ -1300,7 +1322,7 @@ static int fts3MatchinfoValues(
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
if( bGlobal ){
|
||||
if( pCsr->pDeferred ){
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
|
||||
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
||||
|
||||
@@ -350,7 +350,7 @@ static int fts3tokFilterMethod(
|
||||
if( pCsr->zInput==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
memcpy(pCsr->zInput, zByte, nByte);
|
||||
if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
||||
pCsr->zInput[nByte] = 0;
|
||||
rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
@@ -390,7 +390,9 @@ int queryTokenizer(
|
||||
|
||||
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
|
||||
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
|
||||
if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB
|
||||
&& sqlite3_column_bytes(pStmt, 0)==sizeof(*pp)
|
||||
){
|
||||
memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
|
||||
}
|
||||
}
|
||||
@@ -479,7 +481,7 @@ int sqlite3Fts3InitHashTable(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
void *p = (void *)pHash;
|
||||
const int any = SQLITE_ANY;
|
||||
const int any = SQLITE_UTF8|SQLITE_DIRECTONLY;
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
char *zTest = 0;
|
||||
|
||||
+86
-44
@@ -23,7 +23,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FTS_MAX_APPENDABLE_HEIGHT 16
|
||||
|
||||
@@ -67,7 +67,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The two values that may be meaningfully bound to the :1 parameter in
|
||||
** The values that may be meaningfully bound to the :1 parameter in
|
||||
** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
|
||||
*/
|
||||
#define FTS_STAT_DOCTOTAL 0
|
||||
@@ -335,7 +335,7 @@ static int fts3SqlStmt(
|
||||
** returns zero rows. */
|
||||
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
|
||||
" GROUP BY level HAVING cnt>=?"
|
||||
" ORDER BY (level %% 1024) ASC LIMIT 1",
|
||||
" ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",
|
||||
|
||||
/* Estimate the upper limit on the number of leaf nodes in a new segment
|
||||
** created by merging the oldest :2 segments from absolute level :1. See
|
||||
@@ -696,7 +696,7 @@ static int fts3PendingListAppend(
|
||||
assert( !p || p->iLastDocid<=iDocid );
|
||||
|
||||
if( !p || p->iLastDocid!=iDocid ){
|
||||
sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
|
||||
u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
|
||||
if( p ){
|
||||
assert( p->nData<p->nSpace );
|
||||
assert( p->aData[p->nData]==0 );
|
||||
@@ -1153,7 +1153,7 @@ static int fts3AllocateSegdirIdx(
|
||||
** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
|
||||
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
|
||||
*/
|
||||
if( iNext>=FTS3_MERGE_COUNT ){
|
||||
if( iNext>=MergeCount(p) ){
|
||||
fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
|
||||
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
|
||||
*piIdx = 0;
|
||||
@@ -1237,6 +1237,8 @@ int sqlite3Fts3ReadBlock(
|
||||
}
|
||||
*paBlob = aByte;
|
||||
}
|
||||
}else if( rc==SQLITE_ERROR ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
return rc;
|
||||
@@ -1379,7 +1381,7 @@ static int fts3SegReaderNext(
|
||||
pNext += fts3GetVarint32(pNext, &nSuffix);
|
||||
if( nSuffix<=0
|
||||
|| (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
|
||||
|| nPrefix>pReader->nTermAlloc
|
||||
|| nPrefix>pReader->nTerm
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -1413,6 +1415,7 @@ static int fts3SegReaderNext(
|
||||
*/
|
||||
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
|| pReader->nDoclist==0
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -1529,18 +1532,18 @@ static int fts3SegReaderNextDocid(
|
||||
}else{
|
||||
rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_int64 iDelta;
|
||||
pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
|
||||
u64 iDelta;
|
||||
pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
|
||||
if( pTab->bDescIdx ){
|
||||
pReader->iDocid -= iDelta;
|
||||
pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
|
||||
}else{
|
||||
pReader->iDocid += iDelta;
|
||||
pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -2030,6 +2033,11 @@ static int fts3NodeAddTerm(
|
||||
nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm);
|
||||
nSuffix = nTerm-nPrefix;
|
||||
|
||||
/* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
||||
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
||||
** compared with BINARY collation. This indicates corruption. */
|
||||
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix;
|
||||
if( nReq<=p->nNodeSize || !pTree->zTerm ){
|
||||
|
||||
@@ -2274,6 +2282,7 @@ static int fts3SegWriterAdd(
|
||||
int rc;
|
||||
|
||||
/* The current leaf node is full. Write it out to the database. */
|
||||
if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
|
||||
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
p->nLeafAdd++;
|
||||
@@ -2323,9 +2332,11 @@ static int fts3SegWriterAdd(
|
||||
/* Append the prefix-compressed term and doclist to the buffer. */
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix);
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix);
|
||||
assert( nSuffix>0 );
|
||||
memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix);
|
||||
nData += nSuffix;
|
||||
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist);
|
||||
assert( nDoclist>0 );
|
||||
memcpy(&pWriter->aData[nData], aDoclist, nDoclist);
|
||||
pWriter->nData = nData + nDoclist;
|
||||
|
||||
@@ -2345,6 +2356,7 @@ static int fts3SegWriterAdd(
|
||||
pWriter->zTerm = zNew;
|
||||
}
|
||||
assert( pWriter->zTerm==pWriter->zMalloc );
|
||||
assert( nTerm>0 );
|
||||
memcpy(pWriter->zTerm, zTerm, nTerm);
|
||||
}else{
|
||||
pWriter->zTerm = (char *)zTerm;
|
||||
@@ -2491,7 +2503,7 @@ static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
|
||||
sqlite3_bind_int64(pStmt, 2,
|
||||
((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
||||
(((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
||||
);
|
||||
|
||||
*pbMax = 0;
|
||||
@@ -2653,6 +2665,7 @@ static int fts3MsrBufferData(
|
||||
pMsr->aBuffer = pNew;
|
||||
}
|
||||
|
||||
assert( nList>0 );
|
||||
memcpy(pMsr->aBuffer, pList, nList);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -2966,14 +2979,12 @@ int sqlite3Fts3SegReaderStep(
|
||||
** doclist. */
|
||||
sqlite3_int64 iDelta;
|
||||
if( p->bDescIdx && nDoclist>0 ){
|
||||
iDelta = iPrev - iDocid;
|
||||
if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
|
||||
iDelta = (i64)((u64)iPrev - (u64)iDocid);
|
||||
}else{
|
||||
iDelta = iDocid - iPrev;
|
||||
if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
|
||||
iDelta = (i64)((u64)iDocid - (u64)iPrev);
|
||||
}
|
||||
if( iDelta<=0 && (nDoclist>0 || iDelta!=iDocid) ){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
assert( nDoclist>0 || iDelta==iDocid );
|
||||
|
||||
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
||||
if( nDoclist+nByte>pCsr->nBuffer ){
|
||||
@@ -3255,7 +3266,7 @@ static int fts3SegmentMerge(
|
||||
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
|
||||
}
|
||||
if( rc!=SQLITE_OK ) goto finished;
|
||||
assert( pWriter || bIgnoreEmpty );
|
||||
assert_fts3_nc( pWriter || bIgnoreEmpty );
|
||||
|
||||
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
|
||||
rc = fts3DeleteSegdir(
|
||||
@@ -3843,6 +3854,7 @@ static int fts3IncrmergePush(
|
||||
** be added to. */
|
||||
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
|
||||
nSuffix = nTerm - nPrefix;
|
||||
if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
||||
nSpace = sqlite3Fts3VarintLen(nPrefix);
|
||||
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
||||
|
||||
@@ -4237,6 +4249,10 @@ static int fts3IncrmergeLoad(
|
||||
pWriter->bNoLeafData = (pWriter->nLeafData==0);
|
||||
nRoot = sqlite3_column_bytes(pSelect, 4);
|
||||
aRoot = sqlite3_column_blob(pSelect, 4);
|
||||
if( aRoot==0 ){
|
||||
sqlite3_reset(pSelect);
|
||||
return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB;
|
||||
}
|
||||
}else{
|
||||
return sqlite3_reset(pSelect);
|
||||
}
|
||||
@@ -4272,6 +4288,10 @@ static int fts3IncrmergeLoad(
|
||||
int i;
|
||||
int nHeight = (int)aRoot[0];
|
||||
NodeWriter *pNode;
|
||||
if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
|
||||
sqlite3_reset(pSelect);
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
|
||||
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
|
||||
pWriter->iStart = iStart;
|
||||
@@ -4832,13 +4852,17 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
|
||||
const int nHint = pHint->n;
|
||||
int i;
|
||||
|
||||
i = pHint->n-2;
|
||||
i = pHint->n-1;
|
||||
if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB;
|
||||
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
|
||||
if( i==0 ) return FTS_CORRUPT_VTAB;
|
||||
i--;
|
||||
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
|
||||
|
||||
pHint->n = i;
|
||||
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
|
||||
i += fts3GetVarint32(&pHint->a[i], pnInput);
|
||||
assert( i<=nHint );
|
||||
if( i!=nHint ) return FTS_CORRUPT_VTAB;
|
||||
|
||||
return SQLITE_OK;
|
||||
@@ -4908,8 +4932,14 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
|
||||
rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
|
||||
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
|
||||
/* Based on the scan in the block above, it is known that there
|
||||
** are no levels with a relative level smaller than that of
|
||||
** iAbsLevel with more than nSeg segments, or if nSeg is -1,
|
||||
** no levels with more than nMin segments. Use this to limit the
|
||||
** value of nHintSeg to avoid a large memory allocation in case the
|
||||
** merge-hint is corrupt*/
|
||||
iAbsLevel = iHintAbsLevel;
|
||||
nSeg = nHintSeg;
|
||||
nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
|
||||
bUseHint = 1;
|
||||
bDirtyHint = 1;
|
||||
}else{
|
||||
@@ -4922,7 +4952,13 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
||||
/* If nSeg is less that zero, then there is no level with at least
|
||||
** nMin segments and no hint in the %_stat table. No work to do.
|
||||
** Exit early in this case. */
|
||||
if( nSeg<0 ) break;
|
||||
if( nSeg<=0 ) break;
|
||||
|
||||
assert( nMod<=0x7FFFFFFF );
|
||||
if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
|
||||
rc = FTS_CORRUPT_VTAB;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Open a cursor to iterate through the contents of the oldest nSeg
|
||||
** indexes of absolute level iAbsLevel. If this cursor is opened using
|
||||
@@ -5040,7 +5076,7 @@ static int fts3DoIncrmerge(
|
||||
const char *zParam /* Nul-terminated string containing "A,B" */
|
||||
){
|
||||
int rc;
|
||||
int nMin = (FTS3_MERGE_COUNT / 2);
|
||||
int nMin = (MergeCount(p) / 2);
|
||||
int nMerge = 0;
|
||||
const char *z = zParam;
|
||||
|
||||
@@ -5085,7 +5121,7 @@ static int fts3DoAutoincrmerge(
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
p->nAutoincrmerge = fts3Getint(&zParam);
|
||||
if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){
|
||||
if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){
|
||||
p->nAutoincrmerge = 8;
|
||||
}
|
||||
if( !p->bHasStat ){
|
||||
@@ -5168,12 +5204,12 @@ static u64 fts3ChecksumIndex(
|
||||
|
||||
i64 iDocid = 0;
|
||||
i64 iCol = 0;
|
||||
i64 iPos = 0;
|
||||
u64 iPos = 0;
|
||||
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
|
||||
while( pCsr<pEnd ){
|
||||
i64 iVal = 0;
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
|
||||
u64 iVal = 0;
|
||||
pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
|
||||
if( pCsr<pEnd ){
|
||||
if( iVal==0 || iVal==1 ){
|
||||
iCol = 0;
|
||||
@@ -5181,11 +5217,11 @@ static u64 fts3ChecksumIndex(
|
||||
if( iVal ){
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
|
||||
}else{
|
||||
pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
|
||||
pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
|
||||
if( p->bDescIdx ){
|
||||
iDocid -= iVal;
|
||||
iDocid = (i64)((u64)iDocid - iVal);
|
||||
}else{
|
||||
iDocid += iVal;
|
||||
iDocid = (i64)((u64)iDocid + iVal);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -5346,7 +5382,7 @@ static int fts3DoIntegrityCheck(
|
||||
** meaningful value to insert is the text 'optimize'.
|
||||
*/
|
||||
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
int rc; /* Return Code */
|
||||
int rc = SQLITE_ERROR; /* Return Code */
|
||||
const char *zVal = (const char *)sqlite3_value_text(pVal);
|
||||
int nVal = sqlite3_value_bytes(pVal);
|
||||
|
||||
@@ -5362,21 +5398,27 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
||||
rc = fts3DoIncrmerge(p, &zVal[6]);
|
||||
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
|
||||
rc = fts3DoAutoincrmerge(p, &zVal[10]);
|
||||
#ifdef SQLITE_TEST
|
||||
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
p->nNodeSize = atoi(&zVal[9]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
p->nMaxPendingData = atoi(&zVal[11]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
|
||||
p->bNoIncrDoclist = atoi(&zVal[21]);
|
||||
rc = SQLITE_OK;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
int v;
|
||||
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
|
||||
v = atoi(&zVal[9]);
|
||||
if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){
|
||||
p->bNoIncrDoclist = atoi(&zVal[21]);
|
||||
rc = SQLITE_OK;
|
||||
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){
|
||||
v = atoi(&zVal[11]);
|
||||
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -159,7 +159,7 @@ struct Fts5PhraseIter {
|
||||
**
|
||||
** xSetAuxdata(pFts5, pAux, xDelete)
|
||||
**
|
||||
** Save the pointer passed as the second argument as the extension functions
|
||||
** Save the pointer passed as the second argument as the extension function's
|
||||
** "auxiliary data". The pointer may then be retrieved by the current or any
|
||||
** future invocation of the same fts5 extension function made as part of
|
||||
** the same MATCH query using the xGetAuxdata() API.
|
||||
@@ -401,8 +401,8 @@ struct Fts5ExtensionApi {
|
||||
**
|
||||
** There are several ways to approach this in FTS5:
|
||||
**
|
||||
** <ol><li> By mapping all synonyms to a single token. In this case, the
|
||||
** In the above example, this means that the tokenizer returns the
|
||||
** <ol><li> By mapping all synonyms to a single token. In this case, using
|
||||
** the above example, this means that the tokenizer returns the
|
||||
** same token for inputs "first" and "1st". Say that token is in
|
||||
** fact "first", so that when the user inserts the document "I won
|
||||
** 1st place" entries are added to the index for tokens "i", "won",
|
||||
|
||||
@@ -150,7 +150,7 @@ static int fts5Dequote(char *z){
|
||||
assert( q=='[' || q=='\'' || q=='"' || q=='`' );
|
||||
if( q=='[' ) q = ']';
|
||||
|
||||
while( ALWAYS(z[iIn]) ){
|
||||
while( z[iIn] ){
|
||||
if( z[iIn]==q ){
|
||||
if( z[iIn+1]!=q ){
|
||||
/* Character iIn was the close quote. */
|
||||
|
||||
@@ -2516,10 +2516,12 @@ static void fts5ExprFunction(
|
||||
azConfig[1] = "main";
|
||||
azConfig[2] = "tbl";
|
||||
for(i=3; iArg<nArg; iArg++){
|
||||
azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
|
||||
const char *z = (const char*)sqlite3_value_text(apVal[iArg]);
|
||||
azConfig[i++] = (z ? z : "");
|
||||
}
|
||||
|
||||
zExpr = (const char*)sqlite3_value_text(apVal[0]);
|
||||
if( zExpr==0 ) zExpr = "";
|
||||
|
||||
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+45
-4
@@ -5318,9 +5318,13 @@ int sqlite3Fts5IndexCharlenToBytelen(
|
||||
for(i=0; i<nChar; i++){
|
||||
if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
|
||||
if( (unsigned char)p[n++]>=0xc0 ){
|
||||
if( n>=nByte ) return 0;
|
||||
while( (p[n] & 0xc0)==0x80 ){
|
||||
n++;
|
||||
if( n>=nByte ) break;
|
||||
if( n>=nByte ){
|
||||
if( i+1==nChar ) break;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5722,6 +5726,37 @@ static int fts5QueryCksum(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if buffer z[], size n bytes, contains as series of valid utf-8
|
||||
** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
|
||||
** contain valid utf-8, return non-zero.
|
||||
*/
|
||||
static int fts5TestUtf8(const char *z, int n){
|
||||
int i = 0;
|
||||
assert_nc( n>0 );
|
||||
while( i<n ){
|
||||
if( (z[i] & 0x80)==0x00 ){
|
||||
i++;
|
||||
}else
|
||||
if( (z[i] & 0xE0)==0xC0 ){
|
||||
if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
|
||||
i += 2;
|
||||
}else
|
||||
if( (z[i] & 0xF0)==0xE0 ){
|
||||
if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
i += 3;
|
||||
}else
|
||||
if( (z[i] & 0xF8)==0xF0 ){
|
||||
if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
if( (z[i+2] & 0xC0)!=0x80 ) return 1;
|
||||
i += 3;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is also purely an internal test. It does not contribute to
|
||||
@@ -5762,8 +5797,14 @@ static void fts5TestTerm(
|
||||
** This check may only be performed if the hash table is empty. This
|
||||
** is because the hash table only supports a single scan query at
|
||||
** a time, and the multi-iter loop from which this function is called
|
||||
** is already performing such a scan. */
|
||||
if( p->nPendingData==0 ){
|
||||
** is already performing such a scan.
|
||||
**
|
||||
** Also only do this if buffer zTerm contains nTerm bytes of valid
|
||||
** utf-8. Otherwise, the last part of the buffer contents might contain
|
||||
** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
|
||||
** character stored in the main fts index, which will cause the
|
||||
** test to fail. */
|
||||
if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
|
||||
if( iIdx>0 && rc==SQLITE_OK ){
|
||||
int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
|
||||
ck2 = 0;
|
||||
@@ -5896,8 +5937,8 @@ static void fts5IndexIntegrityCheckSegment(
|
||||
i64 iRow; /* Rowid for this leaf */
|
||||
Fts5Data *pLeaf; /* Data for this leaf */
|
||||
|
||||
const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
|
||||
int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
|
||||
const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
|
||||
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
|
||||
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
|
||||
|
||||
|
||||
+30
-2
@@ -289,7 +289,10 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
|
||||
case FTS5_ROLLBACKTO:
|
||||
assert( p->ts.eState==1 );
|
||||
assert( iSavepoint>=-1 );
|
||||
assert( iSavepoint<=p->ts.iSavepoint );
|
||||
/* The following assert() can fail if another vtab strikes an error
|
||||
** within an xSavepoint() call then SQLite calls xRollbackTo() - without
|
||||
** having called xSavepoint() on this vtab. */
|
||||
/* assert( iSavepoint<=p->ts.iSavepoint ); */
|
||||
p->ts.iSavepoint = iSavepoint;
|
||||
break;
|
||||
}
|
||||
@@ -895,15 +898,24 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
default: {
|
||||
Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
|
||||
pConfig->bLock++;
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
pConfig->bLock--;
|
||||
if( rc!=SQLITE_ROW ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc!=SQLITE_OK ){
|
||||
pCursor->pVtab->zErrMsg = sqlite3_mprintf(
|
||||
"%s", sqlite3_errmsg(pConfig->db)
|
||||
);
|
||||
}
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1188,6 +1200,13 @@ static int fts5FilterMethod(
|
||||
int iIdxStr = 0;
|
||||
Fts5Expr *pExpr = 0;
|
||||
|
||||
if( pConfig->bLock ){
|
||||
pTab->p.base.zErrMsg = sqlite3_mprintf(
|
||||
"recursively defined fts5 content table"
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if( pCsr->ePlan ){
|
||||
fts5FreeCursorComponents(pCsr);
|
||||
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
|
||||
@@ -1408,10 +1427,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
|
||||
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
|
||||
assert( pCsr->pExpr );
|
||||
sqlite3_reset(pCsr->pStmt);
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
|
||||
pTab->pConfig->bLock++;
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
pTab->pConfig->bLock--;
|
||||
if( rc==SQLITE_ROW ){
|
||||
rc = SQLITE_OK;
|
||||
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
|
||||
@@ -1419,6 +1441,10 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = FTS5_CORRUPT;
|
||||
}else if( pTab->pConfig->pzErrmsg ){
|
||||
*pTab->pConfig->pzErrmsg = sqlite3_mprintf(
|
||||
"%s", sqlite3_errmsg(pTab->pConfig->db)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2434,10 +2460,12 @@ static int fts5ColumnMethod(
|
||||
}
|
||||
}
|
||||
}else if( !fts5IsContentless(pTab) ){
|
||||
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
rc = fts5SeekCursor(pCsr, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
|
||||
}
|
||||
pConfig->pzErrmsg = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -613,10 +613,11 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
||||
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
|
||||
ctx.szCol = 0;
|
||||
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
||||
const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
|
||||
int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
|
||||
rc = sqlite3Fts5Tokenize(pConfig,
|
||||
FTS5_TOKENIZE_DOCUMENT,
|
||||
(const char*)sqlite3_column_text(pScan, ctx.iCol+1),
|
||||
sqlite3_column_bytes(pScan, ctx.iCol+1),
|
||||
zText, nText,
|
||||
(void*)&ctx,
|
||||
fts5StorageInsertCallback
|
||||
);
|
||||
@@ -738,10 +739,11 @@ int sqlite3Fts5StorageIndexInsert(
|
||||
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
|
||||
ctx.szCol = 0;
|
||||
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
||||
const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
|
||||
int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
|
||||
rc = sqlite3Fts5Tokenize(pConfig,
|
||||
FTS5_TOKENIZE_DOCUMENT,
|
||||
(const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
|
||||
sqlite3_value_bytes(apVal[ctx.iCol+2]),
|
||||
zText, nText,
|
||||
(void*)&ctx,
|
||||
fts5StorageInsertCallback
|
||||
);
|
||||
@@ -910,10 +912,11 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
||||
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
|
||||
int nText = sqlite3_column_bytes(pScan, i+1);
|
||||
rc = sqlite3Fts5Tokenize(pConfig,
|
||||
FTS5_TOKENIZE_DOCUMENT,
|
||||
(const char*)sqlite3_column_text(pScan, i+1),
|
||||
sqlite3_column_bytes(pScan, i+1),
|
||||
zText, nText,
|
||||
(void*)&ctx,
|
||||
fts5StorageIntegrityCallback
|
||||
);
|
||||
|
||||
@@ -50,6 +50,7 @@ struct Fts5VocabTable {
|
||||
sqlite3 *db; /* Database handle */
|
||||
Fts5Global *pGlobal; /* FTS5 global object for this database */
|
||||
int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
|
||||
unsigned bBusy; /* True if busy */
|
||||
};
|
||||
|
||||
struct Fts5VocabCursor {
|
||||
@@ -332,6 +333,12 @@ static int fts5VocabOpenMethod(
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
char *zSql = 0;
|
||||
|
||||
if( pTab->bBusy ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf(
|
||||
"recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
||||
);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
zSql = sqlite3Fts5Mprintf(&rc,
|
||||
"SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
|
||||
pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
|
||||
@@ -343,10 +350,12 @@ static int fts5VocabOpenMethod(
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
|
||||
|
||||
pTab->bBusy = 1;
|
||||
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
i64 iId = sqlite3_column_int64(pStmt, 0);
|
||||
pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
|
||||
}
|
||||
pTab->bBusy = 0;
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
if( pFts5==0 ){
|
||||
|
||||
@@ -257,16 +257,41 @@ do_execsql_test 6.2 {
|
||||
# Check that an fts5 table cannot be its own content table.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.1 {
|
||||
do_execsql_test 7.1.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, c=t1 );
|
||||
INSERT INTO t1( a ) VALUES('abc');
|
||||
}
|
||||
do_catchsql_test 7.2 {
|
||||
do_catchsql_test 7.1.2 {
|
||||
SELECT * FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.3 {
|
||||
do_catchsql_test 7.1.3 {
|
||||
SELECT * FROM t1('abc');
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.1.4 {
|
||||
SELECT count(*) FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.1.5 {
|
||||
SELECT * FROM t1('abc') ORDER BY rank;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 7.2.1 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a, c=t2 );
|
||||
CREATE VIRTUAL TABLE t2 USING fts5(a, c=t1 );
|
||||
INSERT INTO t1( a ) VALUES('abc');
|
||||
}
|
||||
do_catchsql_test 7.2.2 {
|
||||
SELECT * FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.3 {
|
||||
SELECT * FROM t1('abc');
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.4 {
|
||||
SELECT count(*) FROM t1;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
do_catchsql_test 7.2.5 {
|
||||
SELECT * FROM t1('abc') ORDER BY rank;
|
||||
} {1 {recursively defined fts5 content table}}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -9774,6 +9774,339 @@ do_catchsql_test 66.1 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 67.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-43ed0ad79c0194.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 00 .....@ ........
|
||||
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
|
||||
| 112: 0e fc 0e 9d 0e 3d 0d e2 01 00 00 00 00 00 00 00 .....=..........
|
||||
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
|
||||
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
|
||||
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
|
||||
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
|
||||
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
|
||||
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
|
||||
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
|
||||
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
|
||||
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
|
||||
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
|
||||
| 3712: 49 4e 54 45 47 45 52 20 51 52 49 4d 41 52 59 20 INTEGER QRIMARY
|
||||
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
|
||||
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
|
||||
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
|
||||
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
|
||||
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
|
||||
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 f1 59 20 INTEGER PRIMA.Y
|
||||
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
|
||||
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
|
||||
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
|
||||
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
|
||||
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
|
||||
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
|
||||
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
|
||||
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
|
||||
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
|
||||
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
|
||||
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
|
||||
| 4000: 28 69 64 20 49 4e 54 45 47 55 52 20 50 52 49 4d (id INTEGUR PRIM
|
||||
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
|
||||
| 4032: 4c 50 42 29 3a 02 06 17 13 13 08 5f 74 61 62 6c LPB):......_tabl
|
||||
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
|
||||
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
|
||||
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f 44 00 05 0e 71 00 0f e7 0e 81 0f af 0f 58 ..D...q........X
|
||||
| 16: 0e 98 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
|
||||
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
|
||||
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 12 05 05 ...L.....0e.....
|
||||
| 3760: 07 05 01 01 04 03 03 08 04 03 01 2e 02 05 f7 07 ................
|
||||
| 3776: 01 e6 f5 07 05 01 01 04 03 03 01 22 03 18 03 03 ................
|
||||
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
|
||||
| 3808: 03 06 03 f4 06 04 03 00 36 03 ff 05 04 05 05 04 ........6.......
|
||||
| 3824: 05 05 04 05 04 f1 01 03 06 04 04 06 04 04 06 04 ................
|
||||
| 3840: 04 07 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
|
||||
| 3856: 02 08 a5 01 20 04 05 01 94 f7 05 07 05 05 01 01 .... ...........
|
||||
| 3872: 02 08 0a 0a 0a 04 01 65 03 02 0a 00 06 0a 0a 0a .......e........
|
||||
| 3888: 05 01 65 03 06 a7 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
|
||||
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
|
||||
| 3920: 00 02 01 01 01 02 11 01 50 88 80 80 80 80 01 04 ........P.......
|
||||
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
|
||||
| 3952: 05 e6 01 07 aa e3 08 03 03 02 01 65 02 1e 03 05 ...........e....
|
||||
| 3968: 05 05 04 f5 01 01 03 06 04 04 06 04 13 03 01 65 ...............e
|
||||
| 3984: 02 14 04 05 07 05 05 01 f7 f2 08 0a 04 01 65 02 ..............e.
|
||||
| 4000: 02 0a 05 01 65 02 06 00 f1 0a 04 12 14 0f 06 31 ....e..........1
|
||||
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
|
||||
| 4032: 01 10 02 05 05 00 01 04 03 03 02 01 65 01 12 03 ............e...
|
||||
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 04 05 04 ..........e.....
|
||||
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
|
||||
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 02 ...$............
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| page 4 offset 12288
|
||||
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
|
||||
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
|
||||
| 3632: 20 65 65 65 28 15 20 65 65 20 65 65 65 65 20 65 eee(. ee eeee e
|
||||
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 3664: 20 65 65 20 65 65 65 65 20 65 66 20 65 65 55 20 ee eeee ef eeU
|
||||
| 3680: 65 20 65 55 20 65 65 65 20 65 20 65 65 20 65 65 e eU eee e ee ee
|
||||
| 3696: 65 64 20 65 61 c0 65 65 65 20 65 20 65 65 20 65 ed ea.eee e ee e
|
||||
| 3712: 65 65 20 79 20 65 65 20 65 65 65 65 65 65 20 65 ee y ee eeeeee e
|
||||
| 3728: 65 1f 65 20 65 20 65 20 65 65 20 65 65 65 20 65 e.e e e ee eee e
|
||||
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
|
||||
| 3760: 20 65 65 20 65 65 65 20 6b 85 20 65 65 65 66 65 ee eee k. eeefe
|
||||
| 3776: 20 65 65 10 65 20 65 20 65 20 65 65 20 65 65 65 ee.e e e ee eee
|
||||
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 20 65 ee eeeee ee e e
|
||||
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
|
||||
| 3824: 03 04 00 75 71 65 20 65 65 20 65 65 65 20 65 30 ...uqe ee eee e0
|
||||
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
|
||||
| 3856: 20 65 65 20 65 65 65 20 65 1f 65 65 20 65 65 65 ee eee e.ee eee
|
||||
| 3872: 20 65 20 65 65 20 65 65 65 65 65 66 20 65 65 20 e ee eeeeef ee
|
||||
| 3888: 65 21 27 20 65 20 55 65 20 66 65 64 20 65 65 00 e!' e Ue fed ee.
|
||||
| page 5 offset 16384
|
||||
| 4064: 00 00 00 00 05 04 03 00 10 11 20 05 03 03 00 10 .......... .....
|
||||
| 4080: 11 11 05 02 03 00 00 11 11 05 01 03 00 10 09 09 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 01 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-43ed0ad79c0194.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 67.1 {
|
||||
SELECT snippet(ttt, null,null,
|
||||
EXISTS(SELECT 1 FROM ttt('e NuOT ee*e*ÏNuOY ee*') ) , '',
|
||||
(SELECT 1 FROM ttt('eu NuOT ee*e* NuOY ee*'))
|
||||
), * FROM ttt('e')
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_test 68.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 32768 pagesize 4096 filename crash-41234e232809e7.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 08 .....@ ........
|
||||
| 32: 00 00 00 02 00 00 00 01 00 00 00 09 00 00 00 04 ................
|
||||
| 96: 00 00 00 00 0d 0f c7 00 07 0d 92 00 0f 8d 0f 36 ...............6
|
||||
| 112: 0e cb 0e 6b 0e 0e 0d b6 0d 92 0d 92 00 00 00 00 ...k............
|
||||
| 3472: 00 00 22 08 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
|
||||
| 3488: 32 74 32 08 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
|
||||
| 3504: 20 74 32 28 78 29 56 07 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
|
||||
| 3520: 62 6c 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 blet1_configt1_c
|
||||
| 3536: 6f 6e 66 69 67 07 43 52 45 41 54 45 20 54 41 42 onfig.CREATE TAB
|
||||
| 3552: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
|
||||
| 3568: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
|
||||
| 3584: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 06 WITHOUT ROWID[.
|
||||
| 3600: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
|
||||
| 3616: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
|
||||
| 3632: 06 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
|
||||
| 3648: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
|
||||
| 3664: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
|
||||
| 3680: 59 2c 20 73 7a 20 42 4c 4f 42 29 5e 05 07 17 21 Y, sz BLOB)^...!
|
||||
| 3696: 21 01 81 07 74 61 62 6c 65 74 31 5f 63 6f 6e 74 !...tablet1_cont
|
||||
| 3712: 65 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 05 43 52 entt1_content.CR
|
||||
| 3728: 45 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 EATE TABLE 't1_c
|
||||
| 3744: 6f 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 ontent'(id INTEG
|
||||
| 3760: 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 ER PRIMARY KEY,
|
||||
| 3776: 63 30 2c 20 63 31 2c 20 63 32 29 69 04 07 17 19 c0, c1, c2)i....
|
||||
| 3792: 19 01 81 2d 74 61 62 6c 65 74 31 5f 69 64 78 74 ...-tablet1_idxt
|
||||
| 3808: 31 5f 69 64 78 04 43 52 45 41 54 45 20 54 41 42 1_idx.CREATE TAB
|
||||
| 3824: 4c 45 20 27 74 31 5f 69 64 78 27 28 73 65 67 69 LE 't1_idx'(segi
|
||||
| 3840: 64 2c 20 74 65 72 6d 2c 20 70 67 6e 6f 2c 20 50 d, term, pgno, P
|
||||
| 3856: 52 49 4d 41 52 59 20 4b 45 59 28 73 65 67 69 64 RIMARY KEY(segid
|
||||
| 3872: 2c 20 74 65 72 6d 29 29 20 57 49 54 48 4f 55 54 , term)) WITHOUT
|
||||
| 3888: 20 52 4f 57 49 44 55 03 07 17 1b 1b 01 81 01 74 ROWIDU........t
|
||||
| 3904: 61 62 6c 65 74 31 5f 64 61 74 61 74 31 5f 64 61 ablet1_datat1_da
|
||||
| 3920: 74 61 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 ta.CREATE TABLE
|
||||
| 3936: 27 74 31 5f 64 61 74 61 27 28 69 64 20 49 4e 54 't1_data'(id INT
|
||||
| 3952: 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 59 EGER PRIMARY KEY
|
||||
| 3968: 2c 20 62 6c 6f 63 6b 20 42 4c 4f 42 29 38 02 06 , block BLOB)8..
|
||||
| 3984: 17 11 11 08 5f 74 61 62 6c 65 74 31 74 31 43 52 ...._tablet1t1CR
|
||||
| 4000: 45 41 54 45 20 56 49 52 54 55 41 4c 20 54 41 42 EATE VIRTUAL TAB
|
||||
| 4016: 4c 45 20 74 31 20 55 53 49 4e 47 20 66 74 73 35 LE t1 USING fts5
|
||||
| 4032: 28 61 2c 62 2c 63 29 00 00 00 00 00 00 00 00 00 (a,b,c).........
|
||||
| page 3 offset 8192
|
||||
| 0: 0d 00 00 00 03 0c 94 00 0f e6 0f ef 0c 94 00 00 ................
|
||||
| 16: 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3216: 00 00 00 00 86 4a 84 80 80 80 80 01 04 00 8d 18 .....J..........
|
||||
| 3232: 00 00 03 2b 02 30 30 01 02 06 01 02 06 01 02 06 ...+.00.........
|
||||
| 3248: 1f 02 03 01 02 03 01 02 03 01 08 32 30 31 36 30 ...........20160
|
||||
| 3264: 36 30 39 01 02 07 01 02 07 01 02 07 00 01 34 01 609...........4.
|
||||
| 3280: 02 05 01 02 05 01 02 05 01 01 35 01 02 04 01 02 ..........5.....
|
||||
| 3296: 04 01 02 04 02 07 30 30 30 30 30 30 30 1c 02 04 ......0000000...
|
||||
| 3312: 01 02 04 01 02 03 f1 06 62 69 6e 62 72 79 03 06 ........binbry..
|
||||
| 3328: 01 02 02 03 06 01 02 02 03 06 01 02 01 03 16 01 ................
|
||||
| 3344: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3360: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 3376: 03 04 71 02 02 03 06 11 02 02 01 08 63 6f 6d 70 ..q.........comp
|
||||
| 3392: 69 6c 65 72 01 02 02 01 02 02 01 02 02 01 06 64 iler...........d
|
||||
| 3408: 62 73 74 61 74 07 02 03 01 02 03 01 02 03 02 04 bstat...........
|
||||
| 3424: 65 62 75 67 04 02 02 01 02 02 01 02 02 01 06 65 ebug...........e
|
||||
| 3440: 6e 61 62 6c 65 07 02 02 01 02 02 01 02 02 01 02 nable...........
|
||||
| 3456: 02 01 02 02 01 02 02 01 02 02 01 02 02 01 03 02 ................
|
||||
| 3472: 00 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 ................
|
||||
| 3488: 02 02 01 02 02 01 02 02 01 02 02 01 02 02 01 02 ................
|
||||
| 3504: 02 01 02 02 02 08 78 74 65 6e 73 69 6f 6e 1f 02 ......xtension..
|
||||
| 3520: 04 01 02 04 01 02 04 01 04 66 74 73 34 0a 02 03 .........fts4...
|
||||
| 3536: 01 02 03 01 02 03 04 01 35 0d 02 03 01 02 03 01 ........5.......
|
||||
| 3552: 02 03 01 03 66 63 63 01 02 03 01 02 03 01 02 03 ....fcc.........
|
||||
| 3568: 02 06 65 6f 70 6f 6c 79 10 02 03 01 02 03 01 02 ..eopoly........
|
||||
| 3584: 03 01 05 6a 73 6f 5e 31 13 02 03 01 02 03 01 02 ...jso^1........
|
||||
| 3600: 03 01 04 6c 6f 61 64 1f 02 03 01 02 03 01 02 03 ...load.........
|
||||
| 3616: 01 03 6d 61 78 1c 02 02 01 02 02 01 02 02 02 05 ..max...........
|
||||
| 3632: 65 6d 6f 72 79 1c 02 03 01 02 03 01 02 03 04 04 emory...........
|
||||
| 3648: 73 79 73 35 16 02 03 01 02 03 01 02 03 01 06 6e sys5...........n
|
||||
| 3664: 6f 63 61 73 65 02 06 01 02 02 03 06 01 02 02 03 ocase...........
|
||||
| 3680: 06 01 02 02 03 06 01 02 02 03 06 01 02 02 13 06 ................
|
||||
| 3696: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 3712: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3728: 02 01 04 6f 6d 69 74 1f 02 02 01 02 02 01 02 02 ...omit.........
|
||||
| 3744: 01 05 72 74 72 65 65 19 02 03 01 02 03 01 02 03 ..rtree.........
|
||||
| 3760: 04 02 69 6d 01 06 01 02 02 03 06 01 12 02 03 06 ..im............
|
||||
| 3776: 01 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 ................
|
||||
| 3792: 02 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 ................
|
||||
| 3808: 02 03 06 01 02 02 03 06 01 02 02 03 06 01 02 02 ................
|
||||
| 3824: 01 0a 74 68 72 65 61 64 73 61 66 65 22 02 02 01 ..threadsafe....
|
||||
| 3840: 02 02 01 02 02 01 04 76 74 61 62 07 02 04 01 02 .......vtab.....
|
||||
| 3856: 04 01 02 04 01 01 78 01 06 01 01 02 01 06 01 01 ......x.........
|
||||
| 3872: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3888: 01 06 01 01 02 01 06 01 01 02 01 05 f1 01 02 01 ................
|
||||
| 3904: 06 01 01 02 01 06 01 5b 02 01 06 01 01 02 01 06 .......[........
|
||||
| 3920: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 3936: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 3952: 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 ................
|
||||
| 3968: 01 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 ................
|
||||
| 3984: 06 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 ................
|
||||
| 4000: 01 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 ................
|
||||
| 4016: 01 02 01 06 01 01 02 01 06 01 01 02 01 06 01 01 ................
|
||||
| 4032: 02 01 06 01 01 02 01 06 01 01 02 04 15 13 0c 0c ................
|
||||
| 4048: 12 44 13 11 0f 47 13 0f 0c 0e 11 10 0f 0e 10 0f .D...G..........
|
||||
| 4064: 44 0f 10 40 15 0f 07 01 03 00 14 24 5a 24 24 0f D..@.......$Z$$.
|
||||
| 4080: 0a 03 00 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 4 offset 12288
|
||||
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 00 00 00 00 00 00 05 04 09 0b 01 02 ................
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 24 0c 0a 00 0f d8 0f af 0f 86 0f 74 ....$..........t
|
||||
| 16: 0f 61 0f 4e 0f 2f 0f 0f 0e ef 0e d7 0e be 0e a5 .a.N./..........
|
||||
| 32: 0e 8d 0e 74 0e 5b 0e 40 0e 24 0e 08 0d ef 0d d5 ...t.[.@.$......
|
||||
| 48: 0d bb 0d a0 0d 84 0d 68 0d 4f 0d 35 0d 1b 0c fb .......h.O.5....
|
||||
| 64: 0c da 0c b9 0c 99 0c 78 0c 57 0c 3e 0c 24 0c 0a .......x.W.>.$..
|
||||
| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
|
||||
| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
|
||||
| 3104: 4f 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 OARY.#..%..THREA
|
||||
| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
|
||||
| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 41 46 45 3d ..%..THREADSAFE=
|
||||
| 3152: 30 58 52 54 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRTRIM.!..3..OM
|
||||
| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
|
||||
| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
|
||||
| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
|
||||
| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
|
||||
| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
|
||||
| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
|
||||
| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
|
||||
| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
|
||||
| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
|
||||
| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
|
||||
| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
|
||||
| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
|
||||
| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
|
||||
| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
|
||||
| 3392: 4c 45 20 52 54 52 46 45 58 4e 4f 43 41 53 45 17 LE RTRFEXNOCASE.
|
||||
| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
|
||||
| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
|
||||
| 3440: 49 41 42 4c 45 20 4d 45 4d 53 59 53 35 58 42 49 IABLE MEMSYS5XBI
|
||||
| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
|
||||
| 3472: 45 20 4d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 E MEMSYS5XNOCASE
|
||||
| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME
|
||||
| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
|
||||
| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
|
||||
| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
|
||||
| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
|
||||
| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
|
||||
| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
|
||||
| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 57 42 49 NABLE GEOPOLYWBI
|
||||
| 3616: 4e 41 52 59 1a 11 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
|
||||
| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 42 41 53 45 E GEOPOLYXNOBASE
|
||||
| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE
|
||||
| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....#
|
||||
| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
|
||||
| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
|
||||
| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
|
||||
| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
|
||||
| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
|
||||
| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
|
||||
| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
|
||||
| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
|
||||
| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
|
||||
| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
|
||||
| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
|
||||
| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
|
||||
| 3872: 54 41 54 20 56 54 41 42 58 4e 4f 43 41 53 45 1d TAT VTABXNOCASE.
|
||||
| 3888: 07 05 00 31 0f 17 b7 4e 41 42 4c 45 20 44 42 53 ...1...NABLE DBS
|
||||
| 3904: 54 41 54 20 66 54 41 42 58 52 54 52 49 4d 11 06 TAT fTABXRTRIM..
|
||||
| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
|
||||
| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
|
||||
| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
|
||||
| 3968: 58 62 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XbTRIM'...C..COM
|
||||
| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
|
||||
| 4000: 32 30 31 36 30 36 30 39 52 02 4a 4e 41 52 59 27 20160609R.JNARY'
|
||||
| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3d 67 ...C..COMPILER=g
|
||||
| 4032: 63 63 2d 35 2e 34 2e 30 20 32 30 31 36 30 36 30 cc-5.4.0 2016060
|
||||
| 4048: 39 58 4e 4f 43 41 53 45 26 01 05 00 43 0f 17 43 9XNOCASE&...C..C
|
||||
| 4064: 4f 4d 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e OMPILER=gcc-5.4.
|
||||
| 4080: 30 20 32 30 31 36 30 36 30 39 58 52 54 52 49 4d 0 20160609XRTRIM
|
||||
| page 6 offset 20480
|
||||
| 0: 0d 00 00 00 24 0e e0 00 0f f8 0f f0 0f e8 0f e0 ....$...........
|
||||
| 16: 0f d8 0f d0 0f c8 0f c0 0f b8 0f b0 0f a8 0f a0 ................
|
||||
| 32: 0f 98 0f 90 0f 88 0f 80 0f 78 0f 70 0f 68 0f 60 .........x.p.h.`
|
||||
| 48: 0f 58 0f 50 0f 48 0f 40 0f 38 0f 30 0f 28 0f 20 .X.P.H.@.8.0.(.
|
||||
| 64: 0f 18 0f 10 0f 08 0f 00 0e f8 0e f0 0e e8 0e e0 ................
|
||||
| 3808: 06 24 03 00 12 02 01 01 06 23 03 00 12 02 01 01 .$.......#......
|
||||
| 3824: 06 22 03 00 12 02 01 01 06 21 03 00 12 03 01 01 .........!......
|
||||
| 3840: 06 20 03 00 12 03 01 01 06 1f 03 00 12 03 01 01 . ..............
|
||||
| 3856: 06 1e 03 00 12 03 01 01 06 1d 03 00 12 03 01 01 ................
|
||||
| 3872: 06 1c 03 00 12 03 01 01 06 1b 03 00 12 02 01 01 ................
|
||||
| 3888: 06 1a 03 00 12 02 01 01 06 19 03 00 12 02 01 01 ................
|
||||
| 3904: 06 18 03 00 12 02 01 01 06 17 03 00 12 02 01 01 ................
|
||||
| 3920: 06 16 03 00 12 02 01 01 06 15 03 00 12 02 01 01 ................
|
||||
| 3936: 06 14 03 00 12 02 01 01 06 13 03 00 12 02 01 01 ................
|
||||
| 3952: 06 12 03 00 12 02 01 01 06 11 03 00 12 02 01 01 ................
|
||||
| 3968: 06 10 03 00 12 02 01 01 06 0f 03 00 12 02 01 01 ................
|
||||
| 3984: 06 0e 03 00 12 02 01 01 06 0d 03 00 12 02 01 01 ................
|
||||
| 4000: 06 0c 03 00 12 02 01 01 06 0b 03 00 12 02 01 01 ................
|
||||
| 4016: 06 0a 03 00 12 02 01 01 06 09 03 00 12 03 01 01 ................
|
||||
| 4032: 06 08 03 00 12 03 01 01 06 07 03 00 12 03 01 01 ................
|
||||
| 4048: 06 06 03 00 12 01 01 01 06 05 03 00 12 01 01 01 ................
|
||||
| 4064: 06 04 03 00 12 01 01 01 06 03 03 00 12 06 01 01 ................
|
||||
| 4080: 06 02 03 00 12 06 01 01 06 01 03 00 12 06 01 01 ................
|
||||
| page 7 offset 24576
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| page 8 offset 28672
|
||||
| 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................
|
||||
| 4048: 00 00 00 00 00 00 11 04 02 2b 69 6e 74 65 67 72 .........+integr
|
||||
| 4064: 69 74 79 2d 63 68 65 63 6b 09 02 02 1b 72 65 62 ity-check....reb
|
||||
| 4080: 75 69 6c 64 0a 01 02 1d 6f 70 74 69 5d 69 71 a5 uild....opti]iq.
|
||||
| end crash-41234e232809e7.db
|
||||
.testctrl prng_seed 1 db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 68.1 {
|
||||
PRAGMA reverse_unordered_selects=ON;
|
||||
INSERT INTO t1(t1) SELECT x FROM t2;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
|
||||
@@ -59,10 +59,27 @@ do_catchsql_test 2.1 {
|
||||
SELECT fts5_expr()
|
||||
} {1 {wrong number of arguments to function fts5_expr}}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
do_catchsql_test 2.2 {
|
||||
SELECT fts5_expr_tcl()
|
||||
} {1 {wrong number of arguments to function fts5_expr_tcl}}
|
||||
|
||||
do_catchsql_test 2.3 {
|
||||
SELECT fts5_expr('')
|
||||
} {1 {fts5: syntax error near ""}}
|
||||
|
||||
do_catchsql_test 2.4 {
|
||||
SELECT fts5_expr(NULL)
|
||||
} {1 {fts5: syntax error near ""}}
|
||||
|
||||
do_catchsql_test 2.5 {
|
||||
SELECT fts5_expr(NULL, NULL)
|
||||
} {1 {parse error in ""}}
|
||||
|
||||
for {set i 0} {$i < 255} {incr i} {
|
||||
do_test 2.6.$i {
|
||||
lindex [catchsql {sELECT fts5_expr(NULL, char($i));}] 0
|
||||
} 1
|
||||
}
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
|
||||
|
||||
@@ -210,4 +210,76 @@ foreach {tn pgsz} {
|
||||
} {1000}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 7.0 {
|
||||
PRAGMA encoding = 'UTF-16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
INSERT INTO vt0 VALUES (x'46f0');
|
||||
SELECT quote(c0) FROM vt0;
|
||||
} {X'46F0'}
|
||||
do_execsql_test 7.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 7.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('rebuild');
|
||||
}
|
||||
do_execsql_test 7.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 7.4 {
|
||||
UPDATE vt0 SET c0='';
|
||||
}
|
||||
do_execsql_test 7.5 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket 7a458c2a5f4
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
PRAGMA locking_mode = EXCLUSIVE;
|
||||
PRAGMA journal_mode = PERSIST;
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
} {exclusive persist}
|
||||
do_execsql_test 8.1 {
|
||||
PRAGMA data_version
|
||||
} {1}
|
||||
do_execsql_test 8.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
PRAGMA data_version;
|
||||
} {1}
|
||||
do_execsql_test 8.1 {
|
||||
INSERT INTO vt0(vt0, rank) VALUES('usermerge', 2);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [771fe617]
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
PRAGMA encoding = 'UTF16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
}
|
||||
|
||||
#explain_i { SELECT quote(SUBSTR(x'37', 0)); }
|
||||
#execsql { PRAGMA vdbe_trace = 1 }
|
||||
do_execsql_test 9.1.1 {
|
||||
SELECT quote(SUBSTR(x'37', 0));
|
||||
} {X'37'}
|
||||
do_execsql_test 9.1.2 {
|
||||
SELECT quote(x'37');
|
||||
} {X'37'}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 9.2 {
|
||||
INSERT INTO vt0 VALUES (SUBSTR(x'37', 0));
|
||||
-- INSERT INTO vt0 VALUES (x'37');
|
||||
}
|
||||
do_execsql_test 9.3 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -500,14 +500,18 @@ do_execsql_test 15.0 {
|
||||
INSERT INTO t1 VALUES('c', 'd');
|
||||
}
|
||||
|
||||
if {$tcl_platform(byteOrder)=="littleEndian"} {
|
||||
set res {X'02000000'}
|
||||
} else {
|
||||
set res {X'00000002'}
|
||||
}
|
||||
do_execsql_test 15.1 {
|
||||
SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
|
||||
} {X'02000000'}
|
||||
|
||||
} $res
|
||||
do_execsql_test 15.2 {
|
||||
DELETE FROM t1_content WHERE rowid=1;
|
||||
SELECT quote(matchinfo(t1, 'n')) FROM t1 LIMIT 1;
|
||||
} {X'02000000'}
|
||||
} $res
|
||||
|
||||
fts5_aux_test_functions db
|
||||
do_execsql_test 15.3 {
|
||||
@@ -517,4 +521,3 @@ do_execsql_test 15.3 {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -218,6 +218,110 @@ do_execsql_test 7.2 {
|
||||
SELECT rowid FROM t1 WHERE rowid=2 AND t1 = 'hello';
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 8.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0, tokenize = "ascii", prefix = 1);
|
||||
INSERT INTO vt0(c0) VALUES (x'd1');
|
||||
}
|
||||
|
||||
do_execsql_test 8.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE VIRTUAL TABLE t1 using FTS5(mailcontent);
|
||||
insert into t1(rowid, mailcontent) values
|
||||
(-4764623217061966105, 'we are going to upgrade'),
|
||||
(8324454597464624651, 'we are going to upgrade');
|
||||
}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
do_execsql_test 9.2 {
|
||||
SELECT rowid FROM t1('upgrade');
|
||||
} {
|
||||
-4764623217061966105 8324454597464624651
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 10.0 {
|
||||
CREATE VIRTUAL TABLE vt1 USING fts5(c1, c2, prefix = 1, tokenize = "ascii");
|
||||
INSERT INTO vt1 VALUES (x'e4', '䔬');
|
||||
}
|
||||
|
||||
do_execsql_test 10.1 {
|
||||
SELECT quote(CAST(c1 AS blob)), quote(CAST(c2 AS blob)) FROM vt1
|
||||
} {X'E4' X'E494AC'}
|
||||
|
||||
do_execsql_test 10.2 {
|
||||
INSERT INTO vt1(vt1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(
|
||||
c0, prefix = 71, tokenize = "porter ascii", prefix = 9
|
||||
);
|
||||
} {}
|
||||
do_execsql_test 11.1 {
|
||||
BEGIN;
|
||||
INSERT INTO vt0(c0) VALUES (x'e8');
|
||||
}
|
||||
do_execsql_test 11.2 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [752fdbf6]
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.0 {
|
||||
PRAGMA encoding = 'UTF-16';
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0, c1);
|
||||
INSERT INTO vt0(vt0, rank) VALUES('pgsz', '37');
|
||||
INSERT INTO vt0(c0, c1) VALUES (0.66077, 1957391816);
|
||||
}
|
||||
do_execsql_test 11.1 {
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [7c0e06b16]
|
||||
#
|
||||
do_execsql_test 12.0 {
|
||||
CREATE TABLE t1(a, b, rank);
|
||||
INSERT INTO t1 VALUES('a', 'hello', '');
|
||||
INSERT INTO t1 VALUES('b', 'world', '');
|
||||
|
||||
CREATE VIRTUAL TABLE ft USING fts5(a);
|
||||
INSERT INTO ft VALUES('b');
|
||||
INSERT INTO ft VALUES('y');
|
||||
|
||||
CREATE TABLE t2(x, y, ft);
|
||||
INSERT INTO t2 VALUES(1, 2, 'x');
|
||||
INSERT INTO t2 VALUES(3, 4, 'b');
|
||||
}
|
||||
|
||||
do_execsql_test 12.1 {
|
||||
SELECT * FROM t1 NATURAL JOIN ft WHERE ft MATCH('b')
|
||||
} {b world {}}
|
||||
do_execsql_test 12.2 {
|
||||
SELECT * FROM ft NATURAL JOIN t1 WHERE ft MATCH('b')
|
||||
} {b world {}}
|
||||
do_execsql_test 12.3 {
|
||||
SELECT * FROM t2 JOIN ft USING (ft)
|
||||
} {3 4 b b}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# 2019 Dec 26
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5savepoint
|
||||
|
||||
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE ft USING fts5(c);
|
||||
BEGIN;
|
||||
SAVEPOINT one;
|
||||
INSERT INTO ft VALUES('a');
|
||||
SAVEPOINT two;
|
||||
INSERT INTO ft VALUES('b');
|
||||
RELEASE two;
|
||||
SAVEPOINT four;
|
||||
INSERT INTO ft VALUES('c');
|
||||
RELEASE four;
|
||||
SAVEPOINT three;
|
||||
INSERT INTO ft VALUES('d');
|
||||
ROLLBACK TO three;
|
||||
COMMIT;
|
||||
SELECT * FROM ft
|
||||
} {a b c}
|
||||
|
||||
reset_db
|
||||
do_catchsql_test 2.0 {
|
||||
CREATE VIRTUAL TABLE ft1 USING fts5(c);
|
||||
CREATE VIRTUAL TABLE ft2 USING fts5(c);
|
||||
DROP TABLE ft2_idx;
|
||||
BEGIN;
|
||||
INSERT INTO ft2 VALUES('a');
|
||||
INSERT INTO ft1 VALUES('a');
|
||||
SAVEPOINT two;
|
||||
INSERT INTO ft1 VALUES('b');
|
||||
COMMIT;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
reset_db
|
||||
ifcapable fts3 {
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE vt0 USING fts5(c0);
|
||||
CREATE VIRTUAL TABLE vt1 USING fts4(c0);
|
||||
INSERT INTO vt1(c0) VALUES(0);
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
BEGIN;
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
INSERT INTO vt1(c0) VALUES (0), (0);
|
||||
UPDATE vt0 SET c0 = 0;
|
||||
INSERT INTO vt1(c0) VALUES (0);
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
INSERT INTO vt1(vt1) VALUES('automerge=1');
|
||||
UPDATE vt1 SET c0 = 0;
|
||||
}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
DROP TABLE vt1;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SAVEPOINT x;
|
||||
INSERT INTO vt0 VALUES('x');
|
||||
COMMIT;
|
||||
INSERT INTO vt0(vt0) VALUES('integrity-check');
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -542,5 +542,16 @@ do_execsql_test 10.7.3 {
|
||||
SELECT * FROM t2 WHERE term=?;
|
||||
}
|
||||
|
||||
finish_test
|
||||
# 2020-02-16 Detect recursively define fts5vocab() tables.
|
||||
# Error found by dbsqlfuzz.
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 11.100 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts5vocab(rowid , 'col');
|
||||
CREATE VIRTUAL TABLE rowid USING fts5vocab(rowid , 'instance');
|
||||
} {}
|
||||
do_catchsql_test 11.110 {
|
||||
SELECT rowid+1,rowid, * FROM t3 WHERE null>rowid ;
|
||||
} {1 {SQL logic error}}
|
||||
|
||||
finish_test
|
||||
|
||||
+17
-16
@@ -143,7 +143,7 @@ static int icuLikeCompare(
|
||||
** 3. uPattern is an unescaped escape character, or
|
||||
** 4. uPattern is to be handled as an ordinary character
|
||||
*/
|
||||
if( !prevEscape && uPattern==MATCH_ALL ){
|
||||
if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
||||
/* Case 1. */
|
||||
uint8_t c;
|
||||
|
||||
@@ -169,12 +169,12 @@ static int icuLikeCompare(
|
||||
}
|
||||
return 0;
|
||||
|
||||
}else if( !prevEscape && uPattern==MATCH_ONE ){
|
||||
}else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
||||
/* Case 2. */
|
||||
if( *zString==0 ) return 0;
|
||||
SQLITE_ICU_SKIP_UTF8(zString);
|
||||
|
||||
}else if( !prevEscape && uPattern==(uint32_t)uEsc){
|
||||
}else if( uPattern==(uint32_t)uEsc && !prevEscape ){
|
||||
/* Case 3. */
|
||||
prevEscape = 1;
|
||||
|
||||
@@ -499,26 +499,27 @@ static void icuLoadCollation(
|
||||
** Register the ICU extension functions with database db.
|
||||
*/
|
||||
int sqlite3IcuInit(sqlite3 *db){
|
||||
# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
|
||||
static const struct IcuScalar {
|
||||
const char *zName; /* Function name */
|
||||
unsigned char nArg; /* Number of arguments */
|
||||
unsigned short enc; /* Optimal text encoding */
|
||||
unsigned int enc; /* Optimal text encoding */
|
||||
unsigned char iContext; /* sqlite3_user_data() context */
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
|
||||
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
|
||||
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
{"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
||||
{"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
||||
{"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
||||
};
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
@@ -900,6 +900,7 @@ static int amatchConnect(
|
||||
rc = amatchLoadRules(db, pNew, pzErr);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(word,distance,language,"
|
||||
"command HIDDEN,nword HIDDEN)"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
** rootpage INT, -- The root page of the btree
|
||||
** sql TEXT, -- SQL for this btree - from sqlite_master
|
||||
** hasRowid BOOLEAN, -- True if the btree has a rowid
|
||||
** nEntry INT, -- Estimated number of enteries
|
||||
** nEntry INT, -- Estimated number of entries
|
||||
** nPage INT, -- Estimated number of pages
|
||||
** depth INT, -- Depth of the btree
|
||||
** szPage INT, -- Size of each page in bytes
|
||||
|
||||
@@ -118,6 +118,7 @@ static int completionConnect(
|
||||
#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
|
||||
#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
|
||||
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x("
|
||||
" candidate TEXT,"
|
||||
|
||||
+6
-4
@@ -119,11 +119,13 @@ int sqlite3_compress_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
|
||||
compressFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "compress", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS,
|
||||
0, compressFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0,
|
||||
uncompressFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "uncompress", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, uncompressFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -632,6 +632,15 @@ static int csvtabConnect(
|
||||
for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){
|
||||
sqlite3_free(azPValue[i]);
|
||||
}
|
||||
/* Rationale for DIRECTONLY:
|
||||
** An attacker who controls a database schema could use this vtab
|
||||
** to exfiltrate sensitive data from other files in the filesystem.
|
||||
** And, recommended practice is to put all CSV virtual tables in the
|
||||
** TEMP namespace, so they should still be usable from within TEMP
|
||||
** views, so there shouldn't be a serious loss of functionality by
|
||||
** prohibiting the use of this vtab from persistent triggers and views.
|
||||
*/
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
return SQLITE_OK;
|
||||
|
||||
csvtab_connect_oom:
|
||||
|
||||
+4
-2
@@ -113,10 +113,12 @@ int sqlite3_eval_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "eval", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "eval", 2,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+7
-2
@@ -394,6 +394,7 @@ static int writeFile(
|
||||
|
||||
if( mtime>=0 ){
|
||||
#if defined(_WIN32)
|
||||
#if !SQLITE_OS_WINRT
|
||||
/* Windows */
|
||||
FILETIME lastAccess;
|
||||
FILETIME lastWrite;
|
||||
@@ -424,6 +425,7 @@ static int writeFile(
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
|
||||
/* Recent unix */
|
||||
struct timespec times[2];
|
||||
@@ -585,6 +587,7 @@ static int fsdirConnect(
|
||||
pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
}
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
return rc;
|
||||
@@ -978,10 +981,12 @@ int sqlite3_fileio_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "readfile", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
readfileFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "writefile", -1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
writefileFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
@@ -822,6 +822,7 @@ static int deltaparsevtabConnect(
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1070,17 +1071,18 @@ int sqlite3_fossildelta_init(
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
static const int enc = SQLITE_UTF8|SQLITE_INNOCUOUS;
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "delta_create", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "delta_create", 2, enc, 0,
|
||||
deltaCreateFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "delta_apply", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "delta_apply", 2, enc, 0,
|
||||
deltaApplyFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "delta_output_size", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "delta_output_size", 1, enc, 0,
|
||||
deltaOutputSizeFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
@@ -540,6 +540,8 @@ static int fuzzerConnect(
|
||||
if( rc!=SQLITE_OK ){
|
||||
fuzzerDisconnect((sqlite3_vtab *)pNew);
|
||||
pNew = 0;
|
||||
}else{
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -121,10 +121,12 @@ int sqlite3_ieee_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "ieee754", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
ieee754func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "ieee754", 2,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
ieee754func, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+95
-20
@@ -522,6 +522,37 @@ static void jsonReturnJson(
|
||||
sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
|
||||
}
|
||||
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
** This routine only works if h really is a valid hexadecimal
|
||||
** character: 0..9a..fA..F
|
||||
*/
|
||||
static u8 jsonHexToInt(int h){
|
||||
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
|
||||
#ifdef SQLITE_EBCDIC
|
||||
h += 9*(1&~(h>>4));
|
||||
#else
|
||||
h += 9*(1&(h>>6));
|
||||
#endif
|
||||
return (u8)(h & 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 4-byte hex string into an integer
|
||||
*/
|
||||
static u32 jsonHexToInt4(const char *z){
|
||||
u32 v;
|
||||
assert( safe_isxdigit(z[0]) );
|
||||
assert( safe_isxdigit(z[1]) );
|
||||
assert( safe_isxdigit(z[2]) );
|
||||
assert( safe_isxdigit(z[3]) );
|
||||
v = (jsonHexToInt(z[0])<<12)
|
||||
+ (jsonHexToInt(z[1])<<8)
|
||||
+ (jsonHexToInt(z[2])<<4)
|
||||
+ jsonHexToInt(z[3]);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make the JsonNode the return value of the function.
|
||||
*/
|
||||
@@ -615,15 +646,8 @@ static void jsonReturn(
|
||||
}else{
|
||||
c = z[++i];
|
||||
if( c=='u' ){
|
||||
u32 v = 0, k;
|
||||
for(k=0; k<4; i++, k++){
|
||||
assert( i<n-2 );
|
||||
c = z[i+1];
|
||||
assert( safe_isxdigit(c) );
|
||||
if( c<='9' ) v = v*16 + c - '0';
|
||||
else if( c<='F' ) v = v*16 + c - 'A' + 10;
|
||||
else v = v*16 + c - 'a' + 10;
|
||||
}
|
||||
u32 v = jsonHexToInt4(z+i+1);
|
||||
i += 4;
|
||||
if( v==0 ) break;
|
||||
if( v<=0x7f ){
|
||||
zOut[j++] = (char)v;
|
||||
@@ -631,9 +655,25 @@ static void jsonReturn(
|
||||
zOut[j++] = (char)(0xc0 | (v>>6));
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}else{
|
||||
zOut[j++] = (char)(0xe0 | (v>>12));
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
u32 vlo;
|
||||
if( (v&0xfc00)==0xd800
|
||||
&& i<n-6
|
||||
&& z[i+1]=='\\'
|
||||
&& z[i+2]=='u'
|
||||
&& ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
|
||||
){
|
||||
/* We have a surrogate pair */
|
||||
v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
|
||||
i += 6;
|
||||
zOut[j++] = 0xf0 | (v>>18);
|
||||
zOut[j++] = 0x80 | ((v>>12)&0x3f);
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}else{
|
||||
zOut[j++] = 0xe0 | (v>>12);
|
||||
zOut[j++] = 0x80 | ((v>>6)&0x3f);
|
||||
zOut[j++] = 0x80 | (v&0x3f);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( c=='b' ){
|
||||
@@ -1136,18 +1176,49 @@ static JsonNode *jsonLookupStep(
|
||||
}
|
||||
return pNode;
|
||||
}
|
||||
}else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
}else if( zPath[0]=='[' ){
|
||||
i = 0;
|
||||
j = 1;
|
||||
while( safe_isdigit(zPath[j]) ){
|
||||
i = i*10 + zPath[j] - '0';
|
||||
j++;
|
||||
}
|
||||
if( zPath[j]!=']' ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
if( j<2 || zPath[j]!=']' ){
|
||||
if( zPath[1]=='#' ){
|
||||
JsonNode *pBase = pRoot;
|
||||
int iBase = iRoot;
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
for(;;){
|
||||
while( j<=pBase->n ){
|
||||
if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
|
||||
j += jsonNodeSize(&pBase[j]);
|
||||
}
|
||||
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
|
||||
iBase += pBase->u.iAppend;
|
||||
pBase = &pParse->aNode[iBase];
|
||||
j = 1;
|
||||
}
|
||||
j = 2;
|
||||
if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
|
||||
unsigned int x = 0;
|
||||
j = 3;
|
||||
do{
|
||||
x = x*10 + zPath[j] - '0';
|
||||
j++;
|
||||
}while( safe_isdigit(zPath[j]) );
|
||||
if( x>i ) return 0;
|
||||
i -= x;
|
||||
}
|
||||
if( zPath[j]!=']' ){
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
*pzErr = zPath;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if( pRoot->eType!=JSON_ARRAY ) return 0;
|
||||
zPath += j + 1;
|
||||
j = 1;
|
||||
for(;;){
|
||||
@@ -2020,6 +2091,7 @@ static int jsonEachConnect(
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -2510,16 +2582,19 @@ int sqlite3Json1Init(sqlite3 *db){
|
||||
{ "json_tree", &jsonTreeModule },
|
||||
};
|
||||
#endif
|
||||
static const int enc =
|
||||
SQLITE_UTF8 |
|
||||
SQLITE_DETERMINISTIC |
|
||||
SQLITE_INNOCUOUS;
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,
|
||||
(void*)&aFunc[i].flag,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
|
||||
SQLITE_SUBTYPE | SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
|
||||
SQLITE_SUBTYPE | enc, 0,
|
||||
aAgg[i].xStep, aAgg[i].xFinal,
|
||||
aAgg[i].xValue, jsonGroupInverse, 0);
|
||||
}
|
||||
|
||||
+6
-3
@@ -297,14 +297,17 @@ int sqlite3_nextchar_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 3,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 4,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "next_char", 5,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
nextCharFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
** 2020-01-08
|
||||
**
|
||||
** 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 SQLite extension implements a noop() function used for testing.
|
||||
**
|
||||
** Variants:
|
||||
**
|
||||
** noop(X) The default. Deterministic.
|
||||
** noop_i(X) Deterministic and innocuous.
|
||||
** noop_do(X) Deterministic and direct-only.
|
||||
** noop_nd(X) Non-deterministic.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Implementation of the noop() function.
|
||||
**
|
||||
** The function returns its argument, unchanged.
|
||||
*/
|
||||
static void noopfunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
sqlite3_result_value(context, argv[0]);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_noop_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "noop", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_i", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_do", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_DIRECTONLY,
|
||||
0, noopfunc, 0, 0);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3_create_function(db, "noop_nd", 1,
|
||||
SQLITE_UTF8,
|
||||
0, noopfunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
@@ -213,7 +213,8 @@ int sqlite3_percentile_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "percentile", 2,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
0, percentStep, percentFinal);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ static int prefixesConnect(
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+3
-3
@@ -156,7 +156,7 @@ static unsigned re_next_char(ReInput *p){
|
||||
&& (p->z[p->i+1]&0xc0)==0x80 ){
|
||||
c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f);
|
||||
p->i += 2;
|
||||
if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
|
||||
if( c<=0x7ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd;
|
||||
}else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80
|
||||
&& (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){
|
||||
c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6)
|
||||
@@ -754,7 +754,7 @@ int sqlite3_regexp_init(
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0,
|
||||
re_sql_func, 0, 0);
|
||||
rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8|SQLITE_INNOCUOUS,
|
||||
0, re_sql_func, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+3
-2
@@ -105,8 +105,9 @@ int sqlite3_rot_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "rot13", 1, SQLITE_UTF8, 0,
|
||||
rot13func, 0, 0);
|
||||
rc = sqlite3_create_function(db, "rot13", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, rot13func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_collation(db, "rot13", SQLITE_UTF8, 0, rot13CollFunc);
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ static int seriesConnect(
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
+5
-19
@@ -39,25 +39,9 @@ struct SHA1Context {
|
||||
unsigned char buffer[64];
|
||||
};
|
||||
|
||||
|
||||
#if __GNUC__ && (defined(__i386__) || defined(__x86_64__))
|
||||
/*
|
||||
* GCC by itself only generates left rotates. Use right rotates if
|
||||
* possible to be kinder to dinky implementations with iterative rotate
|
||||
* instructions.
|
||||
*/
|
||||
#define SHA_ROT(op, x, k) \
|
||||
({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; })
|
||||
#define rol(x,k) SHA_ROT("roll", x, k)
|
||||
#define ror(x,k) SHA_ROT("rorl", x, k)
|
||||
|
||||
#else
|
||||
/* Generic C equivalent */
|
||||
#define SHA_ROT(x,l,r) ((x) << (l) | (x) >> (r))
|
||||
#define rol(x,k) SHA_ROT(x,k,32-(k))
|
||||
#define ror(x,k) SHA_ROT(x,32-(k),k)
|
||||
#endif
|
||||
|
||||
|
||||
#define blk0le(i) (block[i] = (ror(block[i],8)&0xFF00FF00) \
|
||||
|(rol(block[i],8)&0x00FF00FF))
|
||||
@@ -397,10 +381,12 @@ int sqlite3_sha_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha1", 1, SQLITE_UTF8, 0,
|
||||
sha1Func, 0, 0);
|
||||
rc = sqlite3_create_function(db, "sha1", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, sha1Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "sha1_query", 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
|
||||
sha1QueryFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+12
-8
@@ -696,19 +696,23 @@ int sqlite3_shathree_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sha3", 1, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
rc = sqlite3_create_function(db, "sha3", 1,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, sha3Func, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0,
|
||||
sha3Func, 0, 0);
|
||||
rc = sqlite3_create_function(db, "sha3", 2,
|
||||
SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
|
||||
0, sha3Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "sha3_query", 1,
|
||||
SQLITE_UTF8 | SQLITE_DIRECTONLY,
|
||||
0, sha3QueryFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0,
|
||||
sha3QueryFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "sha3_query", 2,
|
||||
SQLITE_UTF8 | SQLITE_DIRECTONLY,
|
||||
0, sha3QueryFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2069,6 +2069,7 @@ static int spellfix1Init(
|
||||
if( pNew->zTableName==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(word,rank,distance,langid, "
|
||||
"score, matchlen, phonehash HIDDEN, "
|
||||
|
||||
+4
-2
@@ -111,10 +111,12 @@ int sqlite3_sqlar_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "sqlar_compress", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
sqlarCompressFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
|
||||
rc = sqlite3_create_function(db, "sqlar_uncompress", 2,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
sqlarUncompressFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
+6
-4
@@ -502,11 +502,13 @@ int sqlite3_totype_init(
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "tointeger", 1, SQLITE_UTF8, 0,
|
||||
tointegerFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "tointeger", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
|
||||
tointegerFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0,
|
||||
torealFunc, 0, 0);
|
||||
rc = sqlite3_create_function(db, "toreal", 1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS, 0,
|
||||
torealFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
** 2020-04-14
|
||||
**
|
||||
** 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 SQLite extension implements the UINT collating sequence.
|
||||
**
|
||||
** UINT works like BINARY for text, except that embedded strings
|
||||
** of digits compare in numeric order.
|
||||
**
|
||||
** * Leading zeros are handled properly, in the sense that
|
||||
** they do not mess of the maginitude comparison of embedded
|
||||
** strings of digits. "x00123y" is equal to "x123y".
|
||||
**
|
||||
** * Only unsigned integers are recognized. Plus and minus
|
||||
** signs are ignored. Decimal points and exponential notation
|
||||
** are ignored.
|
||||
**
|
||||
** * Embedded integers can be of arbitrary length. Comparison
|
||||
** is *not* limited integers that can be expressed as a
|
||||
** 64-bit machine integer.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Compare text in lexicographic order, except strings of digits
|
||||
** compare in numeric order.
|
||||
*/
|
||||
static int uintCollFunc(
|
||||
void *notUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
const unsigned char *zA = (const unsigned char*)pKey1;
|
||||
const unsigned char *zB = (const unsigned char*)pKey2;
|
||||
int i=0, j=0, x;
|
||||
while( i<nKey1 && j<nKey2 ){
|
||||
x = zA[i] - zB[j];
|
||||
if( isdigit(zA[i]) ){
|
||||
int k;
|
||||
if( !isdigit(zB[j]) ) return x;
|
||||
while( i<nKey1 && zA[i]=='0' ){ i++; }
|
||||
while( j<nKey2 && zB[j]=='0' ){ j++; }
|
||||
k = 0;
|
||||
while( i+k<nKey1 && isdigit(zA[i+k])
|
||||
&& j+k<nKey2 && isdigit(zB[j+k]) ){
|
||||
k++;
|
||||
}
|
||||
if( i+k<nKey1 && isdigit(zA[i+k]) ){
|
||||
return +1;
|
||||
}else if( j+k<nKey2 && isdigit(zB[j+k]) ){
|
||||
return -1;
|
||||
}else{
|
||||
x = memcmp(zA+i, zB+j, k);
|
||||
if( x ) return x;
|
||||
i += k;
|
||||
j += k;
|
||||
}
|
||||
}else if( x ){
|
||||
return x;
|
||||
}else{
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return (nKey1 - i) - (nKey2 - j);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_uint_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
** 2020-01-11
|
||||
**
|
||||
** 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 SQLite extension implements various SQL functions used to access
|
||||
** the following SQLite C-language APIs:
|
||||
**
|
||||
** sqlite3_uri_parameter()
|
||||
** sqlite3_uri_boolean()
|
||||
** sqlite3_uri_int64()
|
||||
** sqlite3_uri_key()
|
||||
** sqlite3_filename_database()
|
||||
** sqlite3_filename_journal()
|
||||
** sqlite3_filename_wal()
|
||||
** sqlite3_db_filename()
|
||||
**
|
||||
** These SQL functions are for testing and demonstration purposes only.
|
||||
**
|
||||
**
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_db_filename(SCHEMA)
|
||||
**
|
||||
** Return the filename corresponding to SCHEMA.
|
||||
*/
|
||||
static void func_db_filename(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
sqlite3_result_text(context, zFile, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_uri_parameter(SCHEMA,NAME)
|
||||
**
|
||||
** Return the value of the NAME query parameter to the database for SCHEMA
|
||||
*/
|
||||
static void func_uri_parameter(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zName = (const char*)sqlite3_value_text(argv[1]);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
const char *zRes = sqlite3_uri_parameter(zFile, zName);
|
||||
sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_uri_boolean(SCHEMA,NAME,DEFAULT)
|
||||
**
|
||||
** Return the boolean value of the NAME query parameter to
|
||||
** the database for SCHEMA
|
||||
*/
|
||||
static void func_uri_boolean(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zName = (const char*)sqlite3_value_text(argv[1]);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
int iDflt = sqlite3_value_int(argv[2]);
|
||||
int iRes = sqlite3_uri_boolean(zFile, zName, iDflt);
|
||||
sqlite3_result_int(context, iRes);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_uri_key(SCHEMA,N)
|
||||
**
|
||||
** Return the name of the Nth query parameter
|
||||
*/
|
||||
static void func_uri_key(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
int N = sqlite3_value_int(argv[1]);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
const char *zRes = sqlite3_uri_key(zFile, N);
|
||||
sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_uri_int64(SCHEMA,NAME,DEFAULT)
|
||||
**
|
||||
** Return the int64 value of the NAME query parameter to
|
||||
** the database for SCHEMA
|
||||
*/
|
||||
static void func_uri_int64(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zName = (const char*)sqlite3_value_text(argv[1]);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
sqlite3_int64 iDflt = sqlite3_value_int64(argv[2]);
|
||||
sqlite3_int64 iRes = sqlite3_uri_int64(zFile, zName, iDflt);
|
||||
sqlite3_result_int64(context, iRes);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_filename_database(SCHEMA)
|
||||
**
|
||||
** Return the database filename for SCHEMA
|
||||
*/
|
||||
static void func_filename_database(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
const char *zRes = zFile ? sqlite3_filename_database(zFile) : 0;
|
||||
sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_filename_journal(SCHEMA)
|
||||
**
|
||||
** Return the rollback journal filename for SCHEMA
|
||||
*/
|
||||
static void func_filename_journal(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
const char *zRes = zFile ? sqlite3_filename_journal(zFile) : 0;
|
||||
sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: sqlite3_filename_wal(SCHEMA)
|
||||
**
|
||||
** Return the WAL filename for SCHEMA
|
||||
*/
|
||||
static void func_filename_wal(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSchema = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
const char *zFile = sqlite3_db_filename(db, zSchema);
|
||||
const char *zRes = zFile ? sqlite3_filename_wal(zFile) : 0;
|
||||
sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_urifuncs_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
static const struct {
|
||||
const char *zFuncName;
|
||||
int nArg;
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} aFunc[] = {
|
||||
{ "sqlite3_db_filename", 1, func_db_filename },
|
||||
{ "sqlite3_uri_parameter", 2, func_uri_parameter },
|
||||
{ "sqlite3_uri_boolean", 3, func_uri_boolean },
|
||||
{ "sqlite3_uri_int64", 3, func_uri_int64 },
|
||||
{ "sqlite3_uri_key", 2, func_uri_key },
|
||||
{ "sqlite3_filename_database", 1, func_filename_database },
|
||||
{ "sqlite3_filename_journal", 1, func_filename_journal },
|
||||
{ "sqlite3_filename_wal", 1, func_filename_wal },
|
||||
};
|
||||
int rc = SQLITE_OK;
|
||||
int i;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
for(i=0; rc==SQLITE_OK && i<sizeof(aFunc)/sizeof(aFunc[0]); i++){
|
||||
rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
|
||||
SQLITE_UTF8, 0,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
** 2019-10-23
|
||||
**
|
||||
** 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 SQLite extension implements functions that handling RFC-4122 UUIDs
|
||||
** Three SQL functions are implemented:
|
||||
**
|
||||
** uuid() - generate a version 4 UUID as a string
|
||||
** uuid_str(X) - convert a UUID X into a well-formed UUID string
|
||||
** uuid_blob(X) - convert a UUID X into a 16-byte blob
|
||||
**
|
||||
** The output from uuid() and uuid_str(X) are always well-formed RFC-4122
|
||||
** UUID strings in this format:
|
||||
**
|
||||
** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
|
||||
**
|
||||
** All of the 'x', 'M', and 'N' values are lower-case hexadecimal digits.
|
||||
** The M digit indicates the "version". For uuid()-generated UUIDs, the
|
||||
** version is always "4" (a random UUID). The upper three bits of N digit
|
||||
** are the "variant". This library only supports variant 1 (indicated
|
||||
** by values of N between '8' and 'b') as those are overwhelming the most
|
||||
** common. Other variants are for legacy compatibility only.
|
||||
**
|
||||
** The output of uuid_blob(X) is always a 16-byte blob. The UUID input
|
||||
** string is converted in network byte order (big-endian) in accordance
|
||||
** with RFC-4122 specifications for variant-1 UUIDs. Note that network
|
||||
** byte order is *always* used, even if the input self-identifies as a
|
||||
** variant-2 UUID.
|
||||
**
|
||||
** The input X to the uuid_str() and uuid_blob() functions can be either
|
||||
** a string or a BLOB. If it is a BLOB it must be exactly 16 bytes in
|
||||
** length or else a NULL is returned. If the input is a string it must
|
||||
** consist of 32 hexadecimal digits, upper or lower case, optionally
|
||||
** surrounded by {...} and with optional "-" characters interposed in the
|
||||
** middle. The flexibility of input is inspired by the PostgreSQL
|
||||
** implementation of UUID functions that accept in all of the following
|
||||
** formats:
|
||||
**
|
||||
** A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
|
||||
** {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
|
||||
** a0eebc999c0b4ef8bb6d6bb9bd380a11
|
||||
** a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
|
||||
** {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
|
||||
**
|
||||
** If any of the above inputs are passed into uuid_str(), the output will
|
||||
** always be in the canonical RFC-4122 format:
|
||||
**
|
||||
** a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
|
||||
**
|
||||
** If the X input string has too few or too many digits or contains
|
||||
** stray characters other than {, }, or -, then NULL is returned.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if !defined(SQLITE_ASCII) && !defined(SQLITE_EBCDIC)
|
||||
# define SQLITE_ASCII 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Translate a single byte of Hex into an integer.
|
||||
** This routine only works if h really is a valid hexadecimal
|
||||
** character: 0..9a..fA..F
|
||||
*/
|
||||
static unsigned char sqlite3UuidHexToInt(int h){
|
||||
assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
|
||||
#ifdef SQLITE_ASCII
|
||||
h += 9*(1&(h>>6));
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
h += 9*(1&~(h>>4));
|
||||
#endif
|
||||
return (unsigned char)(h & 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a 16-byte BLOB into a well-formed RFC-4122 UUID. The output
|
||||
** buffer zStr should be at least 37 bytes in length. The output will
|
||||
** be zero-terminated.
|
||||
*/
|
||||
static void sqlite3UuidBlobToStr(
|
||||
const unsigned char *aBlob, /* Input blob */
|
||||
unsigned char *zStr /* Write the answer here */
|
||||
){
|
||||
static const char zDigits[] = "0123456789abcdef";
|
||||
int i, k;
|
||||
unsigned char x;
|
||||
k = 0;
|
||||
for(i=0, k=0x550; i<16; i++, k=k>>1){
|
||||
if( k&1 ){
|
||||
zStr[0] = '-';
|
||||
zStr++;
|
||||
}
|
||||
x = aBlob[i];
|
||||
zStr[0] = zDigits[x>>4];
|
||||
zStr[1] = zDigits[x&0xf];
|
||||
zStr += 2;
|
||||
}
|
||||
*zStr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to parse a zero-terminated input string zStr into a binary
|
||||
** UUID. Return 0 on success, or non-zero if the input string is not
|
||||
** parsable.
|
||||
*/
|
||||
static int sqlite3UuidStrToBlob(
|
||||
const unsigned char *zStr, /* Input string */
|
||||
unsigned char *aBlob /* Write results here */
|
||||
){
|
||||
int i;
|
||||
if( zStr[0]=='{' ) zStr++;
|
||||
for(i=0; i<16; i++){
|
||||
if( zStr[0]=='-' ) zStr++;
|
||||
if( isxdigit(zStr[0]) && isxdigit(zStr[1]) ){
|
||||
aBlob[i] = (sqlite3UuidHexToInt(zStr[0])<<4)
|
||||
+ sqlite3UuidHexToInt(zStr[1]);
|
||||
zStr += 2;
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if( zStr[0]=='}' ) zStr++;
|
||||
return zStr[0]!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Render sqlite3_value pIn as a 16-byte UUID blob. Return a pointer
|
||||
** to the blob, or NULL if the input is not well-formed.
|
||||
*/
|
||||
static const unsigned char *sqlite3UuidInputToBlob(
|
||||
sqlite3_value *pIn, /* Input text */
|
||||
unsigned char *pBuf /* output buffer */
|
||||
){
|
||||
switch( sqlite3_value_type(pIn) ){
|
||||
case SQLITE_TEXT: {
|
||||
const unsigned char *z = sqlite3_value_text(pIn);
|
||||
if( sqlite3UuidStrToBlob(z, pBuf) ) return 0;
|
||||
return pBuf;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
int n = sqlite3_value_bytes(pIn);
|
||||
return n==16 ? sqlite3_value_blob(pIn) : 0;
|
||||
}
|
||||
default: {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Implementation of uuid() */
|
||||
static void sqlite3UuidFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
unsigned char zStr[37];
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
sqlite3_randomness(16, aBlob);
|
||||
aBlob[6] = (aBlob[6]&0x0f) + 0x40;
|
||||
aBlob[8] = (aBlob[8]&0x3f) + 0x80;
|
||||
sqlite3UuidBlobToStr(aBlob, zStr);
|
||||
sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Implementation of uuid_str() */
|
||||
static void sqlite3UuidStrFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
unsigned char zStr[37];
|
||||
const unsigned char *pBlob;
|
||||
(void)argc;
|
||||
pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
|
||||
if( pBlob==0 ) return;
|
||||
sqlite3UuidBlobToStr(pBlob, zStr);
|
||||
sqlite3_result_text(context, (char*)zStr, 36, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/* Implementation of uuid_blob() */
|
||||
static void sqlite3UuidBlobFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
unsigned char aBlob[16];
|
||||
const unsigned char *pBlob;
|
||||
(void)argc;
|
||||
pBlob = sqlite3UuidInputToBlob(argv[0], aBlob);
|
||||
if( pBlob==0 ) return;
|
||||
sqlite3_result_blob(context, pBlob, 16, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_uuid_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
rc = sqlite3_create_function(db, "uuid", 0, SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
|
||||
sqlite3UuidFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uuid_str", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, sqlite3UuidStrFunc, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "uuid_blob", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, sqlite3UuidBlobFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -50,6 +50,7 @@ static int wholenumberConnect(
|
||||
pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
sqlite3_declare_vtab(db, "CREATE TABLE x(value)");
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+19
-10
@@ -369,6 +369,7 @@ static int zipfileConnect(
|
||||
zipfileDequote(pNew->zFile);
|
||||
}
|
||||
}
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
return rc;
|
||||
}
|
||||
@@ -999,7 +1000,6 @@ static int zipfileDeflate(
|
||||
int res;
|
||||
str.next_out = aOut;
|
||||
str.avail_out = nAlloc;
|
||||
deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
||||
res = deflate(&str, Z_FINISH);
|
||||
if( res==Z_STREAM_END ){
|
||||
*ppOut = aOut;
|
||||
@@ -1309,10 +1309,10 @@ static int zipfileBestIndex(
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
pIdxInfo->estimatedCost = 1000.0;
|
||||
if( idx>=0 ){
|
||||
pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[idx].omit = 1;
|
||||
pIdxInfo->estimatedCost = 1000.0;
|
||||
pIdxInfo->idxNum = 1;
|
||||
}else if( unusable ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
@@ -1434,8 +1434,8 @@ static int zipfileGetMode(
|
||||
** identical, ignoring any trailing '/' character in either path. */
|
||||
static int zipfileComparePath(const char *zA, const char *zB, int nB){
|
||||
int nA = (int)strlen(zA);
|
||||
if( zA[nA-1]=='/' ) nA--;
|
||||
if( zB[nB-1]=='/' ) nB--;
|
||||
if( nA>0 && zA[nA-1]=='/' ) nA--;
|
||||
if( nB>0 && zB[nB-1]=='/' ) nB--;
|
||||
if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1445,6 +1445,10 @@ static int zipfileBegin(sqlite3_vtab *pVtab){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( pTab->pWriteFd==0 );
|
||||
if( pTab->zFile==0 || pTab->zFile[0]==0 ){
|
||||
pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* Open a write fd on the file. Also load the entire central directory
|
||||
** structure into memory. During the transaction any new file data is
|
||||
@@ -1619,6 +1623,7 @@ static int zipfileUpdate(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
zPath = (const char*)sqlite3_value_text(apVal[2]);
|
||||
if( zPath==0 ) zPath = "";
|
||||
nPath = (int)strlen(zPath);
|
||||
mTime = zipfileGetTime(apVal[4]);
|
||||
}
|
||||
@@ -1628,11 +1633,15 @@ static int zipfileUpdate(
|
||||
** '/'. This appears to be required for compatibility with info-zip
|
||||
** (the unzip command on unix). It does not create directories
|
||||
** otherwise. */
|
||||
if( zPath[nPath-1]!='/' ){
|
||||
if( nPath<=0 || zPath[nPath-1]!='/' ){
|
||||
zFree = sqlite3_mprintf("%s/", zPath);
|
||||
if( zFree==0 ){ rc = SQLITE_NOMEM; }
|
||||
zPath = (const char*)zFree;
|
||||
nPath++;
|
||||
if( zFree==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
nPath = 0;
|
||||
}else{
|
||||
nPath = (int)strlen(zPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2025,19 +2034,19 @@ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
|
||||
** at the end of the path. Or, if this is not a directory and the path
|
||||
** ends in '/' it is an error. */
|
||||
if( bIsDir==0 ){
|
||||
if( zName[nName-1]=='/' ){
|
||||
if( nName>0 && zName[nName-1]=='/' ){
|
||||
zErr = sqlite3_mprintf("non-directory name must not end with /");
|
||||
rc = SQLITE_ERROR;
|
||||
goto zipfile_step_out;
|
||||
}
|
||||
}else{
|
||||
if( zName[nName-1]!='/' ){
|
||||
if( nName==0 || zName[nName-1]!='/' ){
|
||||
zName = zFree = sqlite3_mprintf("%s/", zName);
|
||||
nName++;
|
||||
if( zName==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto zipfile_step_out;
|
||||
}
|
||||
nName = (int)strlen(zName);
|
||||
}else{
|
||||
while( nName>1 && zName[nName-2]=='/' ) nName--;
|
||||
}
|
||||
|
||||
+2
-29
@@ -4936,33 +4936,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** A main database named zName has just been opened. The following
|
||||
** function returns a pointer to a buffer owned by SQLite that contains
|
||||
** the name of the *-wal file this db connection will use. SQLite
|
||||
** happens to pass a pointer to this buffer when using xAccess()
|
||||
** or xOpen() to operate on the *-wal file.
|
||||
*/
|
||||
static const char *rbuMainToWal(const char *zName, int flags){
|
||||
int n = (int)strlen(zName);
|
||||
const char *z = &zName[n];
|
||||
if( flags & SQLITE_OPEN_URI ){
|
||||
int odd = 0;
|
||||
while( 1 ){
|
||||
if( z[0]==0 ){
|
||||
odd = 1 - odd;
|
||||
if( odd && z[1]==0 ) break;
|
||||
}
|
||||
z++;
|
||||
}
|
||||
z += 2;
|
||||
}else{
|
||||
while( *z==0 ) z++;
|
||||
}
|
||||
z += (n + 8 + 1);
|
||||
return z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an rbu file handle.
|
||||
*/
|
||||
@@ -5011,7 +4984,7 @@ static int rbuVfsOpen(
|
||||
** the name of the *-wal file this db connection will use. SQLite
|
||||
** happens to pass a pointer to this buffer when using xAccess()
|
||||
** or xOpen() to operate on the *-wal file. */
|
||||
pFd->zWal = rbuMainToWal(zName, flags);
|
||||
pFd->zWal = sqlite3_filename_wal(zName);
|
||||
}
|
||||
else if( flags & SQLITE_OPEN_WAL ){
|
||||
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
|
||||
@@ -5026,7 +4999,7 @@ static int rbuVfsOpen(
|
||||
char *zCopy;
|
||||
if( rbuIsVacuum(pDb->pRbu) ){
|
||||
zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
|
||||
zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
|
||||
zBase = sqlite3_filename_wal(zBase);
|
||||
}
|
||||
nCopy = strlen(zBase);
|
||||
zCopy = sqlite3_malloc64(nCopy+2);
|
||||
|
||||
+10
-10
@@ -1345,17 +1345,11 @@ static int geopolyFilter(
|
||||
RtreeNode *pRoot = 0;
|
||||
int rc = SQLITE_OK;
|
||||
int iCell = 0;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
rtreeReference(pRtree);
|
||||
|
||||
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
|
||||
freeCursorConstraints(pCsr);
|
||||
sqlite3_free(pCsr->aPoint);
|
||||
pStmt = pCsr->pReadAux;
|
||||
memset(pCsr, 0, sizeof(RtreeCursor));
|
||||
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
|
||||
pCsr->pReadAux = pStmt;
|
||||
resetCursor(pCsr);
|
||||
|
||||
pCsr->iStrategy = idxNum;
|
||||
if( idxNum==1 ){
|
||||
@@ -1792,14 +1786,20 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
||||
int enc = aFunc[i].bPure ? SQLITE_UTF8|SQLITE_DETERMINISTIC : SQLITE_UTF8;
|
||||
int enc;
|
||||
if( aFunc[i].bPure ){
|
||||
enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS;
|
||||
}else{
|
||||
enc = SQLITE_UTF8|SQLITE_DIRECTONLY;
|
||||
}
|
||||
rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
|
||||
enc, 0,
|
||||
aFunc[i].xFunc, 0, 0);
|
||||
}
|
||||
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
||||
rc = sqlite3_create_function(db, aAgg[i].zName, 1, SQLITE_UTF8, 0,
|
||||
0, aAgg[i].xStep, aAgg[i].xFinal);
|
||||
rc = sqlite3_create_function(db, aAgg[i].zName, 1,
|
||||
SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0,
|
||||
0, aAgg[i].xStep, aAgg[i].xFinal);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
|
||||
|
||||
+72
-28
@@ -62,6 +62,7 @@
|
||||
#else
|
||||
#include "sqlite3.h"
|
||||
#endif
|
||||
int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
#include "sqlite3rtree.h"
|
||||
@@ -325,6 +326,12 @@ struct RtreeConstraint {
|
||||
#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */
|
||||
#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */
|
||||
|
||||
/* Special operators available only on cursors. Needs to be consecutive
|
||||
** with the normal values above, but must be less than RTREE_MATCH. These
|
||||
** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or
|
||||
** x<'xyz' (RTREE_TRUE) */
|
||||
#define RTREE_TRUE 0x3f /* ? */
|
||||
#define RTREE_FALSE 0x40 /* @ */
|
||||
|
||||
/*
|
||||
** An rtree structure node.
|
||||
@@ -1058,9 +1065,12 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
|
||||
|
||||
/*
|
||||
** Free the RtreeCursor.aConstraint[] array and its contents.
|
||||
** Reset a cursor back to its initial state.
|
||||
*/
|
||||
static void freeCursorConstraints(RtreeCursor *pCsr){
|
||||
static void resetCursor(RtreeCursor *pCsr){
|
||||
Rtree *pRtree = (Rtree *)(pCsr->base.pVtab);
|
||||
int ii;
|
||||
sqlite3_stmt *pStmt;
|
||||
if( pCsr->aConstraint ){
|
||||
int i; /* Used to iterate through constraint array */
|
||||
for(i=0; i<pCsr->nConstraint; i++){
|
||||
@@ -1073,6 +1083,13 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
|
||||
sqlite3_free(pCsr->aConstraint);
|
||||
pCsr->aConstraint = 0;
|
||||
}
|
||||
for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
|
||||
sqlite3_free(pCsr->aPoint);
|
||||
pStmt = pCsr->pReadAux;
|
||||
memset(pCsr, 0, sizeof(RtreeCursor));
|
||||
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
|
||||
pCsr->pReadAux = pStmt;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1080,13 +1097,10 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
|
||||
*/
|
||||
static int rtreeClose(sqlite3_vtab_cursor *cur){
|
||||
Rtree *pRtree = (Rtree *)(cur->pVtab);
|
||||
int ii;
|
||||
RtreeCursor *pCsr = (RtreeCursor *)cur;
|
||||
assert( pRtree->nCursor>0 );
|
||||
freeCursorConstraints(pCsr);
|
||||
resetCursor(pCsr);
|
||||
sqlite3_finalize(pCsr->pReadAux);
|
||||
sqlite3_free(pCsr->aPoint);
|
||||
for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
|
||||
sqlite3_free(pCsr);
|
||||
pRtree->nCursor--;
|
||||
nodeBlobReset(pRtree);
|
||||
@@ -1244,9 +1258,12 @@ static void rtreeNonleafConstraint(
|
||||
pCellData += 8 + 4*(p->iCoord&0xfe);
|
||||
|
||||
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ );
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|
||||
|| p->op==RTREE_FALSE );
|
||||
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
||||
switch( p->op ){
|
||||
case RTREE_TRUE: return; /* Always satisfied */
|
||||
case RTREE_FALSE: break; /* Never satisfied */
|
||||
case RTREE_LE:
|
||||
case RTREE_LT:
|
||||
case RTREE_EQ:
|
||||
@@ -1284,16 +1301,19 @@ static void rtreeLeafConstraint(
|
||||
RtreeDValue xN; /* Coordinate value converted to a double */
|
||||
|
||||
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ );
|
||||
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|
||||
|| p->op==RTREE_FALSE );
|
||||
pCellData += 8 + p->iCoord*4;
|
||||
assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
||||
RTREE_DECODE_COORD(eInt, pCellData, xN);
|
||||
switch( p->op ){
|
||||
case RTREE_LE: if( xN <= p->u.rValue ) return; break;
|
||||
case RTREE_LT: if( xN < p->u.rValue ) return; break;
|
||||
case RTREE_GE: if( xN >= p->u.rValue ) return; break;
|
||||
case RTREE_GT: if( xN > p->u.rValue ) return; break;
|
||||
default: if( xN == p->u.rValue ) return; break;
|
||||
case RTREE_TRUE: return; /* Always satisfied */
|
||||
case RTREE_FALSE: break; /* Never satisfied */
|
||||
case RTREE_LE: if( xN <= p->u.rValue ) return; break;
|
||||
case RTREE_LT: if( xN < p->u.rValue ) return; break;
|
||||
case RTREE_GE: if( xN >= p->u.rValue ) return; break;
|
||||
case RTREE_GT: if( xN > p->u.rValue ) return; break;
|
||||
default: if( xN == p->u.rValue ) return; break;
|
||||
}
|
||||
*peWithin = NOT_WITHIN;
|
||||
}
|
||||
@@ -1786,17 +1806,11 @@ static int rtreeFilter(
|
||||
int ii;
|
||||
int rc = SQLITE_OK;
|
||||
int iCell = 0;
|
||||
sqlite3_stmt *pStmt;
|
||||
|
||||
rtreeReference(pRtree);
|
||||
|
||||
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
|
||||
freeCursorConstraints(pCsr);
|
||||
sqlite3_free(pCsr->aPoint);
|
||||
pStmt = pCsr->pReadAux;
|
||||
memset(pCsr, 0, sizeof(RtreeCursor));
|
||||
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
|
||||
pCsr->pReadAux = pStmt;
|
||||
resetCursor(pCsr);
|
||||
|
||||
pCsr->iStrategy = idxNum;
|
||||
if( idxNum==1 ){
|
||||
@@ -1805,7 +1819,15 @@ static int rtreeFilter(
|
||||
RtreeSearchPoint *p; /* Search point for the leaf */
|
||||
i64 iRowid = sqlite3_value_int64(argv[0]);
|
||||
i64 iNode = 0;
|
||||
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
|
||||
int eType = sqlite3_value_numeric_type(argv[0]);
|
||||
if( eType==SQLITE_INTEGER
|
||||
|| (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid)
|
||||
){
|
||||
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
pLeaf = 0;
|
||||
}
|
||||
if( rc==SQLITE_OK && pLeaf!=0 ){
|
||||
p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
|
||||
assert( p!=0 ); /* Always returns pCsr->sPoint */
|
||||
@@ -1835,6 +1857,7 @@ static int rtreeFilter(
|
||||
|| (idxStr && (int)strlen(idxStr)==argc*2) );
|
||||
for(ii=0; ii<argc; ii++){
|
||||
RtreeConstraint *p = &pCsr->aConstraint[ii];
|
||||
int eType = sqlite3_value_numeric_type(argv[ii]);
|
||||
p->op = idxStr[ii*2];
|
||||
p->iCoord = idxStr[ii*2+1]-'0';
|
||||
if( p->op>=RTREE_MATCH ){
|
||||
@@ -1849,12 +1872,21 @@ static int rtreeFilter(
|
||||
p->pInfo->nCoord = pRtree->nDim2;
|
||||
p->pInfo->anQueue = pCsr->anQueue;
|
||||
p->pInfo->mxLevel = pRtree->iDepth + 1;
|
||||
}else{
|
||||
}else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
|
||||
#ifdef SQLITE_RTREE_INT_ONLY
|
||||
p->u.rValue = sqlite3_value_int64(argv[ii]);
|
||||
#else
|
||||
p->u.rValue = sqlite3_value_double(argv[ii]);
|
||||
#endif
|
||||
}else{
|
||||
p->u.rValue = RTREE_ZERO;
|
||||
if( eType==SQLITE_NULL ){
|
||||
p->op = RTREE_FALSE;
|
||||
}else if( p->op==RTREE_LT || p->op==RTREE_LE ){
|
||||
p->op = RTREE_TRUE;
|
||||
}else{
|
||||
p->op = RTREE_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3631,6 +3663,14 @@ static int getNodeSize(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the length of a token
|
||||
*/
|
||||
static int rtreeTokenLength(const char *z){
|
||||
int dummy = 0;
|
||||
return sqlite3GetToken((const unsigned char*)z,&dummy);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is the implementation of both the xConnect and xCreate
|
||||
** methods of the r-tree virtual table.
|
||||
@@ -3667,8 +3707,8 @@ static int rtreeInit(
|
||||
};
|
||||
|
||||
assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
|
||||
if( argc>RTREE_MAX_AUX_COLUMN+3 ){
|
||||
*pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
|
||||
if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){
|
||||
*pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
@@ -3696,16 +3736,20 @@ static int rtreeInit(
|
||||
** the r-tree table schema.
|
||||
*/
|
||||
pSql = sqlite3_str_new(db);
|
||||
sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);
|
||||
sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT",
|
||||
rtreeTokenLength(argv[3]), argv[3]);
|
||||
for(ii=4; ii<argc; ii++){
|
||||
if( argv[ii][0]=='+' ){
|
||||
const char *zArg = argv[ii];
|
||||
if( zArg[0]=='+' ){
|
||||
pRtree->nAux++;
|
||||
sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
|
||||
sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1);
|
||||
}else if( pRtree->nAux>0 ){
|
||||
break;
|
||||
}else{
|
||||
static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"};
|
||||
pRtree->nDim2++;
|
||||
sqlite3_str_appendf(pSql, ",%s", argv[ii]);
|
||||
sqlite3_str_appendf(pSql, azFormat[eCoordType],
|
||||
rtreeTokenLength(zArg), zArg);
|
||||
}
|
||||
}
|
||||
sqlite3_str_appendf(pSql, ");");
|
||||
|
||||
+77
-9
@@ -112,6 +112,9 @@ for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
|
||||
|
||||
catchsql { DROP TABLE t1 }
|
||||
}
|
||||
do_catchsql_test rtree-1.3.1000 {
|
||||
CREATE VIRTUAL TABLE t1000 USING rtree;
|
||||
} {1 {Too few columns for an rtree table}}
|
||||
|
||||
# Like execsql except display output as integer where that can be
|
||||
# done without loss of information.
|
||||
@@ -374,13 +377,43 @@ do_test rtree-8.1.1 {
|
||||
INSERT INTO t6 VALUES(2, 4, 6);
|
||||
}
|
||||
} {}
|
||||
do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2}
|
||||
do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2}
|
||||
do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {}
|
||||
do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {}
|
||||
do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {}
|
||||
do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1}
|
||||
do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2}
|
||||
do_test rtree-8.1.2 { execsql { SELECT ii FROM t6 WHERE x1>2 } } {1 2}
|
||||
do_test rtree-8.1.3 { execsql { SELECT ii FROM t6 WHERE x1>3 } } {2}
|
||||
do_test rtree-8.1.4 { execsql { SELECT ii FROM t6 WHERE x1>4 } } {}
|
||||
do_test rtree-8.1.5 { execsql { SELECT ii FROM t6 WHERE x1>5 } } {}
|
||||
do_test rtree-8.1.6 { execsql { SELECT ii FROM t6 WHERE x1>''} } {}
|
||||
do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1>null}} {}
|
||||
do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1>'2'} } {1 2}
|
||||
do_test rtree-8.1.9 { execsql { SELECT ii FROM t6 WHERE x1>'3'} } {2}
|
||||
do_test rtree-8.2.2 { execsql { SELECT ii FROM t6 WHERE x1>=2 } } {1 2}
|
||||
do_test rtree-8.2.3 { execsql { SELECT ii FROM t6 WHERE x1>=3 } } {1 2}
|
||||
do_test rtree-8.2.4 { execsql { SELECT ii FROM t6 WHERE x1>=4 } } {2}
|
||||
do_test rtree-8.2.5 { execsql { SELECT ii FROM t6 WHERE x1>=5 } } {}
|
||||
do_test rtree-8.2.6 { execsql { SELECT ii FROM t6 WHERE x1>=''} } {}
|
||||
do_test rtree-8.2.7 { execsql { SELECT ii FROM t6 WHERE x1>=null}} {}
|
||||
do_test rtree-8.2.8 { execsql { SELECT ii FROM t6 WHERE x1>='4'} } {2}
|
||||
do_test rtree-8.2.9 { execsql { SELECT ii FROM t6 WHERE x1>='5'} } {}
|
||||
do_test rtree-8.3.2 { execsql { SELECT ii FROM t6 WHERE x1<2 } } {}
|
||||
do_test rtree-8.3.3 { execsql { SELECT ii FROM t6 WHERE x1<3 } } {}
|
||||
do_test rtree-8.3.4 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1}
|
||||
do_test rtree-8.3.5 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2}
|
||||
do_test rtree-8.3.6 { execsql { SELECT ii FROM t6 WHERE x1<''} } {1 2}
|
||||
do_test rtree-8.3.7 { execsql { SELECT ii FROM t6 WHERE x1<null}} {}
|
||||
do_test rtree-8.3.8 { execsql { SELECT ii FROM t6 WHERE x1<'3'} } {}
|
||||
do_test rtree-8.3.9 { execsql { SELECT ii FROM t6 WHERE x1<'4'} } {1}
|
||||
do_test rtree-8.4.2 { execsql { SELECT ii FROM t6 WHERE x1<=2 } } {}
|
||||
do_test rtree-8.4.3 { execsql { SELECT ii FROM t6 WHERE x1<=3 } } {1}
|
||||
do_test rtree-8.4.4 { execsql { SELECT ii FROM t6 WHERE x1<=4 } } {1 2}
|
||||
do_test rtree-8.4.5 { execsql { SELECT ii FROM t6 WHERE x1<=5 } } {1 2}
|
||||
do_test rtree-8.4.6 { execsql { SELECT ii FROM t6 WHERE x1<=''} } {1 2}
|
||||
do_test rtree-8.4.7 { execsql { SELECT ii FROM t6 WHERE x1<=null}} {}
|
||||
do_test rtree-8.5.2 { execsql { SELECT ii FROM t6 WHERE x1=2 } } {}
|
||||
do_test rtree-8.5.3 { execsql { SELECT ii FROM t6 WHERE x1=3 } } {1}
|
||||
do_test rtree-8.5.4 { execsql { SELECT ii FROM t6 WHERE x1=4 } } {2}
|
||||
do_test rtree-8.5.5 { execsql { SELECT ii FROM t6 WHERE x1=5 } } {}
|
||||
do_test rtree-8.5.6 { execsql { SELECT ii FROM t6 WHERE x1=''} } {}
|
||||
do_test rtree-8.5.7 { execsql { SELECT ii FROM t6 WHERE x1=null}} {}
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Test cases rtree-9.*
|
||||
@@ -578,15 +611,29 @@ do_execsql_test 14.5 {
|
||||
1 0.0 0.0
|
||||
2 52.0 81.0
|
||||
}
|
||||
do_execsql_test 14.6 {
|
||||
INSERT INTO t10 VALUES(0,10,20);
|
||||
SELECT * FROM t10 WHERE ii=NULL;
|
||||
} {}
|
||||
do_execsql_test 14.7 {
|
||||
SELECT * FROM t10 WHERE ii='xyz';
|
||||
} {}
|
||||
do_execsql_test 14.8 {
|
||||
SELECT * FROM t10 WHERE ii='0.0';
|
||||
} {0 10.0 20.0}
|
||||
do_execsql_test 14.9 {
|
||||
SELECT * FROM t10 WHERE ii=0.0;
|
||||
} {0 10.0 20.0}
|
||||
|
||||
do_execsql_test 14.4 {
|
||||
|
||||
do_execsql_test 14.104 {
|
||||
DROP TABLE t10;
|
||||
CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2);
|
||||
INSERT INTO t10 VALUES(1, 'one', 'two');
|
||||
INSERT INTO t10 VALUES(2, '52xyz', '81...');
|
||||
INSERT INTO t10 VALUES(3, 42.3, 49.9);
|
||||
}
|
||||
do_execsql_test 14.5 {
|
||||
do_execsql_test 14.105 {
|
||||
SELECT * FROM t10;
|
||||
} {
|
||||
1 0 0
|
||||
@@ -661,5 +708,26 @@ do_execsql_test 17.2 {
|
||||
REINDEX;
|
||||
} {}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 18.0 {
|
||||
CREATE VIRTUAL TABLE rt0 USING rtree(c0, c1, c2);
|
||||
INSERT INTO rt0(c0,c1,c2) VALUES(9,2,3);
|
||||
SELECT c0 FROM rt0 WHERE rt0.c1 > '-1';
|
||||
SELECT rt0.c1 > '-1' FROM rt0;
|
||||
} {9 1}
|
||||
|
||||
expand_all_sql db
|
||||
|
||||
# 2020-02-28 ticket e63b4d1a65546532
|
||||
reset_db
|
||||
do_execsql_test 19.0 {
|
||||
CREATE VIRTUAL TABLE rt0 USING rtree(a,b,c);
|
||||
INSERT INTO rt0(a,b,c) VALUES(0,0.0,0.0);
|
||||
CREATE VIEW v0(x) AS SELECT DISTINCT rt0.b FROM rt0;
|
||||
SELECT v0.x FROM v0, rt0;
|
||||
} {0.0}
|
||||
do_execsql_test 19.1 {
|
||||
SELECT v0.x FROM v0, rt0 WHERE v0.x = rt0.b;
|
||||
} {0.0}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -33,12 +33,13 @@ if {[info exists G(isquick)] && $G(isquick)} {
|
||||
}
|
||||
|
||||
foreach module {rtree_i32 rtree} {
|
||||
if {$module=="rtree_i32"} {set etype INT} {set etype REAL}
|
||||
for {set nDim 1} {$nDim <= 5} {incr nDim} {
|
||||
|
||||
do_test rtree2-$module.$nDim.1 {
|
||||
set cols [list]
|
||||
foreach c [list c0 c1 c2 c3 c4 c5 c6 c7 c8 c9] {
|
||||
lappend cols "$c REAL"
|
||||
lappend cols "$c $etype"
|
||||
}
|
||||
set cols [join [lrange $cols 0 [expr {$nDim*2-1}]] ", "]
|
||||
execsql "
|
||||
|
||||
@@ -177,7 +177,7 @@ do_execsql_test 4.3 {
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.1 {
|
||||
CREATE TABLE t1(x PRIMARY KEY, y);
|
||||
CREATE TABLE t1(x INT PRIMARY KEY, y);
|
||||
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, +d1);
|
||||
|
||||
INSERT INTO t1(x) VALUES(1);
|
||||
|
||||
@@ -43,10 +43,33 @@ do_execsql_test rtreeH-101 {
|
||||
do_execsql_test rtreeH-102 {
|
||||
SELECT * FROM t1 WHERE rowid=5;
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
do_execsql_test rtreeH-102b {
|
||||
SELECT * FROM t1 WHERE rowid=5.0;
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
do_execsql_test rtreeH-102c {
|
||||
SELECT * FROM t1 WHERE rowid='5';
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
do_execsql_test rtreeH-102d {
|
||||
SELECT * FROM t1 WHERE rowid='0005';
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
do_execsql_test rtreeH-102e {
|
||||
SELECT * FROM t1 WHERE rowid='+5.0e+0';
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
do_execsql_test rtreeH-103 {
|
||||
SELECT * FROM t1 WHERE label='center';
|
||||
} {5 40.0 60.0 40.0 60.0 center {}}
|
||||
|
||||
do_execsql_test rtreeH-104 {
|
||||
SELECT * FROM t1 WHERE rowid='+5.0e+0x';
|
||||
} {}
|
||||
do_execsql_test rtreeH-105 {
|
||||
SELECT * FROM t1 WHERE rowid=x'35';
|
||||
} {}
|
||||
do_execsql_test rtreeH-106 {
|
||||
SELECT * FROM t1 WHERE rowid=null;
|
||||
} {}
|
||||
|
||||
|
||||
do_rtree_integrity_test rtreeH-110 t1
|
||||
|
||||
do_execsql_test rtreeH-120 {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# 2019-12-05
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Additional test cases
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source [file join [file dirname [info script]] rtree_util.tcl]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
|
||||
# The following is a test of rowvalue handling on virtual tables that
|
||||
# deal with inequalities and that set the OMIT flag on terms of the
|
||||
# WHERE clause. This is not specific to rtree. We just use rtree because
|
||||
# it is a convenient test platform since it has all the right
|
||||
# characteristics.
|
||||
#
|
||||
do_execsql_test rtreeI-1.10 {
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
CREATE VIRTUAL TABLE t2 USING rtree(id,x0,x1);
|
||||
INSERT INTO t2(id,x0,x1) VALUES(1,2,3);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.20 {
|
||||
SELECT 123 FROM t1, t2 WHERE (a,0)>(x0,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.21 {
|
||||
SELECT 123 FROM t1, t2 WHERE (a,0.1)>(x0,0);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.22 {
|
||||
SELECT 123 FROM t1, t2 WHERE (a,0)>=(x0,0);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.23 {
|
||||
SELECT 123 FROM t1, t2 WHERE (a,0)<=(x0,0);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.24 {
|
||||
SELECT 123 FROM t1, t2 WHERE (a,0)<(x0,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.30 {
|
||||
SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.31 {
|
||||
SELECT 123 FROM t1, t2 WHERE (x0,0)<(a,0.1);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.40 {
|
||||
SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>(x0,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.41 {
|
||||
SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0.5)>(x0,0);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.42 {
|
||||
SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)>=(x0,0);
|
||||
} {123}
|
||||
do_execsql_test rtreeI-1.43 {
|
||||
SELECT 123 FROM t1, t2 WHERE x1<5 AND id<99 AND (a,0)<(x0,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.50 {
|
||||
SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0);
|
||||
} {}
|
||||
do_execsql_test rtreeI-1.51 {
|
||||
SELECT 123 FROM t1, t2 WHERE 5>x1 AND 99>id AND (x0,0)<(a,0.5);
|
||||
} {123}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -34,5 +34,51 @@ do_test 1.0 {
|
||||
compare_db db db2
|
||||
} {}
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
db2 close
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO main.t1 VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9);
|
||||
}
|
||||
|
||||
do_test 2.1 {
|
||||
sqlite3session S db main
|
||||
S attach *
|
||||
db eval {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(10, 11, 12);
|
||||
DELETE FROM t1 WHERE a=1;
|
||||
UPDATE t1 SET b='five', c='six' WHERE a=4;
|
||||
}
|
||||
|
||||
set C [S changeset]
|
||||
db eval ROLLBACK
|
||||
S delete
|
||||
set {} {}
|
||||
} {}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
INSERT INTO temp.t1 VALUES(1, 2, 3), (4, 5, 6), (7, 8, 9);
|
||||
}
|
||||
|
||||
set ::conflict [list]
|
||||
proc xConflict {args} { lappend ::conflict $args ; return "" }
|
||||
do_test 2.3 {
|
||||
sqlite3changeset_apply db $C xConflict
|
||||
set ::conflict
|
||||
} {}
|
||||
do_execsql_test 2.4 {
|
||||
SELECT * FROM main.t1;
|
||||
SELECT '****';
|
||||
SELECT * FROM temp.t1;
|
||||
} {
|
||||
4 five six 7 8 9 10 11 12
|
||||
****
|
||||
1 2 3 4 5 6 7 8 9
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -3513,7 +3513,7 @@ static int sessionDeleteRow(
|
||||
SessionBuffer buf = {0, 0, 0};
|
||||
int nPk = 0;
|
||||
|
||||
sessionAppendStr(&buf, "DELETE FROM ", &rc);
|
||||
sessionAppendStr(&buf, "DELETE FROM main.", &rc);
|
||||
sessionAppendIdent(&buf, zTab, &rc);
|
||||
sessionAppendStr(&buf, " WHERE ", &rc);
|
||||
|
||||
@@ -3596,7 +3596,7 @@ static int sessionUpdateRow(
|
||||
SessionBuffer buf = {0, 0, 0};
|
||||
|
||||
/* Append "UPDATE tbl SET " */
|
||||
sessionAppendStr(&buf, "UPDATE ", &rc);
|
||||
sessionAppendStr(&buf, "UPDATE main.", &rc);
|
||||
sessionAppendIdent(&buf, zTab, &rc);
|
||||
sessionAppendStr(&buf, " SET ", &rc);
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ int sqlite3session_attach(
|
||||
** The second argument (xFilter) is the "filter callback". For changes to rows
|
||||
** in tables that are not attached to the Session object, the filter is called
|
||||
** to determine whether changes to the table's rows should be tracked or not.
|
||||
** If xFilter returns 0, changes is not tracked. Note that once a table is
|
||||
** If xFilter returns 0, changes are not tracked. Note that once a table is
|
||||
** attached, xFilter will not be called again.
|
||||
*/
|
||||
void sqlite3session_table_filter(
|
||||
@@ -374,7 +374,7 @@ int sqlite3session_changeset(
|
||||
** It an error if database zFrom does not exist or does not contain the
|
||||
** required compatible table.
|
||||
**
|
||||
** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
|
||||
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
||||
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
||||
** may be set to point to a buffer containing an English language error
|
||||
** message. It is the responsibility of the caller to free this buffer using
|
||||
@@ -511,7 +511,7 @@ int sqlite3changeset_start_v2(
|
||||
** CAPI3REF: Advance A Changeset Iterator
|
||||
** METHOD: sqlite3_changeset_iter
|
||||
**
|
||||
** This function may only be used with iterators created by function
|
||||
** This function may only be used with iterators created by the function
|
||||
** [sqlite3changeset_start()]. If it is called on an iterator passed to
|
||||
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
|
||||
** is returned and the call has no effect.
|
||||
@@ -927,8 +927,8 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
||||
** case, this function fails with SQLITE_SCHEMA. If the input changeset
|
||||
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
|
||||
** returned. Or, if an out-of-memory condition occurs during processing, this
|
||||
** function returns SQLITE_NOMEM. In all cases, if an error occurs the
|
||||
** final contents of the changegroup is undefined.
|
||||
** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
|
||||
** of the final contents of the changegroup is undefined.
|
||||
**
|
||||
** If no error occurs, SQLITE_OK is returned.
|
||||
*/
|
||||
@@ -1103,7 +1103,7 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
|
||||
**
|
||||
** It is safe to execute SQL statements, including those that write to the
|
||||
** table that the callback related to, from within the xConflict callback.
|
||||
** This can be used to further customize the applications conflict
|
||||
** This can be used to further customize the application's conflict
|
||||
** resolution strategy.
|
||||
**
|
||||
** All changes made by these functions are enclosed in a savepoint transaction.
|
||||
@@ -1413,7 +1413,7 @@ int sqlite3rebaser_configure(
|
||||
**
|
||||
** Argument pIn must point to a buffer containing a changeset nIn bytes
|
||||
** in size. This function allocates and populates a buffer with a copy
|
||||
** of the changeset rebased rebased according to the configuration of the
|
||||
** of the changeset rebased according to the configuration of the
|
||||
** rebaser object passed as the first argument. If successful, (*ppOut)
|
||||
** is set to point to the new buffer containing the rebased changeset and
|
||||
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
|
||||
|
||||
@@ -40,7 +40,7 @@ static sqlite3_stmt *sqlite3UserAuthPrepare(
|
||||
char *zSql;
|
||||
int rc;
|
||||
va_list ap;
|
||||
int savedFlags = db->flags;
|
||||
u64 savedFlags = db->flags;
|
||||
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
|
||||
@@ -733,6 +733,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/misc/uint.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
97ba442b8d4534ebd2971f6f10ad6e4fc7593b531ded84574dc7bf7f8e2f76cb
|
||||
3cabe06b6e9433cbfb4bf7bd72a425f43b54f57d84a205adbaa6a1147bbe46bf
|
||||
+127
-74
@@ -31,9 +31,8 @@
|
||||
static int isAlterableTable(Parse *pParse, Table *pTab){
|
||||
if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|| ( (pTab->tabFlags & TF_Shadow)
|
||||
&& (pParse->db->flags & SQLITE_Defensive)
|
||||
&& pParse->db->nVdbeExec==0
|
||||
|| ( (pTab->tabFlags & TF_Shadow)!=0
|
||||
&& sqlite3ReadOnlyShadowTables(pParse->db)
|
||||
)
|
||||
#endif
|
||||
){
|
||||
@@ -298,14 +297,6 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If the default value for the new column was specified with a
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
*/
|
||||
assert( pDflt==0 || pDflt->op==TK_SPAN );
|
||||
if( pDflt && pDflt->pLeft->op==TK_NULL ){
|
||||
pDflt = 0;
|
||||
}
|
||||
|
||||
/* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
|
||||
** If there is a NOT NULL constraint, then the default value for the
|
||||
@@ -319,35 +310,49 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
||||
return;
|
||||
}
|
||||
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a REFERENCES column with non-NULL default value");
|
||||
return;
|
||||
}
|
||||
if( pCol->notNull && !pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a NOT NULL column with default value NULL");
|
||||
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
|
||||
/* If the default value for the new column was specified with a
|
||||
** literal NULL, then set pDflt to 0. This simplifies checking
|
||||
** for an SQL NULL default below.
|
||||
*/
|
||||
assert( pDflt==0 || pDflt->op==TK_SPAN );
|
||||
if( pDflt && pDflt->pLeft->op==TK_NULL ){
|
||||
pDflt = 0;
|
||||
}
|
||||
if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a REFERENCES column with non-NULL default value");
|
||||
return;
|
||||
}
|
||||
if( pCol->notNull && !pDflt ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"Cannot add a NOT NULL column with default value NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
if( pDflt ){
|
||||
sqlite3_value *pVal = 0;
|
||||
int rc;
|
||||
rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
|
||||
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( db->mallocFailed == 1 );
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
}else if( pCol->colFlags & COLFLAG_STORED ){
|
||||
sqlite3ErrorMsg(pParse, "cannot add a STORED column");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
||||
** can handle (i.e. not CURRENT_TIME etc.)
|
||||
*/
|
||||
if( pDflt ){
|
||||
sqlite3_value *pVal = 0;
|
||||
int rc;
|
||||
rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
|
||||
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
||||
if( rc!=SQLITE_OK ){
|
||||
assert( db->mallocFailed == 1 );
|
||||
return;
|
||||
}
|
||||
if( !pVal ){
|
||||
sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
|
||||
return;
|
||||
}
|
||||
sqlite3ValueFree(pVal);
|
||||
}
|
||||
|
||||
/* Modify the CREATE TABLE statement. */
|
||||
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
|
||||
@@ -464,6 +469,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
for(i=0; i<pNew->nCol; i++){
|
||||
Column *pCol = &pNew->aCol[i];
|
||||
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
|
||||
pCol->hName = sqlite3StrIHash(pCol->zName);
|
||||
pCol->zColl = 0;
|
||||
pCol->pDflt = 0;
|
||||
}
|
||||
@@ -692,12 +698,14 @@ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
|
||||
RenameToken *pNew;
|
||||
assert( pPtr || pParse->db->mallocFailed );
|
||||
renameTokenCheckAll(pParse, pPtr);
|
||||
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
|
||||
if( pNew ){
|
||||
pNew->p = pPtr;
|
||||
pNew->t = *pToken;
|
||||
pNew->pNext = pParse->pRename;
|
||||
pParse->pRename = pNew;
|
||||
if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
|
||||
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
|
||||
if( pNew ){
|
||||
pNew->p = pPtr;
|
||||
pNew->t = *pToken;
|
||||
pNew->pNext = pParse->pRename;
|
||||
pParse->pRename = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
return pPtr;
|
||||
@@ -728,17 +736,54 @@ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** Iterate through the Select objects that are part of WITH clauses attached
|
||||
** to select statement pSelect.
|
||||
*/
|
||||
static void renameWalkWith(Walker *pWalker, Select *pSelect){
|
||||
With *pWith = pSelect->pWith;
|
||||
if( pWith ){
|
||||
int i;
|
||||
for(i=0; i<pWith->nCte; i++){
|
||||
Select *p = pWith->a[i].pSelect;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pWalker->pParse;
|
||||
sqlite3SelectPrep(sNC.pParse, p, &sNC);
|
||||
sqlite3WalkSelect(pWalker, p);
|
||||
sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Unmap all tokens in the IdList object passed as the second argument.
|
||||
*/
|
||||
static void unmapColumnIdlistNames(
|
||||
Parse *pParse,
|
||||
IdList *pIdList
|
||||
){
|
||||
if( pIdList ){
|
||||
int ii;
|
||||
for(ii=0; ii<pIdList->nId; ii++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Walker callback used by sqlite3RenameExprUnmap().
|
||||
*/
|
||||
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
int i;
|
||||
if( pParse->nErr ) return WRC_Abort;
|
||||
if( NEVER(p->selFlags & SF_View) ) return WRC_Prune;
|
||||
if( ALWAYS(p->pEList) ){
|
||||
ExprList *pList = p->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( pList->a[i].zName ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zName);
|
||||
if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -746,8 +791,12 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
SrcList *pSrc = p->pSrc;
|
||||
for(i=0; i<pSrc->nSrc; i++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
|
||||
if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
|
||||
unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
|
||||
}
|
||||
}
|
||||
|
||||
renameWalkWith(pWalker, p);
|
||||
return WRC_Continue;
|
||||
}
|
||||
|
||||
@@ -755,12 +804,15 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
||||
** Remove all nodes that are part of expression pExpr from the rename list.
|
||||
*/
|
||||
void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
|
||||
u8 eMode = pParse->eParseMode;
|
||||
Walker sWalker;
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
sWalker.pParse = pParse;
|
||||
sWalker.xExprCallback = renameUnmapExprCb;
|
||||
sWalker.xSelectCallback = renameUnmapSelectCb;
|
||||
pParse->eParseMode = PARSE_MODE_UNMAP;
|
||||
sqlite3WalkExpr(&sWalker, pExpr);
|
||||
pParse->eParseMode = eMode;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -776,7 +828,9 @@ void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
|
||||
sWalker.xExprCallback = renameUnmapExprCb;
|
||||
sqlite3WalkExprList(&sWalker, pEList);
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName);
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
|
||||
sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,30 +868,13 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Iterate through the Select objects that are part of WITH clauses attached
|
||||
** to select statement pSelect.
|
||||
*/
|
||||
static void renameWalkWith(Walker *pWalker, Select *pSelect){
|
||||
if( pSelect->pWith ){
|
||||
int i;
|
||||
for(i=0; i<pSelect->pWith->nCte; i++){
|
||||
Select *p = pSelect->pWith->a[i].pSelect;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pWalker->pParse;
|
||||
sqlite3SelectPrep(sNC.pParse, p, &sNC);
|
||||
sqlite3WalkSelect(pWalker, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a Walker select callback. It does nothing. It is only required
|
||||
** because without a dummy callback, sqlite3WalkExpr() and similar do not
|
||||
** descend into sub-select statements.
|
||||
*/
|
||||
static int renameColumnSelectCb(Walker *pWalker, Select *p){
|
||||
if( p->selFlags & SF_View ) return WRC_Prune;
|
||||
renameWalkWith(pWalker, p);
|
||||
return WRC_Continue;
|
||||
}
|
||||
@@ -931,8 +968,11 @@ static void renameColumnElistNames(
|
||||
if( pEList ){
|
||||
int i;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
char *zName = pEList->a[i].zName;
|
||||
if( 0==sqlite3_stricmp(zName, zOld) ){
|
||||
char *zName = pEList->a[i].zEName;
|
||||
if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
|
||||
&& ALWAYS(zName!=0)
|
||||
&& 0==sqlite3_stricmp(zName, zOld)
|
||||
){
|
||||
renameTokenFind(pParse, pCtx, (void*)zName);
|
||||
}
|
||||
}
|
||||
@@ -961,6 +1001,7 @@ static void renameColumnIdlistNames(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Parse the SQL statement zSql using Parse object (*p). The Parse object
|
||||
** is initialized by this function before it is used.
|
||||
@@ -968,7 +1009,6 @@ static void renameColumnIdlistNames(
|
||||
static int renameParseSql(
|
||||
Parse *p, /* Memory to use for Parse object */
|
||||
const char *zDb, /* Name of schema SQL belongs to */
|
||||
int bTable, /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */
|
||||
sqlite3 *db, /* Database handle */
|
||||
const char *zSql, /* SQL to parse */
|
||||
int bTemp /* True if SQL is from temp schema */
|
||||
@@ -982,7 +1022,7 @@ static int renameParseSql(
|
||||
** occurs and the parse does not result in a new table, index or
|
||||
** trigger object, the database must be corrupt. */
|
||||
memset(p, 0, sizeof(Parse));
|
||||
p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN);
|
||||
p->eParseMode = PARSE_MODE_RENAME;
|
||||
p->db = db;
|
||||
p->nQueryLoop = 1;
|
||||
rc = sqlite3RunParser(p, zSql, &zErr);
|
||||
@@ -1289,7 +1329,7 @@ static void renameColumnFunc(
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
db->xAuth = 0;
|
||||
#endif
|
||||
rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);
|
||||
|
||||
/* Find tokens that need to be replaced. */
|
||||
memset(&sWalker, 0, sizeof(Walker));
|
||||
@@ -1303,8 +1343,9 @@ static void renameColumnFunc(
|
||||
if( sParse.pNewTable ){
|
||||
Select *pSelect = sParse.pNewTable->pSelect;
|
||||
if( pSelect ){
|
||||
pSelect->selFlags &= ~SF_View;
|
||||
sParse.rc = SQLITE_OK;
|
||||
sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
|
||||
sqlite3SelectPrep(&sParse, pSelect, 0);
|
||||
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3WalkSelect(&sWalker, pSelect);
|
||||
@@ -1331,6 +1372,11 @@ static void renameColumnFunc(
|
||||
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
for(i=0; i<sParse.pNewTable->nCol; i++){
|
||||
sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
@@ -1416,6 +1462,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
||||
int i;
|
||||
RenameCtx *p = pWalker->u.pRename;
|
||||
SrcList *pSrc = pSelect->pSrc;
|
||||
if( pSelect->selFlags & SF_View ) return WRC_Prune;
|
||||
if( pSrc==0 ){
|
||||
assert( pWalker->pParse->db->mallocFailed );
|
||||
return WRC_Abort;
|
||||
@@ -1486,7 +1533,7 @@ static void renameTableFunc(
|
||||
sWalker.xSelectCallback = renameTableSelectCb;
|
||||
sWalker.u.pRename = &sCtx;
|
||||
|
||||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
||||
@@ -1495,13 +1542,19 @@ static void renameTableFunc(
|
||||
|
||||
if( pTab->pSelect ){
|
||||
if( isLegacy==0 ){
|
||||
Select *pSelect = pTab->pSelect;
|
||||
NameContext sNC;
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = &sParse;
|
||||
|
||||
assert( pSelect->selFlags & SF_View );
|
||||
pSelect->selFlags &= ~SF_View;
|
||||
sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
||||
if( sParse.nErr ) rc = sParse.rc;
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
if( sParse.nErr ){
|
||||
rc = sParse.rc;
|
||||
}else{
|
||||
sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Modify any FK definitions to point to the new table. */
|
||||
@@ -1622,7 +1675,7 @@ static void renameTableTest(
|
||||
if( zDb && zInput ){
|
||||
int rc;
|
||||
Parse sParse;
|
||||
rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
|
||||
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
|
||||
NameContext sNC;
|
||||
|
||||
+76
-80
@@ -256,9 +256,9 @@ static void openStatTable(
|
||||
** share an instance of the following structure to hold their state
|
||||
** information.
|
||||
*/
|
||||
typedef struct Stat4Accum Stat4Accum;
|
||||
typedef struct Stat4Sample Stat4Sample;
|
||||
struct Stat4Sample {
|
||||
typedef struct StatAccum StatAccum;
|
||||
typedef struct StatSample StatSample;
|
||||
struct StatSample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
@@ -273,27 +273,29 @@ struct Stat4Sample {
|
||||
u32 iHash; /* Tiebreaker hash */
|
||||
#endif
|
||||
};
|
||||
struct Stat4Accum {
|
||||
struct StatAccum {
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
tRowcnt nRow; /* Number of rows in the entire table */
|
||||
tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
int nCol; /* Number of columns in index + pk/rowid */
|
||||
int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
||||
StatSample current; /* Current row as a StatSample */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
tRowcnt nPSample; /* How often to do a periodic sample */
|
||||
int mxSample; /* Maximum number of samples to accumulate */
|
||||
Stat4Sample current; /* Current row as a Stat4Sample */
|
||||
u32 iPrn; /* Pseudo-random number used for sampling */
|
||||
Stat4Sample *aBest; /* Array of nCol best samples */
|
||||
StatSample *aBest; /* Array of nCol best samples */
|
||||
int iMin; /* Index in a[] of entry with minimum score */
|
||||
int nSample; /* Current number of samples */
|
||||
int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
|
||||
int iGet; /* Index of current sample accessed by stat_get() */
|
||||
Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
||||
sqlite3 *db; /* Database connection, for malloc() */
|
||||
StatSample *a; /* Array of mxSample StatSample objects */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Reclaim memory used by a Stat4Sample
|
||||
/* Reclaim memory used by a StatSample
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
static void sampleClear(sqlite3 *db, StatSample *p){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ){
|
||||
sqlite3DbFree(db, p->u.aRowid);
|
||||
@@ -305,7 +307,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
||||
/* Initialize the BLOB value of a ROWID
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
|
||||
@@ -321,7 +323,7 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
||||
/* Initialize the INTEGER value of a ROWID.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
|
||||
assert( db!=0 );
|
||||
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
||||
p->nRowid = 0;
|
||||
@@ -334,7 +336,7 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
||||
** Copy the contents of object (*pFrom) into (*pTo).
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
||||
pTo->isPSample = pFrom->isPSample;
|
||||
pTo->iCol = pFrom->iCol;
|
||||
pTo->iHash = pFrom->iHash;
|
||||
@@ -350,10 +352,10 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Reclaim all memory of a Stat4Accum structure.
|
||||
** Reclaim all memory of a StatAccum structure.
|
||||
*/
|
||||
static void stat4Destructor(void *pOld){
|
||||
Stat4Accum *p = (Stat4Accum*)pOld;
|
||||
static void statAccumDestructor(void *pOld){
|
||||
StatAccum *p = (StatAccum*)pOld;
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int i;
|
||||
for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
||||
@@ -381,9 +383,9 @@ static void stat4Destructor(void *pOld){
|
||||
** PRIMARY KEY of the table. The covering index that implements the
|
||||
** original WITHOUT ROWID table as N==K as a special case.
|
||||
**
|
||||
** This routine allocates the Stat4Accum object in heap memory. The return
|
||||
** value is a pointer to the Stat4Accum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
||||
** This routine allocates the StatAccum object in heap memory. The return
|
||||
** value is a pointer to the StatAccum object. The datatype of the
|
||||
** return value is BLOB, but it is really just a pointer to the StatAccum
|
||||
** object.
|
||||
*/
|
||||
static void statInit(
|
||||
@@ -391,7 +393,7 @@ static void statInit(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Stat4Accum *p;
|
||||
StatAccum *p;
|
||||
int nCol; /* Number of columns in index being sampled */
|
||||
int nKeyCol; /* Number of key columns */
|
||||
int nColUp; /* nCol rounded up for alignment */
|
||||
@@ -410,13 +412,13 @@ static void statInit(
|
||||
assert( nKeyCol<=nCol );
|
||||
assert( nKeyCol>0 );
|
||||
|
||||
/* Allocate the space required for the Stat4Accum object */
|
||||
/* Allocate the space required for the StatAccum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
||||
+ sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
||||
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
||||
+ sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
||||
#endif
|
||||
;
|
||||
@@ -445,8 +447,8 @@ static void statInit(
|
||||
p->current.anLt = &p->current.anEq[nColUp];
|
||||
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
||||
|
||||
/* Set up the Stat4Accum.a[] and aBest[] arrays */
|
||||
p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
|
||||
/* Set up the StatAccum.a[] and aBest[] arrays */
|
||||
p->a = (struct StatSample*)&p->current.anLt[nColUp];
|
||||
p->aBest = &p->a[mxSample];
|
||||
pSpace = (u8*)(&p->a[mxSample+nCol]);
|
||||
for(i=0; i<(mxSample+nCol); i++){
|
||||
@@ -466,7 +468,7 @@ static void statInit(
|
||||
** only the pointer (the 2nd parameter) matters. The size of the object
|
||||
** (given by the 3rd parameter) is never used and can be any positive
|
||||
** value. */
|
||||
sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
||||
sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
|
||||
}
|
||||
static const FuncDef statInitFuncdef = {
|
||||
2+IsStat4, /* nArg */
|
||||
@@ -493,9 +495,9 @@ static const FuncDef statInitFuncdef = {
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetterPost(
|
||||
Stat4Accum *pAccum,
|
||||
Stat4Sample *pNew,
|
||||
Stat4Sample *pOld
|
||||
StatAccum *pAccum,
|
||||
StatSample *pNew,
|
||||
StatSample *pOld
|
||||
){
|
||||
int nCol = pAccum->nCol;
|
||||
int i;
|
||||
@@ -517,9 +519,9 @@ static int sampleIsBetterPost(
|
||||
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
||||
*/
|
||||
static int sampleIsBetter(
|
||||
Stat4Accum *pAccum,
|
||||
Stat4Sample *pNew,
|
||||
Stat4Sample *pOld
|
||||
StatAccum *pAccum,
|
||||
StatSample *pNew,
|
||||
StatSample *pOld
|
||||
){
|
||||
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
|
||||
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
|
||||
@@ -539,21 +541,21 @@ static int sampleIsBetter(
|
||||
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
|
||||
** remove the least desirable sample from p->a[] to make room.
|
||||
*/
|
||||
static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
Stat4Sample *pSample = 0;
|
||||
static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
|
||||
StatSample *pSample = 0;
|
||||
int i;
|
||||
|
||||
assert( IsStat4 || nEqZero==0 );
|
||||
|
||||
/* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
||||
/* StatAccum.nMaxEqZero is set to the maximum number of leading 0
|
||||
** values in the anEq[] array of any sample in StatAccum.a[]. In
|
||||
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
||||
** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
|
||||
** are no samples with StatSample.anEq[m]==0 for (m>=n). */
|
||||
if( nEqZero>p->nMaxEqZero ){
|
||||
p->nMaxEqZero = nEqZero;
|
||||
}
|
||||
if( pNew->isPSample==0 ){
|
||||
Stat4Sample *pUpgrade = 0;
|
||||
StatSample *pUpgrade = 0;
|
||||
assert( pNew->anEq[pNew->iCol]>0 );
|
||||
|
||||
/* This sample is being added because the prefix that ends in column
|
||||
@@ -562,7 +564,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
** this one. Instead, upgrade the priority of the highest priority
|
||||
** existing sample that shares this prefix. */
|
||||
for(i=p->nSample-1; i>=0; i--){
|
||||
Stat4Sample *pOld = &p->a[i];
|
||||
StatSample *pOld = &p->a[i];
|
||||
if( pOld->anEq[pNew->iCol]==0 ){
|
||||
if( pOld->isPSample ) return;
|
||||
assert( pOld->iCol>pNew->iCol );
|
||||
@@ -581,7 +583,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
||||
|
||||
/* If necessary, remove sample iMin to make room for the new sample. */
|
||||
if( p->nSample>=p->mxSample ){
|
||||
Stat4Sample *pMin = &p->a[p->iMin];
|
||||
StatSample *pMin = &p->a[p->iMin];
|
||||
tRowcnt *anEq = pMin->anEq;
|
||||
tRowcnt *anLt = pMin->anLt;
|
||||
tRowcnt *anDLt = pMin->anDLt;
|
||||
@@ -624,20 +626,20 @@ find_new_min:
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/*
|
||||
** Field iChng of the index being scanned has changed. So at this point
|
||||
** p->current contains a sample that reflects the previous row of the
|
||||
** index. The value of anEq[iChng] and subsequent anEq[] elements are
|
||||
** correct at this point.
|
||||
*/
|
||||
static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
static void samplePushPrevious(StatAccum *p, int iChng){
|
||||
int i;
|
||||
|
||||
/* Check if any samples from the aBest[] array should be pushed
|
||||
** into IndexSample.a[] at this point. */
|
||||
for(i=(p->nCol-2); i>=iChng; i--){
|
||||
Stat4Sample *pBest = &p->aBest[i];
|
||||
StatSample *pBest = &p->aBest[i];
|
||||
pBest->anEq[i] = p->current.anEq[i];
|
||||
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
|
||||
sampleInsert(p, pBest, i);
|
||||
@@ -661,25 +663,20 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
||||
}
|
||||
p->nMaxEqZero = iChng;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_ENABLE_STAT4
|
||||
UNUSED_PARAMETER( p );
|
||||
UNUSED_PARAMETER( iChng );
|
||||
#endif
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_STAT4 */
|
||||
|
||||
/*
|
||||
** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
||||
** Arguments:
|
||||
**
|
||||
** P Pointer to the Stat4Accum object created by stat_init()
|
||||
** P Pointer to the StatAccum object created by stat_init()
|
||||
** C Index of left-most column to differ from previous row
|
||||
** R Rowid for the current row. Might be a key record for
|
||||
** WITHOUT ROWID tables.
|
||||
**
|
||||
** This SQL function always returns NULL. It's purpose it to accumulate
|
||||
** statistical data and/or samples in the Stat4Accum object about the
|
||||
** statistical data and/or samples in the StatAccum object about the
|
||||
** index being analyzed. The stat_get() SQL function will later be used to
|
||||
** extract relevant information for constructing the sqlite_statN tables.
|
||||
**
|
||||
@@ -693,7 +690,7 @@ static void statPush(
|
||||
int i;
|
||||
|
||||
/* The three function arguments */
|
||||
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
int iChng = sqlite3_value_int(argv[1]);
|
||||
|
||||
UNUSED_PARAMETER( argc );
|
||||
@@ -706,7 +703,9 @@ static void statPush(
|
||||
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
samplePushPrevious(p, iChng);
|
||||
#endif
|
||||
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
@@ -775,15 +774,15 @@ static const FuncDef statPushFuncdef = {
|
||||
/*
|
||||
** Implementation of the stat_get(P,J) SQL function. This routine is
|
||||
** used to query statistical information that has been gathered into
|
||||
** the Stat4Accum object by prior calls to stat_push(). The P parameter
|
||||
** has type BLOB but it is really just a pointer to the Stat4Accum object.
|
||||
** the StatAccum object by prior calls to stat_push(). The P parameter
|
||||
** has type BLOB but it is really just a pointer to the StatAccum object.
|
||||
** The content to returned is determined by the parameter J
|
||||
** which is one of the STAT_GET_xxxx values defined above.
|
||||
**
|
||||
** The stat_get(P,J) function is not available to generic SQL. It is
|
||||
** inserted as part of a manually constructed bytecode program. (See
|
||||
** the callStatGet() routine below.) It is guaranteed that the P
|
||||
** parameter will always be a poiner to a Stat4Accum object, never a
|
||||
** parameter will always be a pointer to a StatAccum object, never a
|
||||
** NULL.
|
||||
**
|
||||
** If STAT4 is not enabled, then J is always
|
||||
@@ -796,7 +795,7 @@ static void statGet(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
||||
StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
/* STAT4 has a parameter on this routine. */
|
||||
int eCall = sqlite3_value_int(argv[1]);
|
||||
@@ -817,7 +816,7 @@ static void statGet(
|
||||
** the index. The first integer in the list is the total number of
|
||||
** entries in the index. There is one additional integer in the list
|
||||
** for each indexed column. This additional integer is an estimate of
|
||||
** the number of rows matched by a stabbing query on the index using
|
||||
** the number of rows matched by a equality query on the index using
|
||||
** a key with the corresponding number of fields. In other words,
|
||||
** if the index is on columns (a,b) and the sqlite_stat1 value is
|
||||
** "100 10 2", then SQLite estimates that:
|
||||
@@ -860,7 +859,7 @@ static void statGet(
|
||||
p->iGet = 0;
|
||||
}
|
||||
if( p->iGet<p->nSample ){
|
||||
Stat4Sample *pS = p->a + p->iGet;
|
||||
StatSample *pS = p->a + p->iGet;
|
||||
if( pS->nRowid==0 ){
|
||||
sqlite3_result_int64(context, pS->u.iRowid);
|
||||
}else{
|
||||
@@ -916,18 +915,17 @@ static const FuncDef statGetFuncdef = {
|
||||
{0}
|
||||
};
|
||||
|
||||
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
|
||||
assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
||||
static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
|
||||
#elif SQLITE_DEBUG
|
||||
assert( iParam==STAT_GET_STAT1 );
|
||||
#else
|
||||
UNUSED_PARAMETER( iParam );
|
||||
#endif
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
|
||||
(char*)&statGetFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 1 + IsStat4);
|
||||
assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
|
||||
&statGetFuncdef, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -952,7 +950,7 @@ static void analyzeOneTable(
|
||||
int iDb; /* Index of database containing pTab */
|
||||
u8 needTableCnt = 1; /* True to count the table */
|
||||
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
||||
int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
||||
int regStat4 = iMem++; /* Register to hold StatAccum object */
|
||||
int regChng = iMem++; /* Index of changed index field */
|
||||
#ifdef SQLITE_ENABLE_STAT4
|
||||
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
||||
@@ -1095,9 +1093,8 @@ static void analyzeOneTable(
|
||||
#endif
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
|
||||
(char*)&statInitFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat4);
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
|
||||
&statInitFuncdef, 0);
|
||||
|
||||
/* Implementation of the following:
|
||||
**
|
||||
@@ -1182,7 +1179,7 @@ static void analyzeOneTable(
|
||||
int j, k, regKey;
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
|
||||
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pIdx->nColumn );
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
||||
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
||||
@@ -1192,13 +1189,12 @@ static void analyzeOneTable(
|
||||
}
|
||||
#endif
|
||||
assert( regChng==(regStat4+1) );
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
|
||||
(char*)&statPushFuncdef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, 2+IsStat4);
|
||||
sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
|
||||
&statPushFuncdef, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
||||
|
||||
/* Add the entry to the stat1 table. */
|
||||
callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
|
||||
callStatGet(pParse, regStat4, STAT_GET_STAT1, regStat1);
|
||||
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
@@ -1224,12 +1220,12 @@ static void analyzeOneTable(
|
||||
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
|
||||
|
||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
||||
callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
|
||||
callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
|
||||
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
|
||||
VdbeCoverage(v);
|
||||
callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
|
||||
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
|
||||
callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
|
||||
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
||||
VdbeCoverage(v);
|
||||
for(i=0; i<nCol; i++){
|
||||
|
||||
+26
-53
@@ -45,6 +45,17 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if zName points to a name that may be used to refer to
|
||||
** database iDb attached to handle db.
|
||||
*/
|
||||
int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
|
||||
return (
|
||||
sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0
|
||||
|| (iDb==0 && sqlite3StrICmp("main", zName)==0)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** An SQL user-function registered to do the work of an ATTACH statement. The
|
||||
** three arguments to the function come directly from an attach statement:
|
||||
@@ -117,9 +128,8 @@ static void attachFunc(
|
||||
goto attach_error;
|
||||
}
|
||||
for(i=0; i<db->nDb; i++){
|
||||
char *z = db->aDb[i].zDbSName;
|
||||
assert( z && zName );
|
||||
if( sqlite3StrICmp(z, zName)==0 ){
|
||||
assert( zName );
|
||||
if( sqlite3DbIsNamed(db, i, zName) ){
|
||||
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
|
||||
goto attach_error;
|
||||
}
|
||||
@@ -187,43 +197,7 @@ static void attachFunc(
|
||||
if( rc==SQLITE_OK && pNew->zDbSName==0 ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( rc==SQLITE_OK ){
|
||||
extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
||||
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
||||
int nKey;
|
||||
char *zKey;
|
||||
int t = sqlite3_value_type(argv[2]);
|
||||
switch( t ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
|
||||
case SQLITE_TEXT:
|
||||
case SQLITE_BLOB:
|
||||
nKey = sqlite3_value_bytes(argv[2]);
|
||||
zKey = (char *)sqlite3_value_blob(argv[2]);
|
||||
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
/* No key specified. Use the key from URI filename, or if none,
|
||||
** use the key from the main database. */
|
||||
if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
|
||||
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
||||
if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
|
||||
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sqlite3_free( zPath );
|
||||
sqlite3_free_filename( zPath );
|
||||
|
||||
/* If the file was opened successfully, read the schema for the new database.
|
||||
** If this fails, or if opening the file failed, then close the file and
|
||||
@@ -308,7 +282,7 @@ static void detachFunc(
|
||||
for(i=0; i<db->nDb; i++){
|
||||
pDb = &db->aDb[i];
|
||||
if( pDb->pBt==0 ) continue;
|
||||
if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
|
||||
if( sqlite3DbIsNamed(db, i, zName) ) break;
|
||||
}
|
||||
|
||||
if( i>=db->nDb ){
|
||||
@@ -401,11 +375,8 @@ static void codeAttach(
|
||||
|
||||
assert( v || db->mallocFailed );
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
|
||||
(char *)pFunc, P4_FUNCDEF);
|
||||
assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
|
||||
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
|
||||
|
||||
sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3,
|
||||
pFunc->nArg, pFunc, 0);
|
||||
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
|
||||
** statement only). For DETACH, set it to false (expire all existing
|
||||
** statements).
|
||||
@@ -480,7 +451,7 @@ void sqlite3FixInit(
|
||||
pFix->pSchema = db->aDb[iDb].pSchema;
|
||||
pFix->zType = zType;
|
||||
pFix->pName = pName;
|
||||
pFix->bVarOnly = (iDb==1);
|
||||
pFix->bTemp = (iDb==1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -502,22 +473,24 @@ int sqlite3FixSrcList(
|
||||
SrcList *pList /* The Source list to check and modify */
|
||||
){
|
||||
int i;
|
||||
const char *zDb;
|
||||
struct SrcList_item *pItem;
|
||||
sqlite3 *db = pFix->pParse->db;
|
||||
int iDb = sqlite3FindDbName(db, pFix->zDb);
|
||||
|
||||
if( NEVER(pList==0) ) return 0;
|
||||
zDb = pFix->zDb;
|
||||
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pFix->bVarOnly==0 ){
|
||||
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
|
||||
if( pFix->bTemp==0 ){
|
||||
if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
|
||||
sqlite3DbFree(db, pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
pItem->fg.fromDDL = 1;
|
||||
}
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
||||
@@ -573,7 +546,7 @@ int sqlite3FixExpr(
|
||||
Expr *pExpr /* The expression to be fixed to one database */
|
||||
){
|
||||
while( pExpr ){
|
||||
ExprSetProperty(pExpr, EP_Indirect);
|
||||
if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
|
||||
if( pExpr->op==TK_VARIABLE ){
|
||||
if( pFix->pParse->db->init.busy ){
|
||||
pExpr->op = TK_NULL;
|
||||
|
||||
@@ -235,13 +235,6 @@ static int backupOnePage(
|
||||
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
|
||||
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
|
||||
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
|
||||
** guaranteed that the shared-mutex is held by this thread, handle
|
||||
** p->pSrc may not actually be the owner. */
|
||||
int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
|
||||
int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
|
||||
#endif
|
||||
int rc = SQLITE_OK;
|
||||
i64 iOff;
|
||||
|
||||
@@ -258,26 +251,6 @@ static int backupOnePage(
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* Backup is not possible if the page size of the destination is changing
|
||||
** and a codec is in use.
|
||||
*/
|
||||
if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
/* Backup is not possible if the number of bytes of reserve space differ
|
||||
** between source and destination. If there is a difference, try to
|
||||
** fix the destination to agree with the source. If that is not possible,
|
||||
** then the backup cannot proceed.
|
||||
*/
|
||||
if( nSrcReserve!=nDestReserve ){
|
||||
u32 newPgsz = nSrcPgsz;
|
||||
rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
|
||||
if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This loop runs once for each destination page spanned by the source
|
||||
** page. For each iteration, variable iOff is set to the byte offset
|
||||
** of the destination page.
|
||||
@@ -773,10 +746,6 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
||||
b.pDest = pTo;
|
||||
b.iNext = 1;
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
|
||||
#endif
|
||||
|
||||
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
|
||||
** file. By passing this as the number of pages to copy to
|
||||
** sqlite3_backup_step(), we can guarantee that the copy finishes
|
||||
|
||||
+105
-47
@@ -611,7 +611,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
|
||||
*/
|
||||
static int btreeGetHasContent(BtShared *pBt, Pgno pgno){
|
||||
Bitvec *p = pBt->pHasContent;
|
||||
return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno)));
|
||||
return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -699,6 +699,9 @@ static int saveCursorPosition(BtCursor *pCur){
|
||||
assert( 0==pCur->pKey );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
|
||||
if( pCur->curFlags & BTCF_Pinned ){
|
||||
return SQLITE_CONSTRAINT_PINNED;
|
||||
}
|
||||
if( pCur->eState==CURSOR_SKIPNEXT ){
|
||||
pCur->eState = CURSOR_VALID;
|
||||
}else{
|
||||
@@ -1455,7 +1458,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
||||
sz += sz2;
|
||||
}else if( iFree+sz>usableSize ){
|
||||
}else if( NEVER(iFree+sz>usableSize) ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
|
||||
@@ -1647,8 +1650,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
|
||||
u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
|
||||
if( pSpace ){
|
||||
int g2;
|
||||
assert( pSpace+nByte<=data+pPage->pBt->usableSize );
|
||||
if( (*pIdx = (int)(pSpace-data))<=gap ){
|
||||
*pIdx = g2 = (int)(pSpace-data);
|
||||
if( NEVER(g2<=gap) ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}else{
|
||||
return SQLITE_OK;
|
||||
@@ -1726,12 +1731,12 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
}else{
|
||||
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
|
||||
if( iFreeBlk<iPtr+4 ){
|
||||
if( iFreeBlk==0 ) break;
|
||||
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iPtr = iFreeBlk;
|
||||
}
|
||||
if( iFreeBlk>pPage->pBt->usableSize-4 ){
|
||||
if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( iFreeBlk>iPtr || iFreeBlk==0 );
|
||||
@@ -1746,7 +1751,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
nFrag = iFreeBlk - iEnd;
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
||||
if( iEnd > pPage->pBt->usableSize ){
|
||||
if( NEVER(iEnd > pPage->pBt->usableSize) ){
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iSize = iEnd - iStart;
|
||||
@@ -1774,7 +1779,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
/* The new freeblock is at the beginning of the cell content area,
|
||||
** so just extend the cell content area rather than create another
|
||||
** freelist entry */
|
||||
if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
put2byte(&data[hdr+1], iFreeBlk);
|
||||
put2byte(&data[hdr+5], iEnd);
|
||||
}else{
|
||||
@@ -1894,7 +1900,7 @@ static int btreeComputeFreeSpace(MemPage *pPage){
|
||||
nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
|
||||
if( pc>0 ){
|
||||
u32 next, size;
|
||||
if( pc<iCellFirst ){
|
||||
if( pc<top ){
|
||||
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
||||
** always be at least one cell before the first freeblock.
|
||||
*/
|
||||
@@ -2131,12 +2137,12 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
|
||||
** error, return ((unsigned int)-1).
|
||||
*/
|
||||
static Pgno btreePagecount(BtShared *pBt){
|
||||
assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
|
||||
return pBt->nPage;
|
||||
}
|
||||
u32 sqlite3BtreeLastPage(Btree *p){
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
assert( ((p->pBt->nPage)&0x80000000)==0 );
|
||||
return btreePagecount(p->pBt);
|
||||
return btreePagecount(p->pBt) & 0x7fffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2403,9 +2409,13 @@ int sqlite3BtreeOpen(
|
||||
rc = sqlite3OsFullPathname(pVfs, zFilename,
|
||||
nFullPathname, zFullPathname);
|
||||
if( rc ){
|
||||
sqlite3_free(zFullPathname);
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
if( rc==SQLITE_OK_SYMLINK ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
sqlite3_free(zFullPathname);
|
||||
sqlite3_free(p);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SQLITE_THREADSAFE
|
||||
@@ -2847,11 +2857,11 @@ int sqlite3BtreeSetPagerFlags(
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
int rc = SQLITE_OK;
|
||||
BtShared *pBt = p->pBt;
|
||||
assert( nReserve>=-1 && nReserve<=255 );
|
||||
assert( nReserve>=-1 && nReserve<=254 );
|
||||
sqlite3BtreeEnter(p);
|
||||
#if SQLITE_HAS_CODEC
|
||||
if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
|
||||
#endif
|
||||
if( nReserve>=0 ){
|
||||
pBt->nReserveWanted = nReserve + 1;
|
||||
}
|
||||
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_READONLY;
|
||||
@@ -2903,18 +2913,12 @@ int sqlite3BtreeGetReserveNoMutex(Btree *p){
|
||||
** Return the number of bytes of space at the end of every page that
|
||||
** are intentually left unused. This is the "reserved" space that is
|
||||
** sometimes used by extensions.
|
||||
**
|
||||
** If SQLITE_HAS_MUTEX is defined then the number returned is the
|
||||
** greater of the current reserved space and the maximum requested
|
||||
** reserve space.
|
||||
*/
|
||||
int sqlite3BtreeGetOptimalReserve(Btree *p){
|
||||
int sqlite3BtreeGetRequestedReserve(Btree *p){
|
||||
int n;
|
||||
sqlite3BtreeEnter(p);
|
||||
n = sqlite3BtreeGetReserveNoMutex(p);
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
|
||||
#endif
|
||||
n = ((int)p->pBt->nReserveWanted) - 1;
|
||||
if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
|
||||
sqlite3BtreeLeave(p);
|
||||
return n;
|
||||
}
|
||||
@@ -4365,8 +4369,9 @@ static int btreeCursor(
|
||||
/* The following assert statements verify that if this is a sharable
|
||||
** b-tree database, the connection is holding the required table locks,
|
||||
** and that no other connection has any open cursor that conflicts with
|
||||
** this lock. */
|
||||
assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
|
||||
** this lock. The iTable<1 term disables the check for corrupt schemas. */
|
||||
assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1))
|
||||
|| iTable<1 );
|
||||
assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
|
||||
|
||||
/* Assert that the caller has opened the required transaction. */
|
||||
@@ -4379,9 +4384,13 @@ static int btreeCursor(
|
||||
allocateTempSpace(pBt);
|
||||
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
if( iTable==1 && btreePagecount(pBt)==0 ){
|
||||
assert( wrFlag==0 );
|
||||
iTable = 0;
|
||||
if( iTable<=1 ){
|
||||
if( iTable<1 ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}else if( btreePagecount(pBt)==0 ){
|
||||
assert( wrFlag==0 );
|
||||
iTable = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that no other errors can occur, finish filling in the BtCursor
|
||||
@@ -4406,6 +4415,19 @@ static int btreeCursor(
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
static int btreeCursorWithLock(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
int wrFlag, /* 1 to write. 0 read-only */
|
||||
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
||||
BtCursor *pCur /* Space for new cursor */
|
||||
){
|
||||
int rc;
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
int sqlite3BtreeCursor(
|
||||
Btree *p, /* The btree */
|
||||
int iTable, /* Root page of table to open */
|
||||
@@ -4413,15 +4435,11 @@ int sqlite3BtreeCursor(
|
||||
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
||||
BtCursor *pCur /* Write new cursor here */
|
||||
){
|
||||
int rc;
|
||||
if( iTable<1 ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
if( p->sharable ){
|
||||
return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur);
|
||||
}else{
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
|
||||
sqlite3BtreeLeave(p);
|
||||
return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4544,6 +4562,18 @@ i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
|
||||
return pCur->info.nKey;
|
||||
}
|
||||
|
||||
/*
|
||||
** Pin or unpin a cursor.
|
||||
*/
|
||||
void sqlite3BtreeCursorPin(BtCursor *pCur){
|
||||
assert( (pCur->curFlags & BTCF_Pinned)==0 );
|
||||
pCur->curFlags |= BTCF_Pinned;
|
||||
}
|
||||
void sqlite3BtreeCursorUnpin(BtCursor *pCur){
|
||||
assert( (pCur->curFlags & BTCF_Pinned)!=0 );
|
||||
pCur->curFlags &= ~BTCF_Pinned;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
/*
|
||||
** Return the offset into the database file for the start of the
|
||||
@@ -5700,8 +5730,11 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
|
||||
** to be invalid here. This can only occur if a second cursor modifies
|
||||
** the page while cursor pCur is holding a reference to it. Which can
|
||||
** only happen if the database is corrupt in such a way as to link the
|
||||
** page into more than one b-tree structure. */
|
||||
testcase( idx>pPage->nCell );
|
||||
** page into more than one b-tree structure.
|
||||
**
|
||||
** Update 2019-12-23: appears to long longer be possible after the
|
||||
** addition of anotherValidCursor() condition on balance_deeper(). */
|
||||
harmless( idx>pPage->nCell );
|
||||
|
||||
if( idx>=pPage->nCell ){
|
||||
if( !pPage->leaf ){
|
||||
@@ -6900,7 +6933,7 @@ static int rebuildPage(
|
||||
|
||||
assert( i<iEnd );
|
||||
j = get2byte(&aData[hdr+5]);
|
||||
if( j>(u32)usableSize ){ j = 0; }
|
||||
if( NEVER(j>(u32)usableSize) ){ j = 0; }
|
||||
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
||||
|
||||
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
||||
@@ -6926,7 +6959,7 @@ static int rebuildPage(
|
||||
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
|
||||
memcpy(pData, pCell, sz);
|
||||
assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
||||
testcase( sz!=pPg->xCellSize(pPg,pCell) );
|
||||
testcase( sz!=pPg->xCellSize(pPg,pCell) )
|
||||
i++;
|
||||
if( i>=iEnd ) break;
|
||||
if( pCArray->ixNx[k]<=i ){
|
||||
@@ -8290,6 +8323,30 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
|
||||
** on the same B-tree as pCur.
|
||||
**
|
||||
** This can if a database is corrupt with two or more SQL tables
|
||||
** pointing to the same b-tree. If an insert occurs on one SQL table
|
||||
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
|
||||
** table linked to the same b-tree. If the secondary insert causes a
|
||||
** rebalance, that can change content out from under the cursor on the
|
||||
** first SQL table, violating invariants on the first insert.
|
||||
*/
|
||||
static int anotherValidCursor(BtCursor *pCur){
|
||||
BtCursor *pOther;
|
||||
for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
|
||||
if( pOther!=pCur
|
||||
&& pOther->eState==CURSOR_VALID
|
||||
&& pOther->pPage==pCur->pPage
|
||||
){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The page that pCur currently points to has just been modified in
|
||||
** some way. This function figures out if this modification means the
|
||||
@@ -8317,7 +8374,7 @@ static int balance(BtCursor *pCur){
|
||||
if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
||||
break;
|
||||
}else if( (iPage = pCur->iPage)==0 ){
|
||||
if( pPage->nOverflow ){
|
||||
if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
|
||||
/* The root page of the b-tree is overfull. In this case call the
|
||||
** balance_deeper() function to create a new child for the root-page
|
||||
** and copy the current contents of the root-page to it. The
|
||||
@@ -8613,7 +8670,6 @@ int sqlite3BtreeInsert(
|
||||
if( flags & BTREE_SAVEPOSITION ){
|
||||
assert( pCur->curFlags & BTCF_ValidNKey );
|
||||
assert( pX->nKey==pCur->info.nKey );
|
||||
assert( pCur->info.nSize!=0 );
|
||||
assert( loc==0 );
|
||||
}
|
||||
#endif
|
||||
@@ -8688,7 +8744,9 @@ int sqlite3BtreeInsert(
|
||||
}
|
||||
|
||||
}
|
||||
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
|
||||
assert( pCur->eState==CURSOR_VALID
|
||||
|| (pCur->eState==CURSOR_INVALID && loc)
|
||||
|| CORRUPT_DB );
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage->intKey || pX->nKey>=0 );
|
||||
@@ -9472,7 +9530,7 @@ int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
||||
/* Unless an error occurs, the following loop runs one iteration for each
|
||||
** page in the B-Tree structure (not including overflow pages).
|
||||
*/
|
||||
while( rc==SQLITE_OK && !db->u1.isInterrupted ){
|
||||
while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){
|
||||
int iIdx; /* Index of child node in parent */
|
||||
MemPage *pPage; /* Current page of the b-tree */
|
||||
|
||||
@@ -9598,7 +9656,7 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){
|
||||
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
|
||||
return 1;
|
||||
}
|
||||
if( pCheck->db->u1.isInterrupted ) return 1;
|
||||
if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1;
|
||||
setPageReferenced(pCheck, iPage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-1
@@ -74,7 +74,7 @@ int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
u32 sqlite3BtreeLastPage(Btree*);
|
||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
int sqlite3BtreeGetOptimalReserve(Btree*);
|
||||
int sqlite3BtreeGetRequestedReserve(Btree*);
|
||||
int sqlite3BtreeGetReserveNoMutex(Btree *p);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
@@ -306,6 +306,8 @@ int sqlite3BtreeNext(BtCursor*, int flags);
|
||||
int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int flags);
|
||||
i64 sqlite3BtreeIntegerKey(BtCursor*);
|
||||
void sqlite3BtreeCursorPin(BtCursor*);
|
||||
void sqlite3BtreeCursorUnpin(BtCursor*);
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
i64 sqlite3BtreeOffset(BtCursor*);
|
||||
#endif
|
||||
|
||||
+2
-3
@@ -417,9 +417,7 @@ struct BtShared {
|
||||
#endif
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
u8 optimalReserve; /* Desired amount of reserved space per page */
|
||||
#endif
|
||||
u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
|
||||
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
|
||||
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
@@ -542,6 +540,7 @@ struct BtCursor {
|
||||
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
|
||||
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
|
||||
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
|
||||
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
|
||||
|
||||
/*
|
||||
** Potential values for BtCursor.eState.
|
||||
|
||||
+329
-62
@@ -315,7 +315,7 @@ Table *sqlite3FindTable(sqlite3 *db, const char *zName, const char *zDatabase){
|
||||
while(1){
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
|
||||
if( zDatabase==0 || sqlite3DbIsNamed(db, j, zDatabase) ){
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
||||
if( p ) return p;
|
||||
@@ -437,7 +437,7 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
Schema *pSchema = db->aDb[j].pSchema;
|
||||
assert( pSchema );
|
||||
if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
|
||||
if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
||||
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
||||
p = sqlite3HashFind(&pSchema->idxHash, zName);
|
||||
if( p ) break;
|
||||
@@ -590,6 +590,7 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
||||
assert( pTable!=0 );
|
||||
if( (pCol = pTable->aCol)!=0 ){
|
||||
for(i=0; i<pTable->nCol; i++, pCol++){
|
||||
assert( pCol->zName==0 || pCol->hName==sqlite3StrIHash(pCol->zName) );
|
||||
sqlite3DbFree(db, pCol->zName);
|
||||
sqlite3ExprDelete(db, pCol->pDflt);
|
||||
sqlite3DbFree(db, pCol->zColl);
|
||||
@@ -856,13 +857,14 @@ int sqlite3CheckObjectName(
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( pParse->nested==0
|
||||
&& 0==sqlite3StrNICmp(zName, "sqlite_", 7)
|
||||
if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
|
||||
|| (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s",
|
||||
zName);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -877,10 +879,12 @@ Index *sqlite3PrimaryKeyIndex(Table *pTab){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the column of index pIdx that corresponds to table
|
||||
** column iCol. Return -1 if not found.
|
||||
** Convert an table column number into a index column number. That is,
|
||||
** for the column iCol in the table (as defined by the CREATE TABLE statement)
|
||||
** find the (first) offset of that column in index pIdx. Or return -1
|
||||
** if column iCol is not used in index pIdx.
|
||||
*/
|
||||
i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
|
||||
i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
|
||||
int i;
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
if( iCol==pIdx->aiColumn[i] ) return i;
|
||||
@@ -888,6 +892,84 @@ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
/* Convert a storage column number into a table column number.
|
||||
**
|
||||
** The storage column number (0,1,2,....) is the index of the value
|
||||
** as it appears in the record on disk. The true column number
|
||||
** is the index (0,1,2,...) of the column in the CREATE TABLE statement.
|
||||
**
|
||||
** The storage column number is less than the table column number if
|
||||
** and only there are VIRTUAL columns to the left.
|
||||
**
|
||||
** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro.
|
||||
*/
|
||||
i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){
|
||||
if( pTab->tabFlags & TF_HasVirtual ){
|
||||
int i;
|
||||
for(i=0; i<=iCol; i++){
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++;
|
||||
}
|
||||
}
|
||||
return iCol;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
/* Convert a table column number into a storage column number.
|
||||
**
|
||||
** The storage column number (0,1,2,....) is the index of the value
|
||||
** as it appears in the record on disk. Or, if the input column is
|
||||
** the N-th virtual column (zero-based) then the storage number is
|
||||
** the number of non-virtual columns in the table plus N.
|
||||
**
|
||||
** The true column number is the index (0,1,2,...) of the column in
|
||||
** the CREATE TABLE statement.
|
||||
**
|
||||
** If the input column is a VIRTUAL column, then it should not appear
|
||||
** in storage. But the value sometimes is cached in registers that
|
||||
** follow the range of registers used to construct storage. This
|
||||
** avoids computing the same VIRTUAL column multiple times, and provides
|
||||
** values for use by OP_Param opcodes in triggers. Hence, if the
|
||||
** input column is a VIRTUAL table, put it after all the other columns.
|
||||
**
|
||||
** In the following, N means "normal column", S means STORED, and
|
||||
** V means VIRTUAL. Suppose the CREATE TABLE has columns like this:
|
||||
**
|
||||
** CREATE TABLE ex(N,S,V,N,S,V,N,S,V);
|
||||
** -- 0 1 2 3 4 5 6 7 8
|
||||
**
|
||||
** Then the mapping from this function is as follows:
|
||||
**
|
||||
** INPUTS: 0 1 2 3 4 5 6 7 8
|
||||
** OUTPUTS: 0 1 6 2 3 7 4 5 8
|
||||
**
|
||||
** So, in other words, this routine shifts all the virtual columns to
|
||||
** the end.
|
||||
**
|
||||
** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
|
||||
** this routine is a no-op macro. If the pTab does not have any virtual
|
||||
** columns, then this routine is no-op that always return iCol. If iCol
|
||||
** is negative (indicating the ROWID column) then this routine return iCol.
|
||||
*/
|
||||
i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
|
||||
int i;
|
||||
i16 n;
|
||||
assert( iCol<pTab->nCol );
|
||||
if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol;
|
||||
for(i=0, n=0; i<iCol; i++){
|
||||
if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++;
|
||||
}
|
||||
if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
|
||||
/* iCol is a virtual column itself */
|
||||
return pTab->nNVCol + i - n;
|
||||
}else{
|
||||
/* iCol is a normal or stored column */
|
||||
return n;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Begin constructing a new table representation in memory. This is
|
||||
** the first of several action routines that get called in response
|
||||
@@ -1157,6 +1239,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
pCol = &p->aCol[p->nCol];
|
||||
memset(pCol, 0, sizeof(p->aCol[0]));
|
||||
pCol->zName = z;
|
||||
pCol->hName = sqlite3StrIHash(z);
|
||||
sqlite3ColumnPropertiesFromName(p, pCol);
|
||||
|
||||
if( pType->n==0 ){
|
||||
@@ -1178,6 +1261,7 @@ void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
||||
pCol->colFlags |= COLFLAG_HASTYPE;
|
||||
}
|
||||
p->nCol++;
|
||||
p->nNVCol++;
|
||||
pParse->constraintName.n = 0;
|
||||
}
|
||||
|
||||
@@ -1322,10 +1406,17 @@ void sqlite3AddDefaultValue(
|
||||
sqlite3 *db = pParse->db;
|
||||
p = pParse->pNewTable;
|
||||
if( p!=0 ){
|
||||
int isInit = db->init.busy && db->init.iDb!=1;
|
||||
pCol = &(p->aCol[p->nCol-1]);
|
||||
if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){
|
||||
if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){
|
||||
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
||||
pCol->zName);
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
}else if( pCol->colFlags & COLFLAG_GENERATED ){
|
||||
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( pCol->colFlags & COLFLAG_STORED );
|
||||
sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");
|
||||
#endif
|
||||
}else{
|
||||
/* A copy of pExpr is used instead of the original, as pExpr contains
|
||||
** tokens that point to volatile memory.
|
||||
@@ -1371,6 +1462,21 @@ static void sqlite3StringToId(Expr *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Tag the given column as being part of the PRIMARY KEY
|
||||
*/
|
||||
static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( pCol->colFlags & COLFLAG_GENERATED ){
|
||||
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( pCol->colFlags & COLFLAG_STORED );
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"generated columns cannot be part of the PRIMARY KEY");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Designate the PRIMARY KEY for the table. pList is a list of names
|
||||
** of columns that form the primary key. If pList is NULL, then the
|
||||
@@ -1410,7 +1516,7 @@ void sqlite3AddPrimaryKey(
|
||||
if( pList==0 ){
|
||||
iCol = pTab->nCol - 1;
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
makeColumnPartOfPrimaryKey(pParse, pCol);
|
||||
nTerm = 1;
|
||||
}else{
|
||||
nTerm = pList->nExpr;
|
||||
@@ -1423,7 +1529,7 @@ void sqlite3AddPrimaryKey(
|
||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pCol->colFlags |= COLFLAG_PRIMKEY;
|
||||
makeColumnPartOfPrimaryKey(pParse, pCol);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1444,6 +1550,7 @@ void sqlite3AddPrimaryKey(
|
||||
assert( autoInc==0 || autoInc==1 );
|
||||
pTab->tabFlags |= autoInc*TF_Autoincrement;
|
||||
if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
|
||||
(void)sqlite3HasExplicitNulls(pParse, pList);
|
||||
}else if( autoInc ){
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
|
||||
@@ -1520,6 +1627,58 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
||||
}
|
||||
}
|
||||
|
||||
/* Change the most recently parsed column to be a GENERATED ALWAYS AS
|
||||
** column.
|
||||
*/
|
||||
void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
u8 eType = COLFLAG_VIRTUAL;
|
||||
Table *pTab = pParse->pNewTable;
|
||||
Column *pCol;
|
||||
if( pTab==0 ){
|
||||
/* generated column in an CREATE TABLE IF NOT EXISTS that already exists */
|
||||
goto generated_done;
|
||||
}
|
||||
pCol = &(pTab->aCol[pTab->nCol-1]);
|
||||
if( IN_DECLARE_VTAB ){
|
||||
sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
|
||||
goto generated_done;
|
||||
}
|
||||
if( pCol->pDflt ) goto generated_error;
|
||||
if( pType ){
|
||||
if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){
|
||||
/* no-op */
|
||||
}else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){
|
||||
eType = COLFLAG_STORED;
|
||||
}else{
|
||||
goto generated_error;
|
||||
}
|
||||
}
|
||||
if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--;
|
||||
pCol->colFlags |= eType;
|
||||
assert( TF_HasVirtual==COLFLAG_VIRTUAL );
|
||||
assert( TF_HasStored==COLFLAG_STORED );
|
||||
pTab->tabFlags |= eType;
|
||||
if( pCol->colFlags & COLFLAG_PRIMKEY ){
|
||||
makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
|
||||
}
|
||||
pCol->pDflt = pExpr;
|
||||
pExpr = 0;
|
||||
goto generated_done;
|
||||
|
||||
generated_error:
|
||||
sqlite3ErrorMsg(pParse, "error in generated column \"%s\"",
|
||||
pCol->zName);
|
||||
generated_done:
|
||||
sqlite3ExprDelete(pParse->db, pExpr);
|
||||
#else
|
||||
/* Throw and error for the GENERATED ALWAYS AS clause if the
|
||||
** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */
|
||||
sqlite3ErrorMsg(pParse, "generated columns not supported");
|
||||
sqlite3ExprDelete(pParse->db, pExpr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will increment the schema cookie.
|
||||
**
|
||||
@@ -1777,15 +1936,24 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
|
||||
** high-order bit of colNotIdxed is always 1. All unindexed columns
|
||||
** of the table have a 1.
|
||||
**
|
||||
** 2019-10-24: For the purpose of this computation, virtual columns are
|
||||
** not considered to be covered by the index, even if they are in the
|
||||
** index, because we do not trust the logic in whereIndexExprTrans() to be
|
||||
** able to find all instances of a reference to the indexed table column
|
||||
** and convert them into references to the index. Hence we always want
|
||||
** the actual table at hand in order to recompute the virtual column, if
|
||||
** necessary.
|
||||
**
|
||||
** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
|
||||
** to determine if the index is covering index.
|
||||
*/
|
||||
static void recomputeColumnsNotIndexed(Index *pIdx){
|
||||
Bitmask m = 0;
|
||||
int j;
|
||||
Table *pTab = pIdx->pTable;
|
||||
for(j=pIdx->nColumn-1; j>=0; j--){
|
||||
int x = pIdx->aiColumn[j];
|
||||
if( x>=0 ){
|
||||
if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
|
||||
testcase( x==BMS-1 );
|
||||
testcase( x==BMS-2 );
|
||||
if( x<BMS-1 ) m |= MASKBIT(x);
|
||||
@@ -1836,6 +2004,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
pTab->aCol[i].notNull = OE_Abort;
|
||||
}
|
||||
}
|
||||
pTab->tabFlags |= TF_HasNotNull;
|
||||
}
|
||||
|
||||
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
||||
@@ -1943,11 +2112,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
*/
|
||||
nExtra = 0;
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, nPk, i) ) nExtra++;
|
||||
if( !hasColumn(pPk->aiColumn, nPk, i)
|
||||
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
|
||||
}
|
||||
if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
|
||||
for(i=0, j=nPk; i<pTab->nCol; i++){
|
||||
if( !hasColumn(pPk->aiColumn, j, i) ){
|
||||
if( !hasColumn(pPk->aiColumn, j, i)
|
||||
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
|
||||
){
|
||||
assert( j<pPk->nColumn );
|
||||
pPk->aiColumn[j] = i;
|
||||
pPk->azColl[j] = sqlite3StrBINARY;
|
||||
@@ -1955,7 +2127,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
}
|
||||
}
|
||||
assert( pPk->nColumn==j );
|
||||
assert( pTab->nCol<=j );
|
||||
assert( pTab->nNVCol<=j );
|
||||
recomputeColumnsNotIndexed(pPk);
|
||||
}
|
||||
|
||||
@@ -1967,7 +2139,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
** zName is temporarily modified while this routine is running, but is
|
||||
** restored to its original value prior to this routine returning.
|
||||
*/
|
||||
static int isShadowTableName(sqlite3 *db, char *zName){
|
||||
int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
||||
char *zTail; /* Pointer to the last "_" in zName */
|
||||
Table *pTab; /* Table that zName is a shadow of */
|
||||
Module *pMod; /* Module for the virtual table */
|
||||
@@ -1985,10 +2157,34 @@ static int isShadowTableName(sqlite3 *db, char *zName){
|
||||
if( pMod->pModule->xShadowName==0 ) return 0;
|
||||
return pMod->pModule->xShadowName(zTail+1);
|
||||
}
|
||||
#else
|
||||
# define isShadowTableName(x,y) 0
|
||||
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Mark all nodes of an expression as EP_Immutable, indicating that
|
||||
** they should not be changed. Expressions attached to a table or
|
||||
** index definition are tagged this way to help ensure that we do
|
||||
** not pass them into code generator routines by mistake.
|
||||
*/
|
||||
static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
|
||||
ExprSetVVAProperty(pExpr, EP_Immutable);
|
||||
return WRC_Continue;
|
||||
}
|
||||
static void markExprListImmutable(ExprList *pList){
|
||||
if( pList ){
|
||||
Walker w;
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = markImmutableExprStep;
|
||||
w.xSelectCallback = sqlite3SelectWalkNoop;
|
||||
w.xSelectCallback2 = 0;
|
||||
sqlite3WalkExprList(&w, pList);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define markExprListImmutable(X) /* no-op */
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
|
||||
/*
|
||||
** This routine is called to report the final ")" that terminates
|
||||
** a CREATE TABLE statement.
|
||||
@@ -2028,7 +2224,7 @@ void sqlite3EndTable(
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 ) return;
|
||||
|
||||
if( pSelect==0 && isShadowTableName(db, p->zName) ){
|
||||
if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){
|
||||
p->tabFlags |= TF_Shadow;
|
||||
}
|
||||
|
||||
@@ -2064,12 +2260,11 @@ void sqlite3EndTable(
|
||||
}
|
||||
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
|
||||
}else{
|
||||
p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
|
||||
convertToWithoutRowidTable(pParse, p);
|
||||
return;
|
||||
}
|
||||
p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
|
||||
convertToWithoutRowidTable(pParse, p);
|
||||
}
|
||||
|
||||
iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
||||
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
@@ -2077,8 +2272,47 @@ void sqlite3EndTable(
|
||||
*/
|
||||
if( p->pCheck ){
|
||||
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
|
||||
if( pParse->nErr ){
|
||||
/* If errors are seen, delete the CHECK constraints now, else they might
|
||||
** actually be used if PRAGMA writable_schema=ON is set. */
|
||||
sqlite3ExprListDelete(db, p->pCheck);
|
||||
p->pCheck = 0;
|
||||
}else{
|
||||
markExprListImmutable(p->pCheck);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
if( p->tabFlags & TF_HasGenerated ){
|
||||
int ii, nNG = 0;
|
||||
testcase( p->tabFlags & TF_HasVirtual );
|
||||
testcase( p->tabFlags & TF_HasStored );
|
||||
for(ii=0; ii<p->nCol; ii++){
|
||||
u32 colFlags = p->aCol[ii].colFlags;
|
||||
if( (colFlags & COLFLAG_GENERATED)!=0 ){
|
||||
Expr *pX = p->aCol[ii].pDflt;
|
||||
testcase( colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( colFlags & COLFLAG_STORED );
|
||||
if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){
|
||||
/* If there are errors in resolving the expression, change the
|
||||
** expression to a NULL. This prevents code generators that operate
|
||||
** on the expression from inserting extra parts into the expression
|
||||
** tree that have been allocated from lookaside memory, which is
|
||||
** illegal in a schema and will lead to errors or heap corruption
|
||||
** when the database connection closes. */
|
||||
sqlite3ExprDelete(db, pX);
|
||||
p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
|
||||
}
|
||||
}else{
|
||||
nNG++;
|
||||
}
|
||||
}
|
||||
if( nNG==0 ){
|
||||
sqlite3ErrorMsg(pParse, "must have at least one non-generated column");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Estimate the average row size for the table and for all implied indices */
|
||||
estimateTableWidth(p);
|
||||
@@ -2155,7 +2389,7 @@ void sqlite3EndTable(
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB);
|
||||
if( pSelTab==0 ) return;
|
||||
assert( p->aCol==0 );
|
||||
p->nCol = pSelTab->nCol;
|
||||
p->nCol = p->nNVCol = pSelTab->nCol;
|
||||
p->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
@@ -2228,7 +2462,6 @@ void sqlite3EndTable(
|
||||
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
|
||||
}
|
||||
|
||||
|
||||
/* Add the table to the in-memory representation of the database.
|
||||
*/
|
||||
if( db->init.busy ){
|
||||
@@ -2299,6 +2532,7 @@ void sqlite3CreateView(
|
||||
** allocated rather than point to the input string - which means that
|
||||
** they will persist after the current sqlite3_exec() call returns.
|
||||
*/
|
||||
pSelect->selFlags |= SF_View;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
p->pSelect = pSelect;
|
||||
pSelect = 0;
|
||||
@@ -2422,7 +2656,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
|
||||
#endif
|
||||
pParse->nTab = n;
|
||||
if( pTable->pCheck ){
|
||||
if( pSelTab==0 ){
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
}else if( pTable->pCheck ){
|
||||
/* CREATE VIEW name(arglist) AS ...
|
||||
** The names of the columns in the table are taken from
|
||||
** arglist which is stored in pTable->pCheck. The pCheck field
|
||||
@@ -2438,7 +2675,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
|
||||
SQLITE_AFF_NONE);
|
||||
}
|
||||
}else if( pSelTab ){
|
||||
}else{
|
||||
/* CREATE VIEW name AS... without an argument list. Construct
|
||||
** the column names from the SELECT statement that defines the view.
|
||||
*/
|
||||
@@ -2448,10 +2685,8 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
}
|
||||
pTable->nNVCol = pTable->nCol;
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
EnableLookaside;
|
||||
@@ -2711,6 +2946,37 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
sqliteViewResetAll(db, iDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if shadow tables should be read-only in the current
|
||||
** context.
|
||||
*/
|
||||
int sqlite3ReadOnlyShadowTables(sqlite3 *db){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( (db->flags & SQLITE_Defensive)!=0
|
||||
&& db->pVtabCtx==0
|
||||
&& db->nVdbeExec==0
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if it is not allowed to drop the given table
|
||||
*/
|
||||
static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
|
||||
if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called to do the work of a DROP TABLE statement.
|
||||
** pName is the name of the table to be dropped.
|
||||
@@ -2780,9 +3046,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
||||
&& sqlite3StrNICmp(pTab->zName+7, "stat", 4)!=0
|
||||
&& sqlite3StrNICmp(pTab->zName+7, "parameters", 10)!=0 ){
|
||||
if( tableMayNotBeDropped(db, pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
|
||||
goto exit_drop_table;
|
||||
}
|
||||
@@ -2874,7 +3138,7 @@ void sqlite3CreateForeignKey(
|
||||
nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
||||
if( pToCol ){
|
||||
for(i=0; i<pToCol->nExpr; i++){
|
||||
nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1;
|
||||
nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
|
||||
}
|
||||
}
|
||||
pFKey = sqlite3DbMallocZero(db, nByte );
|
||||
@@ -2899,7 +3163,7 @@ void sqlite3CreateForeignKey(
|
||||
for(i=0; i<nCol; i++){
|
||||
int j;
|
||||
for(j=0; j<p->nCol; j++){
|
||||
if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
|
||||
if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){
|
||||
pFKey->aCol[i].iFrom = j;
|
||||
break;
|
||||
}
|
||||
@@ -2907,22 +3171,22 @@ void sqlite3CreateForeignKey(
|
||||
if( j>=p->nCol ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"unknown column \"%s\" in foreign key definition",
|
||||
pFromCol->a[i].zName);
|
||||
pFromCol->a[i].zEName);
|
||||
goto fk_end;
|
||||
}
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
|
||||
sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pToCol ){
|
||||
for(i=0; i<nCol; i++){
|
||||
int n = sqlite3Strlen30(pToCol->a[i].zName);
|
||||
int n = sqlite3Strlen30(pToCol->a[i].zEName);
|
||||
pFKey->aCol[i].zCol = z;
|
||||
if( IN_RENAME_OBJECT ){
|
||||
sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
|
||||
sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName);
|
||||
}
|
||||
memcpy(z, pToCol->a[i].zName, n);
|
||||
memcpy(z, pToCol->a[i].zEName, n);
|
||||
z[n] = 0;
|
||||
z += n+1;
|
||||
}
|
||||
@@ -3453,8 +3717,13 @@ void sqlite3CreateIndex(
|
||||
assert( j<=0x7fff );
|
||||
if( j<0 ){
|
||||
j = pTab->iPKey;
|
||||
}else if( pTab->aCol[j].notNull==0 ){
|
||||
pIndex->uniqNotNull = 0;
|
||||
}else{
|
||||
if( pTab->aCol[j].notNull==0 ){
|
||||
pIndex->uniqNotNull = 0;
|
||||
}
|
||||
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
|
||||
pIndex->bHasVCol = 1;
|
||||
}
|
||||
}
|
||||
pIndex->aiColumn[i] = (i16)j;
|
||||
}
|
||||
@@ -3509,13 +3778,13 @@ void sqlite3CreateIndex(
|
||||
/* If this index contains every column of its table, then mark
|
||||
** it as a covering index */
|
||||
assert( HasRowid(pTab)
|
||||
|| pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
|
||||
|| pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 );
|
||||
recomputeColumnsNotIndexed(pIndex);
|
||||
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
|
||||
pIndex->isCovering = 1;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
if( j==pTab->iPKey ) continue;
|
||||
if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
|
||||
if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue;
|
||||
pIndex->isCovering = 0;
|
||||
break;
|
||||
}
|
||||
@@ -3690,26 +3959,9 @@ void sqlite3CreateIndex(
|
||||
sqlite3VdbeJumpHere(v, pIndex->tnum);
|
||||
}
|
||||
}
|
||||
|
||||
/* When adding an index to the list of indices for a table, make
|
||||
** sure all indices labeled OE_Replace come after all those labeled
|
||||
** OE_Ignore. This is necessary for the correct constraint check
|
||||
** processing (in sqlite3GenerateConstraintChecks()) as part of
|
||||
** UPDATE and INSERT statements.
|
||||
*/
|
||||
if( db->init.busy || pTblName==0 ){
|
||||
if( onError!=OE_Replace || pTab->pIndex==0
|
||||
|| pTab->pIndex->onError==OE_Replace){
|
||||
pIndex->pNext = pTab->pIndex;
|
||||
pTab->pIndex = pIndex;
|
||||
}else{
|
||||
Index *pOther = pTab->pIndex;
|
||||
while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
|
||||
pOther = pOther->pNext;
|
||||
}
|
||||
pIndex->pNext = pOther->pNext;
|
||||
pOther->pNext = pIndex;
|
||||
}
|
||||
pIndex->pNext = pTab->pIndex;
|
||||
pTab->pIndex = pIndex;
|
||||
pIndex = 0;
|
||||
}
|
||||
else if( IN_RENAME_OBJECT ){
|
||||
@@ -3721,6 +3973,21 @@ void sqlite3CreateIndex(
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
if( pIndex ) sqlite3FreeIndex(db, pIndex);
|
||||
if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
|
||||
Index **ppFrom = &pTab->pIndex;
|
||||
Index *pThis;
|
||||
for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
|
||||
Index *pNext;
|
||||
if( pThis->onError!=OE_Replace ) continue;
|
||||
while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
|
||||
*ppFrom = pNext;
|
||||
pThis->pNext = pNext->pNext;
|
||||
pNext->pNext = pThis;
|
||||
ppFrom = &pNext->pNext;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3ExprDelete(db, pPIWhere);
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
sqlite3SrcListDelete(db, pTblName);
|
||||
|
||||
+21
-7
@@ -163,17 +163,30 @@ CollSeq *sqlite3FindCollSeq(
|
||||
int create /* True to create CollSeq if doesn't already exist */
|
||||
){
|
||||
CollSeq *pColl;
|
||||
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
||||
if( zName ){
|
||||
pColl = findCollSeqEntry(db, zName, create);
|
||||
if( pColl ) pColl += enc-1;
|
||||
}else{
|
||||
pColl = db->pDfltColl;
|
||||
}
|
||||
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
||||
if( pColl ) pColl += enc-1;
|
||||
return pColl;
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the text encoding for a database connection. This means that
|
||||
** the pDfltColl must change as well.
|
||||
*/
|
||||
void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
|
||||
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
||||
db->enc = enc;
|
||||
/* EVIDENCE-OF: R-08308-17224 The default collating function for all
|
||||
** strings is BINARY.
|
||||
*/
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is responsible for invoking the collation factory callback
|
||||
** or substituting a collation sequence of a different encoding when the
|
||||
@@ -288,12 +301,13 @@ static int matchQuality(
|
||||
u8 enc /* Desired text encoding */
|
||||
){
|
||||
int match;
|
||||
|
||||
/* nArg of -2 is a special case */
|
||||
if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
|
||||
assert( p->nArg>=-1 );
|
||||
|
||||
/* Wrong number of arguments means "no match" */
|
||||
if( p->nArg!=nArg && p->nArg>=0 ) return 0;
|
||||
if( p->nArg!=nArg ){
|
||||
if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
|
||||
if( p->nArg>=0 ) return 0;
|
||||
}
|
||||
|
||||
/* Give a better score to a function with a specific number of arguments
|
||||
** than to function that accepts any number of arguments. */
|
||||
|
||||
@@ -355,9 +355,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_FTS5_NO_WITHOUT_ROWID
|
||||
"FTS5_NO_WITHOUT_ROWID",
|
||||
#endif
|
||||
#if SQLITE_HAS_CODEC
|
||||
"HAS_CODEC",
|
||||
#endif
|
||||
#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
|
||||
"HAVE_ISNAN",
|
||||
#endif
|
||||
|
||||
+7
-7
@@ -621,12 +621,12 @@ static const struct {
|
||||
double rLimit; /* Maximum NNN value for this transform */
|
||||
double rXform; /* Constant used for this transform */
|
||||
} aXformType[] = {
|
||||
{ 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
|
||||
{ 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
|
||||
{ 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
|
||||
{ 0, 3, "day", 5373485.0, 86400000.0 },
|
||||
{ 1, 5, "month", 176546.0, 30.0*86400000.0 },
|
||||
{ 2, 4, "year", 14713.0, 365.0*86400000.0 },
|
||||
{ 0, 6, "second", 464269060800.0, 1000.0 },
|
||||
{ 0, 6, "minute", 7737817680.0, 60000.0 },
|
||||
{ 0, 4, "hour", 128963628.0, 3600000.0 },
|
||||
{ 0, 3, "day", 5373485.0, 86400000.0 },
|
||||
{ 1, 5, "month", 176546.0, 2592000000.0 },
|
||||
{ 2, 4, "year", 14713.0, 31536000000.0 },
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -688,7 +688,7 @@ static int parseModifier(
|
||||
r = p->s*1000.0 + 210866760000000.0;
|
||||
if( r>=0.0 && r<464269060800000.0 ){
|
||||
clearYMD_HMS_TZ(p);
|
||||
p->iJD = (sqlite3_int64)r;
|
||||
p->iJD = (sqlite3_int64)(r + 0.5);
|
||||
p->validJD = 1;
|
||||
p->rawS = 0;
|
||||
rc = 0;
|
||||
|
||||
@@ -73,6 +73,7 @@ static int dbpageConnect(
|
||||
DbpageTable *pTab = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
rc = sqlite3_declare_vtab(db,
|
||||
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
+238
-115
@@ -12,7 +12,7 @@
|
||||
**
|
||||
** This file contains an implementation of the "dbstat" virtual table.
|
||||
**
|
||||
** The dbstat virtual table is used to extract low-level formatting
|
||||
** The dbstat virtual table is used to extract low-level storage
|
||||
** information from an SQLite database in order to implement the
|
||||
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
|
||||
** for an example implementation.
|
||||
@@ -56,27 +56,30 @@
|
||||
**
|
||||
** '/1c2/000/' // Left-most child of 451st child of root
|
||||
*/
|
||||
#define VTAB_SCHEMA \
|
||||
"CREATE TABLE xx( " \
|
||||
" name TEXT, /* Name of table or index */" \
|
||||
" path TEXT, /* Path to page from root */" \
|
||||
" pageno INTEGER, /* Page number */" \
|
||||
" pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
|
||||
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
|
||||
" payload INTEGER, /* Bytes of payload on this page */" \
|
||||
" unused INTEGER, /* Bytes of unused space on this page */" \
|
||||
" mx_payload INTEGER, /* Largest payload size of all cells */" \
|
||||
" pgoffset INTEGER, /* Offset of page in file */" \
|
||||
" pgsize INTEGER, /* Size of the page */" \
|
||||
" schema TEXT HIDDEN /* Database schema being analyzed */" \
|
||||
");"
|
||||
|
||||
static const char zDbstatSchema[] =
|
||||
"CREATE TABLE x("
|
||||
" name TEXT," /* 0 Name of table or index */
|
||||
" path TEXT," /* 1 Path to page from root (NULL for agg) */
|
||||
" pageno INTEGER," /* 2 Page number (page count for aggregates) */
|
||||
" pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */
|
||||
" ncell INTEGER," /* 4 Cells on page (0 for overflow) */
|
||||
" payload INTEGER," /* 5 Bytes of payload on this page */
|
||||
" unused INTEGER," /* 6 Bytes of unused space on this page */
|
||||
" mx_payload INTEGER," /* 7 Largest payload size of all cells */
|
||||
" pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */
|
||||
" pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */
|
||||
" schema TEXT HIDDEN," /* 10 Database schema being analyzed */
|
||||
" aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */
|
||||
")"
|
||||
;
|
||||
|
||||
/* Forward reference to data structured used in this module */
|
||||
typedef struct StatTable StatTable;
|
||||
typedef struct StatCursor StatCursor;
|
||||
typedef struct StatPage StatPage;
|
||||
typedef struct StatCell StatCell;
|
||||
|
||||
/* Size information for a single cell within a btree page */
|
||||
struct StatCell {
|
||||
int nLocal; /* Bytes of local payload */
|
||||
u32 iChildPg; /* Child node (or 0 if this is a leaf) */
|
||||
@@ -86,10 +89,11 @@ struct StatCell {
|
||||
int iOvfl; /* Iterates through aOvfl[] */
|
||||
};
|
||||
|
||||
/* Size information for a single btree page */
|
||||
struct StatPage {
|
||||
u32 iPgno;
|
||||
DbPage *pPg;
|
||||
int iCell;
|
||||
u32 iPgno; /* Page number */
|
||||
DbPage *pPg; /* Page content */
|
||||
int iCell; /* Current cell */
|
||||
|
||||
char *zPath; /* Path to this page */
|
||||
|
||||
@@ -99,34 +103,38 @@ struct StatPage {
|
||||
int nUnused; /* Number of unused bytes on page */
|
||||
StatCell *aCell; /* Array of parsed cells */
|
||||
u32 iRightChildPg; /* Right-child page number (or 0) */
|
||||
int nMxPayload; /* Largest payload of any cell on this page */
|
||||
int nMxPayload; /* Largest payload of any cell on the page */
|
||||
};
|
||||
|
||||
/* The cursor for scanning the dbstat virtual table */
|
||||
struct StatCursor {
|
||||
sqlite3_vtab_cursor base;
|
||||
sqlite3_vtab_cursor base; /* base class. MUST BE FIRST! */
|
||||
sqlite3_stmt *pStmt; /* Iterates through set of root pages */
|
||||
int isEof; /* After pStmt has returned SQLITE_DONE */
|
||||
u8 isEof; /* After pStmt has returned SQLITE_DONE */
|
||||
u8 isAgg; /* Aggregate results for each table */
|
||||
int iDb; /* Schema used for this query */
|
||||
|
||||
StatPage aPage[32];
|
||||
StatPage aPage[32]; /* Pages in path to current page */
|
||||
int iPage; /* Current entry in aPage[] */
|
||||
|
||||
/* Values to return. */
|
||||
u32 iPageno; /* Value of 'pageno' column */
|
||||
char *zName; /* Value of 'name' column */
|
||||
char *zPath; /* Value of 'path' column */
|
||||
u32 iPageno; /* Value of 'pageno' column */
|
||||
char *zPagetype; /* Value of 'pagetype' column */
|
||||
int nPage; /* Number of pages in current btree */
|
||||
int nCell; /* Value of 'ncell' column */
|
||||
int nPayload; /* Value of 'payload' column */
|
||||
int nUnused; /* Value of 'unused' column */
|
||||
int nMxPayload; /* Value of 'mx_payload' column */
|
||||
i64 nUnused; /* Value of 'unused' column */
|
||||
i64 nPayload; /* Value of 'payload' column */
|
||||
i64 iOffset; /* Value of 'pgOffset' column */
|
||||
int szPage; /* Value of 'pgSize' column */
|
||||
i64 szPage; /* Value of 'pgSize' column */
|
||||
};
|
||||
|
||||
/* An instance of the DBSTAT virtual table */
|
||||
struct StatTable {
|
||||
sqlite3_vtab base;
|
||||
sqlite3 *db;
|
||||
sqlite3_vtab base; /* base class. MUST BE FIRST! */
|
||||
sqlite3 *db; /* Database connection that owns this vtab */
|
||||
int iDb; /* Index of database to analyze */
|
||||
};
|
||||
|
||||
@@ -135,7 +143,7 @@ struct StatTable {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Connect to or create a statvfs virtual table.
|
||||
** Connect to or create a new DBSTAT virtual table.
|
||||
*/
|
||||
static int statConnect(
|
||||
sqlite3 *db,
|
||||
@@ -159,7 +167,8 @@ static int statConnect(
|
||||
}else{
|
||||
iDb = 0;
|
||||
}
|
||||
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
|
||||
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
||||
rc = sqlite3_declare_vtab(db, zDbstatSchema);
|
||||
if( rc==SQLITE_OK ){
|
||||
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
|
||||
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
@@ -177,7 +186,7 @@ static int statConnect(
|
||||
}
|
||||
|
||||
/*
|
||||
** Disconnect from or destroy a statvfs virtual table.
|
||||
** Disconnect from or destroy the DBSTAT virtual table.
|
||||
*/
|
||||
static int statDisconnect(sqlite3_vtab *pVtab){
|
||||
sqlite3_free(pVtab);
|
||||
@@ -185,14 +194,20 @@ static int statDisconnect(sqlite3_vtab *pVtab){
|
||||
}
|
||||
|
||||
/*
|
||||
** There is no "best-index". This virtual table always does a linear
|
||||
** scan. However, a schema=? constraint should cause this table to
|
||||
** operate on a different database schema, so check for it.
|
||||
** Compute the best query strategy and return the result in idxNum.
|
||||
**
|
||||
** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
|
||||
** idxNum-Bit Meaning
|
||||
** ---------- ----------------------------------------------
|
||||
** 0x01 There is a schema=? term in the WHERE clause
|
||||
** 0x02 There is a name=? term in the WHERE clause
|
||||
** 0x04 There is an aggregate=? term in the WHERE clause
|
||||
** 0x08 Output should be ordered by name and path
|
||||
*/
|
||||
static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
int i;
|
||||
int iSchema = -1;
|
||||
int iName = -1;
|
||||
int iAgg = -1;
|
||||
|
||||
/* Look for a valid schema=? constraint. If found, change the idxNum to
|
||||
** 1 and request the value of that constraint be sent to xFilter. And
|
||||
@@ -200,16 +215,41 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
** used.
|
||||
*/
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++){
|
||||
if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
|
||||
if( pIdxInfo->aConstraint[i].usable==0 ) return SQLITE_CONSTRAINT;
|
||||
if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
|
||||
pIdxInfo->idxNum = 1;
|
||||
pIdxInfo->estimatedCost = 1.0;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
break;
|
||||
if( pIdxInfo->aConstraint[i].usable==0 ){
|
||||
/* Force DBSTAT table should always be the right-most table in a join */
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
switch( pIdxInfo->aConstraint[i].iColumn ){
|
||||
case 0: { /* name */
|
||||
iName = i;
|
||||
break;
|
||||
}
|
||||
case 10: { /* schema */
|
||||
iSchema = i;
|
||||
break;
|
||||
}
|
||||
case 11: { /* aggregate */
|
||||
iAgg = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
if( iSchema>=0 ){
|
||||
pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
|
||||
pIdxInfo->aConstraintUsage[iSchema].omit = 1;
|
||||
pIdxInfo->idxNum |= 0x01;
|
||||
}
|
||||
if( iName>=0 ){
|
||||
pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;
|
||||
pIdxInfo->idxNum |= 0x02;
|
||||
}
|
||||
if( iAgg>=0 ){
|
||||
pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;
|
||||
pIdxInfo->idxNum |= 0x04;
|
||||
}
|
||||
pIdxInfo->estimatedCost = 1.0;
|
||||
|
||||
/* Records are always returned in ascending order of (name, path).
|
||||
** If this will satisfy the client, set the orderByConsumed flag so that
|
||||
@@ -227,13 +267,14 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
)
|
||||
){
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
pIdxInfo->idxNum |= 0x08;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new statvfs cursor.
|
||||
** Open a new DBSTAT cursor.
|
||||
*/
|
||||
static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
StatTable *pTab = (StatTable *)pVTab;
|
||||
@@ -283,8 +324,18 @@ static void statResetCsr(StatCursor *pCsr){
|
||||
pCsr->isEof = 0;
|
||||
}
|
||||
|
||||
/* Resize the space-used counters inside of the cursor */
|
||||
static void statResetCounts(StatCursor *pCsr){
|
||||
pCsr->nCell = 0;
|
||||
pCsr->nMxPayload = 0;
|
||||
pCsr->nUnused = 0;
|
||||
pCsr->nPayload = 0;
|
||||
pCsr->szPage = 0;
|
||||
pCsr->nPage = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a statvfs cursor.
|
||||
** Close a DBSTAT cursor.
|
||||
*/
|
||||
static int statClose(sqlite3_vtab_cursor *pCursor){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
@@ -294,11 +345,15 @@ static int statClose(sqlite3_vtab_cursor *pCursor){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static void getLocalPayload(
|
||||
/*
|
||||
** For a single cell on a btree page, compute the number of bytes of
|
||||
** content (payload) stored on that page. That is to say, compute the
|
||||
** number of bytes of content not found on overflow pages.
|
||||
*/
|
||||
static int getLocalPayload(
|
||||
int nUsable, /* Usable bytes per page */
|
||||
u8 flags, /* Page flags */
|
||||
int nTotal, /* Total record (payload) size */
|
||||
int *pnLocal /* OUT: Bytes stored locally */
|
||||
int nTotal /* Total record (payload) size */
|
||||
){
|
||||
int nLocal;
|
||||
int nMinLocal;
|
||||
@@ -314,9 +369,12 @@ static void getLocalPayload(
|
||||
|
||||
nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
|
||||
if( nLocal>nMaxLocal ) nLocal = nMinLocal;
|
||||
*pnLocal = nLocal;
|
||||
return nLocal;
|
||||
}
|
||||
|
||||
/* Populate the StatPage object with information about the all
|
||||
** cells found on the page currently under analysis.
|
||||
*/
|
||||
static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
int nUnused;
|
||||
int iOff;
|
||||
@@ -387,7 +445,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
iOff += sqlite3GetVarint(&aData[iOff], &dummy);
|
||||
}
|
||||
if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
|
||||
getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
|
||||
nLocal = getLocalPayload(nUsable, p->flags, nPayload);
|
||||
if( nLocal<0 ) goto statPageIsCorrupt;
|
||||
pCell->nLocal = nLocal;
|
||||
assert( nPayload>=(u32)nLocal );
|
||||
@@ -395,7 +453,9 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
||||
if( nPayload>(u32)nLocal ){
|
||||
int j;
|
||||
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
|
||||
if( iOff+nLocal>nUsable ) goto statPageIsCorrupt;
|
||||
if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){
|
||||
goto statPageIsCorrupt;
|
||||
}
|
||||
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
|
||||
pCell->nOvfl = nOvfl;
|
||||
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
|
||||
@@ -437,23 +497,25 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
||||
sqlite3_file *fd;
|
||||
sqlite3_int64 x[2];
|
||||
|
||||
/* The default page size and offset */
|
||||
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
|
||||
pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
|
||||
|
||||
/* If connected to a ZIPVFS backend, override the page size and
|
||||
** offset with actual values obtained from ZIPVFS.
|
||||
/* If connected to a ZIPVFS backend, find the page size and
|
||||
** offset from ZIPVFS.
|
||||
*/
|
||||
fd = sqlite3PagerFile(pPager);
|
||||
x[0] = pCsr->iPageno;
|
||||
if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
|
||||
pCsr->iOffset = x[0];
|
||||
pCsr->szPage = (int)x[1];
|
||||
pCsr->szPage += x[1];
|
||||
}else{
|
||||
/* Not ZIPVFS: The default page size and offset */
|
||||
pCsr->szPage += sqlite3BtreeGetPageSize(pBt);
|
||||
pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Move a statvfs cursor to the next entry in the file.
|
||||
** Move a DBSTAT cursor to the next entry. Normally, the next
|
||||
** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
|
||||
** the next entry is the next btree.
|
||||
*/
|
||||
static int statNext(sqlite3_vtab_cursor *pCursor){
|
||||
int rc;
|
||||
@@ -469,6 +531,8 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
||||
|
||||
statNextRestart:
|
||||
if( pCsr->aPage[0].pPg==0 ){
|
||||
/* Start measuring space on the next btree */
|
||||
statResetCounts(pCsr);
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
int nPage;
|
||||
@@ -481,44 +545,47 @@ statNextRestart:
|
||||
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
|
||||
pCsr->aPage[0].iPgno = iRoot;
|
||||
pCsr->aPage[0].iCell = 0;
|
||||
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
|
||||
if( !pCsr->isAgg ){
|
||||
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
pCsr->iPage = 0;
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
pCsr->nPage = 1;
|
||||
}else{
|
||||
pCsr->isEof = 1;
|
||||
return sqlite3_reset(pCsr->pStmt);
|
||||
}
|
||||
}else{
|
||||
|
||||
/* Page p itself has already been visited. */
|
||||
/* Continue analyzing the btree previously started */
|
||||
StatPage *p = &pCsr->aPage[pCsr->iPage];
|
||||
|
||||
if( !pCsr->isAgg ) statResetCounts(pCsr);
|
||||
while( p->iCell<p->nCell ){
|
||||
StatCell *pCell = &p->aCell[p->iCell];
|
||||
if( pCell->iOvfl<pCell->nOvfl ){
|
||||
int nUsable;
|
||||
while( pCell->iOvfl<pCell->nOvfl ){
|
||||
int nUsable, iOvfl;
|
||||
sqlite3BtreeEnter(pBt);
|
||||
nUsable = sqlite3BtreeGetPageSize(pBt) -
|
||||
sqlite3BtreeGetReserveNoMutex(pBt);
|
||||
sqlite3BtreeLeave(pBt);
|
||||
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
|
||||
pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
|
||||
pCsr->zPagetype = "overflow";
|
||||
pCsr->nCell = 0;
|
||||
pCsr->nMxPayload = 0;
|
||||
pCsr->zPath = z = sqlite3_mprintf(
|
||||
"%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
|
||||
);
|
||||
if( pCell->iOvfl<pCell->nOvfl-1 ){
|
||||
pCsr->nUnused = 0;
|
||||
pCsr->nPayload = nUsable - 4;
|
||||
}else{
|
||||
pCsr->nPayload = pCell->nLastOvfl;
|
||||
pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
|
||||
}
|
||||
pCell->iOvfl++;
|
||||
pCsr->nPage++;
|
||||
statSizeAndOffset(pCsr);
|
||||
return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
|
||||
if( pCell->iOvfl<pCell->nOvfl-1 ){
|
||||
pCsr->nPayload += nUsable - 4;
|
||||
}else{
|
||||
pCsr->nPayload += pCell->nLastOvfl;
|
||||
pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl;
|
||||
}
|
||||
iOvfl = pCell->iOvfl;
|
||||
pCell->iOvfl++;
|
||||
if( !pCsr->isAgg ){
|
||||
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
|
||||
pCsr->iPageno = pCell->aOvfl[iOvfl];
|
||||
pCsr->zPagetype = "overflow";
|
||||
pCsr->zPath = z = sqlite3_mprintf(
|
||||
"%s%.3x+%.6x", p->zPath, p->iCell, iOvfl
|
||||
);
|
||||
return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
|
||||
}
|
||||
}
|
||||
if( p->iRightChildPg ) break;
|
||||
p->iCell++;
|
||||
@@ -526,8 +593,13 @@ statNextRestart:
|
||||
|
||||
if( !p->iRightChildPg || p->iCell>p->nCell ){
|
||||
statClearPage(p);
|
||||
if( pCsr->iPage==0 ) return statNext(pCursor);
|
||||
pCsr->iPage--;
|
||||
if( pCsr->iPage>0 ){
|
||||
pCsr->iPage--;
|
||||
}else if( pCsr->isAgg ){
|
||||
/* label-statNext-done: When computing aggregate space usage over
|
||||
** an entire btree, this is the exit point from this function */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
goto statNextRestart; /* Tail recursion */
|
||||
}
|
||||
pCsr->iPage++;
|
||||
@@ -543,10 +615,13 @@ statNextRestart:
|
||||
p[1].iPgno = p->aCell[p->iCell].iChildPg;
|
||||
}
|
||||
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
|
||||
pCsr->nPage++;
|
||||
p[1].iCell = 0;
|
||||
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
|
||||
if( !pCsr->isAgg ){
|
||||
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
p->iCell++;
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
|
||||
|
||||
@@ -576,16 +651,23 @@ statNextRestart:
|
||||
pCsr->zPagetype = "corrupted";
|
||||
break;
|
||||
}
|
||||
pCsr->nCell = p->nCell;
|
||||
pCsr->nUnused = p->nUnused;
|
||||
pCsr->nMxPayload = p->nMxPayload;
|
||||
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
pCsr->nCell += p->nCell;
|
||||
pCsr->nUnused += p->nUnused;
|
||||
if( p->nMxPayload>pCsr->nMxPayload ) pCsr->nMxPayload = p->nMxPayload;
|
||||
if( !pCsr->isAgg ){
|
||||
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
|
||||
if( z==0 ) rc = SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
nPayload = 0;
|
||||
for(i=0; i<p->nCell; i++){
|
||||
nPayload += p->aCell[i].nLocal;
|
||||
}
|
||||
pCsr->nPayload = nPayload;
|
||||
pCsr->nPayload += nPayload;
|
||||
|
||||
/* If computing aggregate space usage by btree, continue with the
|
||||
** next page. The loop will exit via the return at label-statNext-done
|
||||
*/
|
||||
if( pCsr->isAgg ) goto statNextRestart;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,6 +679,10 @@ static int statEof(sqlite3_vtab_cursor *pCursor){
|
||||
return pCsr->isEof;
|
||||
}
|
||||
|
||||
/* Initialize a cursor according to the query plan idxNum using the
|
||||
** arguments in argv[0]. See statBestIndex() for a description of the
|
||||
** meaning of the bits in idxNum.
|
||||
*/
|
||||
static int statFilter(
|
||||
sqlite3_vtab_cursor *pCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
@@ -604,29 +690,52 @@ static int statFilter(
|
||||
){
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
StatTable *pTab = (StatTable*)(pCursor->pVtab);
|
||||
char *zSql;
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_str *pSql; /* Query of btrees to analyze */
|
||||
char *zSql; /* String value of pSql */
|
||||
int iArg = 0; /* Count of argv[] parameters used so far */
|
||||
int rc = SQLITE_OK; /* Result of this operation */
|
||||
const char *zName = 0; /* Only provide analysis of this table */
|
||||
|
||||
if( idxNum==1 ){
|
||||
const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
|
||||
statResetCsr(pCsr);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
if( idxNum & 0x01 ){
|
||||
/* schema=? constraint is present. Get its value */
|
||||
const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
|
||||
pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
|
||||
if( pCsr->iDb<0 ){
|
||||
sqlite3_free(pCursor->pVtab->zErrMsg);
|
||||
pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
|
||||
return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
|
||||
pCsr->iDb = 0;
|
||||
pCsr->isEof = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}else{
|
||||
pCsr->iDb = pTab->iDb;
|
||||
}
|
||||
statResetCsr(pCsr);
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
|
||||
" UNION ALL "
|
||||
"SELECT name, rootpage, type"
|
||||
" FROM \"%w\".sqlite_master WHERE rootpage!=0"
|
||||
" ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName);
|
||||
if( idxNum & 0x02 ){
|
||||
/* name=? constraint is present */
|
||||
zName = (const char*)sqlite3_value_text(argv[iArg++]);
|
||||
}
|
||||
if( idxNum & 0x04 ){
|
||||
/* aggregate=? constraint is present */
|
||||
pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0;
|
||||
}else{
|
||||
pCsr->isAgg = 0;
|
||||
}
|
||||
pSql = sqlite3_str_new(pTab->db);
|
||||
sqlite3_str_appendf(pSql,
|
||||
"SELECT * FROM ("
|
||||
"SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
|
||||
" UNION ALL "
|
||||
"SELECT name,rootpage,type"
|
||||
" FROM \"%w\".sqlite_master WHERE rootpage!=0)",
|
||||
pTab->db->aDb[pCsr->iDb].zDbSName);
|
||||
if( zName ){
|
||||
sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
|
||||
}
|
||||
if( idxNum & 0x08 ){
|
||||
sqlite3_str_appendf(pSql, " ORDER BY name");
|
||||
}
|
||||
zSql = sqlite3_str_finish(pSql);
|
||||
if( zSql==0 ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}else{
|
||||
@@ -651,13 +760,21 @@ static int statColumn(
|
||||
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
|
||||
break;
|
||||
case 1: /* path */
|
||||
sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
|
||||
if( !pCsr->isAgg ){
|
||||
sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case 2: /* pageno */
|
||||
sqlite3_result_int64(ctx, pCsr->iPageno);
|
||||
if( pCsr->isAgg ){
|
||||
sqlite3_result_int64(ctx, pCsr->nPage);
|
||||
}else{
|
||||
sqlite3_result_int64(ctx, pCsr->iPageno);
|
||||
}
|
||||
break;
|
||||
case 3: /* pagetype */
|
||||
sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
|
||||
if( !pCsr->isAgg ){
|
||||
sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
case 4: /* ncell */
|
||||
sqlite3_result_int(ctx, pCsr->nCell);
|
||||
@@ -672,17 +789,23 @@ static int statColumn(
|
||||
sqlite3_result_int(ctx, pCsr->nMxPayload);
|
||||
break;
|
||||
case 8: /* pgoffset */
|
||||
sqlite3_result_int64(ctx, pCsr->iOffset);
|
||||
if( !pCsr->isAgg ){
|
||||
sqlite3_result_int64(ctx, pCsr->iOffset);
|
||||
}
|
||||
break;
|
||||
case 9: /* pgsize */
|
||||
sqlite3_result_int(ctx, pCsr->szPage);
|
||||
break;
|
||||
default: { /* schema */
|
||||
case 10: { /* schema */
|
||||
sqlite3 *db = sqlite3_context_db_handle(ctx);
|
||||
int iDb = pCsr->iDb;
|
||||
sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
default: { /* aggregate */
|
||||
sqlite3_result_int(ctx, pCsr->isAgg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
+8
-7
@@ -70,11 +70,7 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
|
||||
return sqlite3WritableSchema(db)==0 && pParse->nested==0;
|
||||
}
|
||||
assert( pTab->tabFlags & TF_Shadow );
|
||||
return (db->flags & SQLITE_Defensive)!=0
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
&& db->pVtabCtx==0
|
||||
#endif
|
||||
&& db->nVdbeExec==0;
|
||||
return sqlite3ReadOnlyShadowTables(db);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -537,7 +533,9 @@ void sqlite3DeleteFrom(
|
||||
iTabCur, aToOpen, &iDataCur, &iIdxCur);
|
||||
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
|
||||
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
|
||||
if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
|
||||
if( eOnePass==ONEPASS_MULTI ){
|
||||
sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up a loop over the rowids/primary-keys that were found in the
|
||||
@@ -737,7 +735,8 @@ void sqlite3GenerateRowDelete(
|
||||
testcase( mask!=0xffffffff && iCol==31 );
|
||||
testcase( mask!=0xffffffff && iCol==32 );
|
||||
if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
|
||||
int kk = sqlite3TableColumnToStorage(pTab, iCol);
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,6 +916,8 @@ int sqlite3GenerateIndexKey(
|
||||
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
pParse->iSelfTab = 0;
|
||||
pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02;
|
||||
** pPartIdxWhere may have corrupted regPrior registers */
|
||||
}else{
|
||||
*piPartIdxLabel = 0;
|
||||
}
|
||||
|
||||
+542
-235
File diff suppressed because it is too large
Load Diff
+25
-9
@@ -349,7 +349,7 @@ static void fkLookupParent(
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
int iReg = aiCol[i] + regData + 1;
|
||||
int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
@@ -365,7 +365,8 @@ static void fkLookupParent(
|
||||
** is no matching parent key. Before using MustBeInt, make a copy of
|
||||
** the value. Otherwise, the value inserted into the child key column
|
||||
** will have INTEGER affinity applied to it, which may not be correct. */
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy,
|
||||
sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp);
|
||||
iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
|
||||
VdbeCoverage(v);
|
||||
|
||||
@@ -392,7 +393,9 @@ static void fkLookupParent(
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
|
||||
sqlite3VdbeAddOp2(v, OP_Copy,
|
||||
sqlite3TableColumnToStorage(pFKey->pFrom, aiCol[i])+1+regData,
|
||||
regTemp+i);
|
||||
}
|
||||
|
||||
/* If the parent table is the same as the child table, and we are about
|
||||
@@ -408,8 +411,11 @@ static void fkLookupParent(
|
||||
if( pTab==pFKey->pFrom && nIncr==1 ){
|
||||
int iJump = sqlite3VdbeCurrentAddr(v) + nCol + 1;
|
||||
for(i=0; i<nCol; i++){
|
||||
int iChild = aiCol[i]+1+regData;
|
||||
int iParent = pIdx->aiColumn[i]+1+regData;
|
||||
int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i])
|
||||
+1+regData;
|
||||
int iParent = 1+regData;
|
||||
iParent += sqlite3TableColumnToStorage(pIdx->pTable,
|
||||
pIdx->aiColumn[i]);
|
||||
assert( pIdx->aiColumn[i]>=0 );
|
||||
assert( aiCol[i]!=pTab->iPKey );
|
||||
if( pIdx->aiColumn[i]==pTab->iPKey ){
|
||||
@@ -477,7 +483,7 @@ static Expr *exprTableRegister(
|
||||
if( pExpr ){
|
||||
if( iCol>=0 && iCol!=pTab->iPKey ){
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pExpr->iTable = regBase + iCol + 1;
|
||||
pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
|
||||
pExpr->affExpr = pCol->affinity;
|
||||
zColl = pCol->zColl;
|
||||
if( zColl==0 ) zColl = db->pDfltColl->zName;
|
||||
@@ -652,7 +658,7 @@ static void fkScanChildren(
|
||||
/* Clean up the WHERE clause constructed above. */
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
if( iFkIfZero ){
|
||||
sqlite3VdbeJumpHere(v, iFkIfZero);
|
||||
sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,7 +932,9 @@ void sqlite3FkCheck(
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1;
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
int iReg = pFKey->aCol[i].iFrom + regOld + 1;
|
||||
int iFromCol, iReg;
|
||||
iFromCol = pFKey->aCol[i].iFrom;
|
||||
iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1);
|
||||
@@ -1261,7 +1269,15 @@ static Trigger *fkActionTrigger(
|
||||
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
||||
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
|
||||
}else if( action==OE_SetDflt ){
|
||||
Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
|
||||
Column *pCol = pFKey->pFrom->aCol + iFromCol;
|
||||
Expr *pDflt;
|
||||
if( pCol->colFlags & COLFLAG_GENERATED ){
|
||||
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
|
||||
testcase( pCol->colFlags & COLFLAG_STORED );
|
||||
pDflt = 0;
|
||||
}else{
|
||||
pDflt = pCol->pDflt;
|
||||
}
|
||||
if( pDflt ){
|
||||
pNew = sqlite3ExprDup(db, pDflt, 0);
|
||||
}else{
|
||||
|
||||
+41
-104
@@ -16,7 +16,9 @@
|
||||
#include "sqliteInt.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
#include <math.h>
|
||||
#endif
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
@@ -851,6 +853,7 @@ static void likeFunc(
|
||||
int nPat;
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
struct compareInfo *pInfo = sqlite3_user_data(context);
|
||||
struct compareInfo backupInfo;
|
||||
|
||||
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
|
||||
@@ -886,6 +889,12 @@ static void likeFunc(
|
||||
return;
|
||||
}
|
||||
escape = sqlite3Utf8Read(&zEsc);
|
||||
if( escape==pInfo->matchAll || escape==pInfo->matchOne ){
|
||||
memcpy(&backupInfo, pInfo, sizeof(backupInfo));
|
||||
pInfo = &backupInfo;
|
||||
if( escape==pInfo->matchAll ) pInfo->matchAll = 0;
|
||||
if( escape==pInfo->matchOne ) pInfo->matchOne = 0;
|
||||
}
|
||||
}else{
|
||||
escape = pInfo->matchSet;
|
||||
}
|
||||
@@ -1802,88 +1811,6 @@ static void groupConcatValue(sqlite3_context *context){
|
||||
# define groupConcatValue 0
|
||||
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
||||
|
||||
/*
|
||||
** The uuid_blob() function. Interpret the argument as a RFC 4122 UUID string.
|
||||
** Return a blob representing the parsed UUID.
|
||||
*/
|
||||
static void uuidBlob(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int h, i, j = 0, rc = SQLITE_ERROR;
|
||||
unsigned char parsed[16];
|
||||
const char *zHex;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
zHex = sqlite3_value_text(argv[0]);
|
||||
if( sqlite3_value_bytes(argv[0])==36 ){
|
||||
for (i=0, h = zHex[i]; i <= 36; i++, h=zHex[i]) {
|
||||
if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
|
||||
if( h !='-' ){
|
||||
break;
|
||||
}
|
||||
}else if (i==36 && h==0 ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
if( (h<'0' || h>'9')&&(h<'a'||h>'f')&&(h<'A'||h>'F') ){
|
||||
break;
|
||||
}
|
||||
if( j%2 ){
|
||||
parsed[j++ / 2] |= sqlite3HexToInt(h);
|
||||
}else{
|
||||
parsed[j++ / 2] = sqlite3HexToInt(h) << 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc ){
|
||||
sqlite3_result_error(context, "parameter is not a valid UUID", -1);
|
||||
return;
|
||||
}else{
|
||||
sqlite3_result_blob(context, parsed, sizeof(parsed), SQLITE_TRANSIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The uuid_string() function. Argument must be a 128-bit blob. Return a
|
||||
** RFC 4122 string representation of the blob.
|
||||
*/
|
||||
static void uuidString(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i, n;
|
||||
const unsigned char *pBlob;
|
||||
char *zHex, *z;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
pBlob = sqlite3_value_blob(argv[0]);
|
||||
n = sqlite3_value_bytes(argv[0]);
|
||||
if( n>16 ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
return;
|
||||
}
|
||||
if( n<16 ){
|
||||
sqlite3_result_error(context, "parameter too small to print as UUID", -1);
|
||||
return;
|
||||
}
|
||||
z = zHex = contextMalloc(context, 36);
|
||||
if( zHex ){
|
||||
for(i=0; i<16; i++, pBlob++){
|
||||
unsigned char c = *pBlob;
|
||||
*(z++) = hexdigits[(c>>4)&0xf];
|
||||
*(z++) = hexdigits[c&0xf];
|
||||
if( i==3||i==5||i==7||i==9 ){
|
||||
*(z++) = '-';
|
||||
}
|
||||
}
|
||||
sqlite3_result_text(context, zHex, 36, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine does per-connection function registration. Most
|
||||
** of the built-in functions above are part of the global function set.
|
||||
@@ -1944,19 +1871,12 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
nExpr = pExpr->x.pList->nExpr;
|
||||
pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
|
||||
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
if( pDef==0 ) return 0;
|
||||
#endif
|
||||
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
|
||||
return 0;
|
||||
}
|
||||
if( nExpr<3 ){
|
||||
aWc[3] = 0;
|
||||
}else{
|
||||
Expr *pEscape = pExpr->x.pList->a[2].pExpr;
|
||||
char *zEscape;
|
||||
if( pEscape->op!=TK_STRING ) return 0;
|
||||
zEscape = pEscape->u.zToken;
|
||||
if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
|
||||
aWc[3] = zEscape[0];
|
||||
}
|
||||
|
||||
/* The memcpy() statement assumes that the wildcard characters are
|
||||
** the first three statements in the compareInfo structure. The
|
||||
@@ -1966,6 +1886,20 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
||||
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
||||
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
||||
|
||||
if( nExpr<3 ){
|
||||
aWc[3] = 0;
|
||||
}else{
|
||||
Expr *pEscape = pExpr->x.pList->a[2].pExpr;
|
||||
char *zEscape;
|
||||
if( pEscape->op!=TK_STRING ) return 0;
|
||||
zEscape = pEscape->u.zToken;
|
||||
if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
|
||||
if( zEscape[0]==aWc[0] ) return 0;
|
||||
if( zEscape[0]==aWc[1] ) return 0;
|
||||
aWc[3] = zEscape[0];
|
||||
}
|
||||
|
||||
*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1989,14 +1923,20 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
** For peak efficiency, put the most frequently used function last.
|
||||
*/
|
||||
static FuncDef aBuiltinFunc[] = {
|
||||
FUNCTION(uuid_str, 1, 0, 0, uuidString),
|
||||
FUNCTION(uuid_blob, 1, 0, 0, uuidBlob),
|
||||
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
|
||||
TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
|
||||
TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
|
||||
TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
|
||||
#ifdef SQLITE_DEBUG
|
||||
TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
|
||||
#endif
|
||||
/***** Regular functions *****/
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
||||
VFUNCTION(load_extension, 1, 0, 0, loadExt ),
|
||||
VFUNCTION(load_extension, 2, 0, 0, loadExt ),
|
||||
SFUNCTION(load_extension, 1, 0, 0, loadExt ),
|
||||
SFUNCTION(load_extension, 2, 0, 0, loadExt ),
|
||||
#endif
|
||||
#if SQLITE_USER_AUTHENTICATION
|
||||
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
|
||||
@@ -2005,12 +1945,9 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
|
||||
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
#ifdef SQLITE_DEBUG
|
||||
FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY),
|
||||
#endif
|
||||
INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
||||
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
|
||||
SQLITE_FUNC_TYPEOF),
|
||||
@@ -2043,7 +1980,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION(upper, 1, 0, 0, upperFunc ),
|
||||
FUNCTION(lower, 1, 0, 0, lowerFunc ),
|
||||
FUNCTION(hex, 1, 0, 0, hexFunc ),
|
||||
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
VFUNCTION(random, 0, 0, 0, randomFunc ),
|
||||
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
@@ -2083,7 +2020,7 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
#endif
|
||||
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
||||
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
||||
FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
||||
};
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
sqlite3AlterFunctions();
|
||||
|
||||
+11
-12
@@ -87,7 +87,6 @@ const unsigned char sqlite3UpperToLower[] = {
|
||||
** non-ASCII UTF character. Hence the test for whether or not a character is
|
||||
** part of an identifier is 0x46.
|
||||
*/
|
||||
#ifdef SQLITE_ASCII
|
||||
const unsigned char sqlite3CtypeMap[256] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
|
||||
@@ -125,7 +124,6 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
|
||||
** compatibility for legacy applications, the URI filename capability is
|
||||
@@ -137,16 +135,9 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
|
||||
** disabled. The default value may be changed by compiling with the
|
||||
** SQLITE_USE_URI symbol defined.
|
||||
**
|
||||
** URI filenames are enabled by default if SQLITE_HAS_CODEC is
|
||||
** enabled.
|
||||
*/
|
||||
#ifndef SQLITE_USE_URI
|
||||
# ifdef SQLITE_HAS_CODEC
|
||||
# define SQLITE_USE_URI 1
|
||||
# else
|
||||
# define SQLITE_USE_URI 0
|
||||
# endif
|
||||
# define SQLITE_USE_URI 0
|
||||
#endif
|
||||
|
||||
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
|
||||
@@ -190,9 +181,18 @@ const unsigned char sqlite3CtypeMap[256] = {
|
||||
** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
|
||||
** or at run-time for an individual database connection using
|
||||
** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
|
||||
**
|
||||
** With the two-size-lookaside enhancement, less lookaside is required.
|
||||
** The default configuration of 1200,40 actually provides 30 1200-byte slots
|
||||
** and 93 128-byte slots, which is more lookaside than is available
|
||||
** using the older 1200,100 configuration without two-size-lookaside.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_LOOKASIDE
|
||||
# define SQLITE_DEFAULT_LOOKASIDE 1200,100
|
||||
# ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
||||
# define SQLITE_DEFAULT_LOOKASIDE 1200,100 /* 120KB of memory */
|
||||
# else
|
||||
# define SQLITE_DEFAULT_LOOKASIDE 1200,40 /* 48KB of memory */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -258,7 +258,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* xTestCallback */
|
||||
#endif
|
||||
0, /* bLocaltimeFault */
|
||||
0, /* bInternalFunctions */
|
||||
0x7ffffffe, /* iOnceResetThreshold */
|
||||
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
|
||||
0, /* iPrngSeed */
|
||||
|
||||
+12
-12
@@ -11,7 +11,7 @@
|
||||
******************************************************************************
|
||||
**
|
||||
** This file contains inline asm code for retrieving "high-performance"
|
||||
** counters for x86 class CPUs.
|
||||
** counters for x86 and x86_64 class CPUs.
|
||||
*/
|
||||
#ifndef SQLITE_HWTIME_H
|
||||
#define SQLITE_HWTIME_H
|
||||
@@ -22,8 +22,9 @@
|
||||
** processor and returns that value. This can be used for high-res
|
||||
** profiling.
|
||||
*/
|
||||
#if (defined(__GNUC__) || defined(_MSC_VER)) && \
|
||||
(defined(i386) || defined(__i386__) || defined(_M_IX86))
|
||||
#if !defined(__STRICT_ANSI__) && \
|
||||
(defined(__GNUC__) || defined(_MSC_VER)) && \
|
||||
(defined(i386) || defined(__i386__) || defined(_M_IX86))
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
@@ -44,7 +45,7 @@
|
||||
|
||||
#endif
|
||||
|
||||
#elif (defined(__GNUC__) && defined(__x86_64__))
|
||||
#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
||||
|
||||
__inline__ sqlite_uint64 sqlite3Hwtime(void){
|
||||
unsigned long val;
|
||||
@@ -52,7 +53,7 @@
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif (defined(__GNUC__) && defined(__ppc__))
|
||||
#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
||||
|
||||
__inline__ sqlite_uint64 sqlite3Hwtime(void){
|
||||
unsigned long long retval;
|
||||
@@ -69,14 +70,13 @@
|
||||
|
||||
#else
|
||||
|
||||
#error Need implementation of sqlite3Hwtime() for your platform.
|
||||
|
||||
/*
|
||||
** To compile without implementing sqlite3Hwtime() for your platform,
|
||||
** you can remove the above #error and use the following
|
||||
** stub function. You will lose timing support for many
|
||||
** of the debugging and testing utilities, but it should at
|
||||
** least compile and run.
|
||||
** asm() is needed for hardware timing support. Without asm(),
|
||||
** disable the sqlite3Hwtime() routine.
|
||||
**
|
||||
** sqlite3Hwtime() is only used for some obscure debugging
|
||||
** and analysis configurations, not in any deliverable, so this
|
||||
** should not be a great loss.
|
||||
*/
|
||||
sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
||||
|
||||
|
||||
+573
-169
File diff suppressed because it is too large
Load Diff
@@ -468,6 +468,16 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
/* Version 3.31.0 and later */
|
||||
sqlite3_hard_heap_limit64,
|
||||
sqlite3_uri_key,
|
||||
sqlite3_filename_database,
|
||||
sqlite3_filename_journal,
|
||||
sqlite3_filename_wal,
|
||||
/* Version 3.32.0 and later */
|
||||
sqlite3_create_filename,
|
||||
sqlite3_free_filename,
|
||||
sqlite3_database_file_object,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+254
-89
@@ -161,7 +161,10 @@ int sqlite3_initialize(void){
|
||||
** must be complete. So isInit must not be set until the very end
|
||||
** of this routine.
|
||||
*/
|
||||
if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
|
||||
if( sqlite3GlobalConfig.isInit ){
|
||||
sqlite3MemoryBarrier();
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Make sure the mutex subsystem is initialized. If unable to
|
||||
** initialize the mutex subsystem, return early with the error.
|
||||
@@ -683,6 +686,9 @@ int sqlite3_config(int op, ...){
|
||||
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
||||
#ifndef SQLITE_OMIT_LOOKASIDE
|
||||
void *pStart;
|
||||
sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
|
||||
int nBig; /* Number of full-size slots */
|
||||
int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
|
||||
|
||||
if( sqlite3LookasideUsed(db,0)>0 ){
|
||||
return SQLITE_BUSY;
|
||||
@@ -705,12 +711,27 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
||||
pStart = 0;
|
||||
}else if( pBuf==0 ){
|
||||
sqlite3BeginBenignMalloc();
|
||||
pStart = sqlite3Malloc( sz*(sqlite3_int64)cnt ); /* IMP: R-61949-35727 */
|
||||
pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */
|
||||
sqlite3EndBenignMalloc();
|
||||
if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
|
||||
if( pStart ) szAlloc = sqlite3MallocSize(pStart);
|
||||
}else{
|
||||
pStart = pBuf;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
||||
if( sz>=LOOKASIDE_SMALL*3 ){
|
||||
nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
|
||||
nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
|
||||
}else if( sz>=LOOKASIDE_SMALL*2 ){
|
||||
nBig = szAlloc/(LOOKASIDE_SMALL+sz);
|
||||
nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
||||
if( sz>0 ){
|
||||
nBig = szAlloc/sz;
|
||||
nSm = 0;
|
||||
}else{
|
||||
nBig = nSm = 0;
|
||||
}
|
||||
db->lookaside.pStart = pStart;
|
||||
db->lookaside.pInit = 0;
|
||||
db->lookaside.pFree = 0;
|
||||
@@ -720,24 +741,41 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
||||
int i;
|
||||
LookasideSlot *p;
|
||||
assert( sz > (int)sizeof(LookasideSlot*) );
|
||||
db->lookaside.nSlot = cnt;
|
||||
p = (LookasideSlot*)pStart;
|
||||
for(i=cnt-1; i>=0; i--){
|
||||
for(i=0; i<nBig; i++){
|
||||
p->pNext = db->lookaside.pInit;
|
||||
db->lookaside.pInit = p;
|
||||
p = (LookasideSlot*)&((u8*)p)[sz];
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
||||
db->lookaside.pSmallInit = 0;
|
||||
db->lookaside.pSmallFree = 0;
|
||||
db->lookaside.pMiddle = p;
|
||||
for(i=0; i<nSm; i++){
|
||||
p->pNext = db->lookaside.pSmallInit;
|
||||
db->lookaside.pSmallInit = p;
|
||||
p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL];
|
||||
}
|
||||
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
||||
assert( ((uptr)p)<=szAlloc + (uptr)pStart );
|
||||
db->lookaside.pEnd = p;
|
||||
db->lookaside.bDisable = 0;
|
||||
db->lookaside.bMalloced = pBuf==0 ?1:0;
|
||||
db->lookaside.nSlot = nBig+nSm;
|
||||
}else{
|
||||
db->lookaside.pStart = db;
|
||||
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
||||
db->lookaside.pSmallInit = 0;
|
||||
db->lookaside.pSmallFree = 0;
|
||||
db->lookaside.pMiddle = db;
|
||||
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
||||
db->lookaside.pEnd = db;
|
||||
db->lookaside.bDisable = 1;
|
||||
db->lookaside.sz = 0;
|
||||
db->lookaside.bMalloced = 0;
|
||||
db->lookaside.nSlot = 0;
|
||||
}
|
||||
assert( sqlite3LookasideUsed(db,0)==0 );
|
||||
#endif /* SQLITE_OMIT_LOOKASIDE */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -851,6 +889,8 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
|
||||
{ SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter },
|
||||
{ SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL },
|
||||
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
|
||||
{ SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
|
||||
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
|
||||
};
|
||||
unsigned int i;
|
||||
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
|
||||
@@ -1389,6 +1429,7 @@ const char *sqlite3ErrName(int rc){
|
||||
case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
|
||||
case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
|
||||
case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break;
|
||||
case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; break;
|
||||
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
|
||||
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
|
||||
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
|
||||
@@ -1528,9 +1569,21 @@ static int sqliteDefaultBusyCallback(
|
||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||
if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
|
||||
if( count ){
|
||||
tmout = 0;
|
||||
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
|
||||
return 0;
|
||||
/* If this is the second or later invocation of the busy-handler,
|
||||
** but tmout==0, then code in wal.c must have disabled the blocking
|
||||
** lock before the SQLITE_BUSY error was hit. In this case, no delay
|
||||
** occurred while waiting for the lock, so fall through to the xSleep()
|
||||
** code below to delay a while before retrying the lock.
|
||||
**
|
||||
** Alternatively, if tmout!=0, then SQLite has already waited
|
||||
** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
|
||||
** indicate that the lock should not be retried and the SQLITE_BUSY
|
||||
** error returned to the application. */
|
||||
if( tmout ){
|
||||
tmout = 0;
|
||||
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
return 1;
|
||||
}
|
||||
@@ -1680,7 +1733,7 @@ void sqlite3_interrupt(sqlite3 *db){
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
db->u1.isInterrupted = 1;
|
||||
AtomicStore(&db->u1.isInterrupted, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1721,8 +1774,15 @@ int sqlite3CreateFunc(
|
||||
|
||||
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
|
||||
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
|
||||
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|SQLITE_SUBTYPE);
|
||||
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
|
||||
SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
|
||||
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
|
||||
|
||||
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
|
||||
** the meaning is inverted. So flip the bit. */
|
||||
assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
|
||||
extraFlags ^= SQLITE_FUNC_UNSAFE;
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
||||
@@ -1736,11 +1796,13 @@ int sqlite3CreateFunc(
|
||||
enc = SQLITE_UTF16NATIVE;
|
||||
}else if( enc==SQLITE_ANY ){
|
||||
int rc;
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
|
||||
(SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
|
||||
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
|
||||
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
||||
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
|
||||
(SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
|
||||
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@@ -2293,7 +2355,7 @@ int sqlite3_wal_checkpoint_v2(
|
||||
/* If there are no active statements, clear the interrupt flag at this
|
||||
** point. */
|
||||
if( db->nVdbeActive==0 ){
|
||||
db->u1.isInterrupted = 0;
|
||||
AtomicStore(&db->u1.isInterrupted, 0);
|
||||
}
|
||||
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
@@ -2703,9 +2765,11 @@ int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
||||
**
|
||||
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
|
||||
** the VFS that should be used to open the database file. *pzFile is set to
|
||||
** point to a buffer containing the name of the file to open. It is the
|
||||
** responsibility of the caller to eventually call sqlite3_free() to release
|
||||
** this buffer.
|
||||
** point to a buffer containing the name of the file to open. The value
|
||||
** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter()
|
||||
** and is in the same format as names created using sqlite3_create_filename().
|
||||
** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on
|
||||
** the value returned in *pzFile to avoid a memory leak.
|
||||
**
|
||||
** If an error occurs, then an SQLite error code is returned and *pzErrMsg
|
||||
** may be set to point to a buffer containing an English language error
|
||||
@@ -2737,7 +2801,7 @@ int sqlite3ParseUri(
|
||||
int eState; /* Parser state when parsing URI */
|
||||
int iIn; /* Input character index */
|
||||
int iOut = 0; /* Output character index */
|
||||
u64 nByte = nUri+2; /* Bytes of space to allocate */
|
||||
u64 nByte = nUri+8; /* Bytes of space to allocate */
|
||||
|
||||
/* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
|
||||
** method that there may be extra parameters following the file-name. */
|
||||
@@ -2747,6 +2811,9 @@ int sqlite3ParseUri(
|
||||
zFile = sqlite3_malloc64(nByte);
|
||||
if( !zFile ) return SQLITE_NOMEM_BKPT;
|
||||
|
||||
memset(zFile, 0, 4); /* 4-byte of 0x00 is the start of DB name marker */
|
||||
zFile += 4;
|
||||
|
||||
iIn = 5;
|
||||
#ifdef SQLITE_ALLOW_URI_AUTHORITY
|
||||
if( strncmp(zUri+5, "///", 3)==0 ){
|
||||
@@ -2836,8 +2903,7 @@ int sqlite3ParseUri(
|
||||
zFile[iOut++] = c;
|
||||
}
|
||||
if( eState==1 ) zFile[iOut++] = '\0';
|
||||
zFile[iOut++] = '\0';
|
||||
zFile[iOut++] = '\0';
|
||||
memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */
|
||||
|
||||
/* Check if there were any options specified that should be interpreted
|
||||
** here. Options that are interpreted here include "vfs" and those that
|
||||
@@ -2917,13 +2983,14 @@ int sqlite3ParseUri(
|
||||
}
|
||||
|
||||
}else{
|
||||
zFile = sqlite3_malloc64(nUri+2);
|
||||
zFile = sqlite3_malloc64(nUri+8);
|
||||
if( !zFile ) return SQLITE_NOMEM_BKPT;
|
||||
memset(zFile, 0, 4);
|
||||
zFile += 4;
|
||||
if( nUri ){
|
||||
memcpy(zFile, zUri, nUri);
|
||||
}
|
||||
zFile[nUri] = '\0';
|
||||
zFile[nUri+1] = '\0';
|
||||
memset(zFile+nUri, 0, 4);
|
||||
flags &= ~SQLITE_OPEN_URI;
|
||||
}
|
||||
|
||||
@@ -2934,7 +3001,7 @@ int sqlite3ParseUri(
|
||||
}
|
||||
parse_uri_out:
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(zFile);
|
||||
sqlite3_free_filename(zFile);
|
||||
zFile = 0;
|
||||
}
|
||||
*pFlags = flags;
|
||||
@@ -2942,39 +3009,21 @@ int sqlite3ParseUri(
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
/*
|
||||
** Process URI filename query parameters relevant to the SQLite Encryption
|
||||
** Extension. Return true if any of the relevant query parameters are
|
||||
** seen and return false if not.
|
||||
** This routine does the core work of extracting URI parameters from a
|
||||
** database filename for the sqlite3_uri_parameter() interface.
|
||||
*/
|
||||
int sqlite3CodecQueryParameters(
|
||||
sqlite3 *db, /* Database connection */
|
||||
const char *zDb, /* Which schema is being created/attached */
|
||||
const char *zUri /* URI filename */
|
||||
){
|
||||
const char *zKey;
|
||||
if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){
|
||||
u8 iByte;
|
||||
int i;
|
||||
char zDecoded[40];
|
||||
for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
|
||||
iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
|
||||
if( (i&1)!=0 ) zDecoded[i/2] = iByte;
|
||||
}
|
||||
sqlite3_key_v2(db, zDb, zDecoded, i/2);
|
||||
return 1;
|
||||
}else if( (zKey = sqlite3_uri_parameter(zUri, "key"))!=0 ){
|
||||
sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
|
||||
return 1;
|
||||
}else if( (zKey = sqlite3_uri_parameter(zUri, "textkey"))!=0 ){
|
||||
sqlite3_key_v2(db, zDb, zKey, -1);
|
||||
return 1;
|
||||
}else{
|
||||
return 0;
|
||||
static const char *uriParameter(const char *zFilename, const char *zParam){
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
while( zFilename[0] ){
|
||||
int x = strcmp(zFilename, zParam);
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
if( x==0 ) return zFilename;
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ -3080,7 +3129,9 @@ static int openDatabase(
|
||||
| SQLITE_EnableTrigger
|
||||
| SQLITE_EnableView
|
||||
| SQLITE_CacheSpill
|
||||
|
||||
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
|
||||
| SQLITE_TrustedSchema
|
||||
#endif
|
||||
/* The SQLITE_DQS compile-time option determines the default settings
|
||||
** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
|
||||
**
|
||||
@@ -3160,11 +3211,6 @@ static int openDatabase(
|
||||
if( db->mallocFailed ){
|
||||
goto opendb_out;
|
||||
}
|
||||
/* EVIDENCE-OF: R-08308-17224 The default collating function for all
|
||||
** strings is BINARY.
|
||||
*/
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
|
||||
assert( db->pDfltColl!=0 );
|
||||
|
||||
/* Parse the filename/URI argument
|
||||
**
|
||||
@@ -3209,7 +3255,9 @@ static int openDatabase(
|
||||
}
|
||||
sqlite3BtreeEnter(db->aDb[0].pBt);
|
||||
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
|
||||
if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
|
||||
if( !db->mallocFailed ){
|
||||
sqlite3SetTextEncoding(db, SCHEMA_ENC(db));
|
||||
}
|
||||
sqlite3BtreeLeave(db->aDb[0].pBt);
|
||||
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
|
||||
|
||||
@@ -3310,6 +3358,13 @@ static int openDatabase(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
|
||||
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
|
||||
** option gives access to internal functions by default.
|
||||
** Testing use only!!! */
|
||||
db->mDbFlags |= DBFLAG_InternalFunc;
|
||||
#endif
|
||||
|
||||
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
|
||||
** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
|
||||
** mode. Doing nothing at all also makes NORMAL the default.
|
||||
@@ -3350,10 +3405,7 @@ opendb_out:
|
||||
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
|
||||
}
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC)
|
||||
if( rc==SQLITE_OK ) sqlite3CodecQueryParameters(db, 0, zOpen);
|
||||
#endif
|
||||
sqlite3_free(zOpen);
|
||||
sqlite3_free_filename(zOpen);
|
||||
return rc & 0xff;
|
||||
}
|
||||
|
||||
@@ -3580,13 +3632,15 @@ int sqlite3CantopenError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
|
||||
int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
|
||||
char zMsg[100];
|
||||
sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3NomemError(int lineno){
|
||||
testcase( sqlite3GlobalConfig.xLog!=0 );
|
||||
return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
|
||||
@@ -3789,6 +3843,13 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
|
||||
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
|
||||
rc = SQLITE_OK;
|
||||
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
|
||||
int iNew = *(int*)pArg;
|
||||
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
|
||||
if( iNew>=0 && iNew<=254 ){
|
||||
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
|
||||
}
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}
|
||||
@@ -3848,6 +3909,7 @@ int sqlite3_test_control(int op, ...){
|
||||
** This test-control also resets the PRNG so that the new seed will
|
||||
** be used for the next call to sqlite3_randomness().
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
case SQLITE_TESTCTRL_PRNG_SEED: {
|
||||
int x = va_arg(ap, int);
|
||||
int y;
|
||||
@@ -3858,6 +3920,7 @@ int sqlite3_test_control(int op, ...){
|
||||
sqlite3_randomness(0,0);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** sqlite3_test_control(BITVEC_TEST, size, program)
|
||||
@@ -4003,20 +4066,6 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
|
||||
**
|
||||
** Set the nReserve size to N for the main database on the database
|
||||
** connection db.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_RESERVE: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
int x = va_arg(ap,int);
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
|
||||
**
|
||||
** Enable or disable various optimizations for testing purposes. The
|
||||
@@ -4042,15 +4091,14 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCS, int onoff);
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
|
||||
**
|
||||
** If parameter onoff is non-zero, internal-use-only SQL functions
|
||||
** are visible to ordinary SQL. This is useful for testing but is
|
||||
** unsafe because invalid parameters to those internal-use-only functions
|
||||
** can result in crashes or segfaults.
|
||||
** Toggle the ability to use internal functions on or off for
|
||||
** the database connection given in the argument.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
|
||||
sqlite3GlobalConfig.bInternalFunctions = va_arg(ap, int);
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
db->mDbFlags ^= DBFLAG_InternalFunc;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4186,6 +4234,83 @@ int sqlite3_test_control(int op, ...){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** The Pager stores the Database filename, Journal filename, and WAL filename
|
||||
** consecutively in memory, in that order. The database filename is prefixed
|
||||
** by four zero bytes. Locate the start of the database filename by searching
|
||||
** backwards for the first byte following four consecutive zero bytes.
|
||||
**
|
||||
** This only works if the filename passed in was obtained from the Pager.
|
||||
*/
|
||||
static const char *databaseName(const char *zName){
|
||||
while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
|
||||
zName--;
|
||||
}
|
||||
return zName;
|
||||
}
|
||||
|
||||
/*
|
||||
** Append text z[] to the end of p[]. Return a pointer to the first
|
||||
** character after then zero terminator on the new text in p[].
|
||||
*/
|
||||
static char *appendText(char *p, const char *z){
|
||||
size_t n = strlen(z);
|
||||
memcpy(p, z, n+1);
|
||||
return p+n+1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate memory to hold names for a database, journal file, WAL file,
|
||||
** and query parameters. The pointer returned is valid for use by
|
||||
** sqlite3_filename_database() and sqlite3_uri_parameter() and related
|
||||
** functions.
|
||||
**
|
||||
** Memory layout must be compatible with that generated by the pager
|
||||
** and expected by sqlite3_uri_parameter() and databaseName().
|
||||
*/
|
||||
char *sqlite3_create_filename(
|
||||
const char *zDatabase,
|
||||
const char *zJournal,
|
||||
const char *zWal,
|
||||
int nParam,
|
||||
const char **azParam
|
||||
){
|
||||
sqlite3_int64 nByte;
|
||||
int i;
|
||||
char *pResult, *p;
|
||||
nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10;
|
||||
for(i=0; i<nParam*2; i++){
|
||||
nByte += strlen(azParam[i])+1;
|
||||
}
|
||||
pResult = p = sqlite3_malloc64( nByte );
|
||||
if( p==0 ) return 0;
|
||||
memset(p, 0, 4);
|
||||
p += 4;
|
||||
p = appendText(p, zDatabase);
|
||||
for(i=0; i<nParam*2; i++){
|
||||
p = appendText(p, azParam[i]);
|
||||
}
|
||||
*(p++) = 0;
|
||||
p = appendText(p, zJournal);
|
||||
p = appendText(p, zWal);
|
||||
*(p++) = 0;
|
||||
*(p++) = 0;
|
||||
assert( (sqlite3_int64)(p - pResult)==nByte );
|
||||
return pResult + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free memory obtained from sqlite3_create_filename(). It is a severe
|
||||
** error to call this routine with any parameter other than a pointer
|
||||
** previously obtained from sqlite3_create_filename() or a NULL pointer.
|
||||
*/
|
||||
void sqlite3_free_filename(char *p){
|
||||
if( p==0 ) return;
|
||||
p = (char*)databaseName(p);
|
||||
sqlite3_free(p - 4);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This is a utility routine, useful to VFS implementations, that checks
|
||||
** to see if a database file was a URI that contained a specific query
|
||||
@@ -4199,14 +4324,22 @@ int sqlite3_test_control(int op, ...){
|
||||
*/
|
||||
const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
|
||||
if( zFilename==0 || zParam==0 ) return 0;
|
||||
zFilename = databaseName(zFilename);
|
||||
return uriParameter(zFilename, zParam);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the name of Nth query parameter of the filename.
|
||||
*/
|
||||
const char *sqlite3_uri_key(const char *zFilename, int N){
|
||||
if( zFilename==0 || N<0 ) return 0;
|
||||
zFilename = databaseName(zFilename);
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
while( zFilename[0] ){
|
||||
int x = strcmp(zFilename, zParam);
|
||||
while( zFilename[0] && (N--)>0 ){
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
if( x==0 ) return zFilename;
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
}
|
||||
return 0;
|
||||
return zFilename[0] ? zFilename : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4234,6 +4367,38 @@ sqlite3_int64 sqlite3_uri_int64(
|
||||
return bDflt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Translate a filename that was handed to a VFS routine into the corresponding
|
||||
** database, journal, or WAL file.
|
||||
**
|
||||
** It is an error to pass this routine a filename string that was not
|
||||
** passed into the VFS from the SQLite core. Doing so is similar to
|
||||
** passing free() a pointer that was not obtained from malloc() - it is
|
||||
** an error that we cannot easily detect but that will likely cause memory
|
||||
** corruption.
|
||||
*/
|
||||
const char *sqlite3_filename_database(const char *zFilename){
|
||||
return databaseName(zFilename);
|
||||
}
|
||||
const char *sqlite3_filename_journal(const char *zFilename){
|
||||
zFilename = databaseName(zFilename);
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
while( zFilename[0] ){
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
}
|
||||
return zFilename + 1;
|
||||
}
|
||||
const char *sqlite3_filename_wal(const char *zFilename){
|
||||
#ifdef SQLITE_OMIT_WAL
|
||||
return 0;
|
||||
#else
|
||||
zFilename = sqlite3_filename_journal(zFilename);
|
||||
zFilename += sqlite3Strlen30(zFilename) + 1;
|
||||
return zFilename;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the Btree pointer identified by zDbName. Return NULL if not found.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user