]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Merge all the latest trunk enhancements into the reuse-schema branch.
authordrh <drh@noemail.net>
Tue, 14 May 2019 22:25:26 +0000 (22:25 +0000)
committerdrh <drh@noemail.net>
Tue, 14 May 2019 22:25:26 +0000 (22:25 +0000)
FossilOrigin-Name: 018f3199b9ba043fbbf88ec46b4fa16728f6507e000f4813ed346aaf6665add6

18 files changed:
1  2 
main.mk
manifest
manifest.uuid
src/alter.c
src/attach.c
src/build.c
src/fkey.c
src/main.c
src/pragma.c
src/pragma.h
src/shell.c.in
src/sqlite.h.in
src/sqliteInt.h
src/vacuum.c
src/vdbe.c
src/vdbeaux.c
src/vtab.c
tool/mkpragmatab.tcl

diff --cc main.mk
Simple merge
diff --cc manifest
index 42abd6db63da193433ae3bc8a713faa3b253c3ab,5cd70b117f37abf28e50aad056097dd70dbaf658..18384295c0ed3eaca10b38aaeed050d16d6fd5bd
+++ b/manifest
@@@ -1,13 -1,13 +1,13 @@@
- C Merge\srecent\schanges\sfrom\strunk\sinto\sreuse-schema
- D 2019-04-15T15:35:43.643
 -C Fix\sa\sproblem\swith\sthe\sfix\sfor\s[9cf6c9bb51]\s(commit\s[658b84d7])\sthat\scould\scause\sa\scursor\sto\sbe\sleft\sin\san\sinvalid\sstate\sfollowing\sa\s(rowid\s<\stext-value)\ssearch.
 -D 2019-05-14T20:25:22.199
++C Merge\sall\sthe\slatest\strunk\senhancements\sinto\sthe\sreuse-schema\sbranch.
++D 2019-05-14T22:25:26.972
  F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
  F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
  F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
 -F Makefile.in 4640daf826b80947a924ac44275c451ffc13007c7c866a5730c8ce5cf9e1dc74
 +F Makefile.in c4b55bbca70511d8757e38358dfbc06dd74abd51d61bf4939d2caea023c9b97b
  F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 -F Makefile.msc 26957950b2b4f3b26e311eeea70437f85a77765f71d3a06489466d66ee321100
 +F Makefile.msc 93f8f1352fe1a03249a0f7a24c42df04fef01a74a56fe309420b4b3931945bdf
  F README.md 74745e53db87fdc86f571dd7ec1bd18e154d0abd6d37d2292a1062e931318a29
- F VERSION 288d756b1b7be03ecdbf1795c23af2c8425f2e46ba6979a14ef53360308f080d
+ F VERSION cc8cd90333c65cdf4cb346f356a2ce1eb0f5b7fa1d17a34d7350103e7320af1f
  F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
  F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
  F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
@@@ -441,7 -443,7 +444,7 @@@ F ext/userauth/userauth.c f81aa5a3ecacf
  F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
  F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
  F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
- F main.mk 2db4b35d6fec85ffa158bd5f078bde988434e96746932240a028bab0216579a6
 -F main.mk 125adda36bb32c99dc3a11340bd029ef373b9523eac2b2af76087bfe82d4fdf8
++F main.mk b5dd74c752335a232b454f55387012e9326ee6002a2d0c2a2f3b6dc8b8dec642
  F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
  F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
  F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@@ -453,37 -455,37 +456,37 @@@ F spec.template 86a4a43b99ebb3e75e6b9a7
  F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
  F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
  F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
- F src/alter.c 7516a6e36dd5634ef7f28541c5dfc3861f2e619ffa9d0aeab54c565d1254f0f6
 -F src/alter.c 85b41586b2527c8288b249fb0beb96f25860e5b2bf94c02f788b3d0f686354ee
 -F src/analyze.c 58db66344a5c58dcabb57f26696f6f2993956c830446da40b444051d2fdaf644
 -F src/attach.c 78e986baee90cb7b83fb9eafa79c22581a8ada14030fd633b0683c95cf11213c
++F src/alter.c 7b0602147d45191494399507303531909a25e0f6ce7e91621a30c6be3f6a21f5
 +F src/analyze.c e75c3c1d6534265f74a4763282f17e9ad946606ef0a68c5517fcfb355cc243d0
- F src/attach.c d42f6c3a7f838714ae4a95cc26151d96f481c8adee7cb179ac03be05843e5a37
++F src/attach.c 95c3e4b1aa81c16a537cfa0c990dbcfa6e460e382b6ff888752f8e70075a4def
  F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
- F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
+ F src/backup.c b1d37f6f7f5913944583733ed0f9e182f3ece0d42c27f46701142141a6e6fd33
  F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
  F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
- F src/btree.c 958939f608e351a36756e3749596472baa0e5aae54eebd14e6beffe7a68aafc7
+ F src/btree.c 5e15f903fd44b076b864a8d2449d63b44a546efabb66fca7dfed90f106f5c756
  F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
  F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
- F src/build.c ed008d999a9851c561874d8101ef9b759acd19c6cc1dbbb51461abe055f4368c
 -F src/build.c aead3d74794ed4dac396fdd9323ba2272e3734f07c5d7f1f57389e5afbd99f3f
 -F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
++F src/build.c ae462f7766fa342ad6700f958111a0028253709ed0c2e01a458bf575e49b44fe
 +F src/callback.c 5a9a83d7cecce452902da0a24bf51f6e4d232b5dc54b67418276ca9ad82c5bde
  F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
  F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b
  F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
  F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
  F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
  F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
- F src/expr.c e100212835d20498780e7c6d2bdb16c677ecc04350fb75db3bf192a86ba48c92
+ F src/expr.c a41e5a03d60e2d99a8eac1535f21258e3833b29a3f52789e76284d97b54bed5f
  F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
- F src/fkey.c 878bec1b4d9aab3b34585121b834fce9b2780352b7282510e4ffc94b75ce6c83
- F src/func.c 2ccf4ae12430b1ae7096be5f0675887e1bd0732828af0ac0f7496339b7c6edee
 -F src/fkey.c 0e14d4bef8eac2d87bbd517e492d9084c65008d117823f8922c5e7b2b599bd33
++F src/fkey.c 4b54ea67779fb17590861382acc0243d05bde9f3ce680504506db2f5428ee00e
+ F src/func.c 08d6d07d138735dd79f12a2b0c623d1dc9270d0eea61b8be584625391ef84475
  F src/global.c 0dea3065ea72a65ae941559b6686aad6516d4913e76fa4f79a95ff7787f624ec
  F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
  F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
  F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
  F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
- F src/insert.c fc3cf5c371f9a400144e8c2f148ab29cd3f67f7da7eaf47e6a6959f8255fd92c
+ F src/insert.c 4ffc3aa5d2aed178b501533428a76e150907e92a1e4bf7af4ffbcb0d77e99823
  F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
  F src/loadext.c 22afc33c3a61b4fd80a60a54f1882688371e6bc64685df2696b008fce65a999c
- F src/main.c 815aee401c9a031449f28d26fdf5d33104cbcd5c86709b11614362cd12e5445c
 -F src/main.c 3c3925b0bcb4c45687fd52f54c79e98e379252e1d3393f8b7dcccfa26181b661
++F src/main.c 7d9370ced0eff622de28df31656220bf78046c66d0ac8d53c80409bdf306335d
  F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990
  F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
  F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@@ -512,24 -514,24 +515,24 @@@ F src/parse.y 22f64d8a8910acd1758045051
  F src/pcache.c 696a01f1a6370c1b50a09c15972bc3bee3333f8fcd1f2da8e9a76b1b062c59ee
  F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
  F src/pcache1.c be64b2f3908a7f97c56c963676eb12f0d6254c95b28cdc1d73a186eff213219d
- F src/pragma.c 13e40651f965e9ac6d4fd44d6c48c4152185209b677b253dc2141c32c14c8dd6
- F src/pragma.h 9d7658a7be442c1149409aab8ebdde012f387de66fca20056fc9e0791e40dbda
 -F src/pragma.c 2e9fbfcb23cb72eabb38ab6fa84c36a65f9c4839ce1e9bb3dd982ab26b67a5a8
 -F src/pragma.h 482c26f352efd7a4ed1354d83ffa992e13004f6528edeee44cdbfd5025a490bd
 -F src/prepare.c 78027c6231fbb19ca186a5f5f0c0a1375d9c2cec0655273f9bd90d9ff74a34b3
++F src/pragma.c 5e8c63fd746a6a521c657b7d2ce02205286c6a0b90b9fdf3f682d8d8b9e7cd66
++F src/pragma.h 85a1a57c0c9f63f615cf4bde60f8a413a42e1931eef577dfa0e41934fca492bb
 +F src/prepare.c ed5110154bd7644665398b8e5801937f83af3a069c928244235462b5e3adcef3
  F src/printf.c 67f79227273a9009d86a017619717c3f554f50b371294526da59faa6014ed2cd
  F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
- F src/resolve.c 567888ee3faec14dae06519b4306201771058364a37560186a3e0e755ebc4cb8
+ F src/resolve.c 408632d9531ca8f1df8591f00530797daaa7bde3fe0d3211de4d431cbb99347e
  F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
- F src/select.c 9263f5c30dd44c7ac2eb29f40a7ec64322a96885b71c00de6bc30b756c2e1c49
- F src/shell.c.in 30eac60e064eca559c173b46e243c912c30c90c34bdcaafeabb03b5537c72a1c
- F src/sqlite.h.in d8e38484e42e20e6e677cb222c67ff8487142a82e2ed38eeb908ebd57a5a8b76
+ F src/select.c ef860c7e5882c89c030432a6d2cf13c67d1d51fd511cf45cbdfd5c2faf44d51d
 -F src/shell.c.in 6c992809abf20dbb4aad89299d7c15c98ddf2504b23c83ef71eb435ad392cdc3
 -F src/sqlite.h.in 0605c88d98c85fbcba8bbd9716e7cc10b361e7b21cf2375171130f577388c943
++F src/shell.c.in 9353bb93d04b31c823fdd9140beb10d7dc9f19c878d79f081fe08bdede11f6e7
++F src/sqlite.h.in 66e5751c85cd2602213e86945adf26387dba919ac578e55eac0e9b08e453c914
  F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
  F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
- F src/sqliteInt.h 666517f86d73f4f36cc17cb2221ee43117a54342228e99f09bba227cdbcfbe75
 -F src/sqliteInt.h b78a1f0bdc46582f33876932f8b45a264be7ee4f3f6c31102f924d33fa6177ee
++F src/sqliteInt.h b14459b20bfccd8e0a58d463b7df605908ffd4adc8a360c5ed15e98e95e0d828
  F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 -F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 +F src/status.c d9f7d66ae8bee9ffbe4cf7ae72a8d3d429a269336dee1e705ecb3dbea27fa5e2
  F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
 -F src/tclsqlite.c cfe7f93daf9d8787f65e099efb67d7cdfc2c35236dec5d3f6758520bd3519424
 +F src/tclsqlite.c 5947f3797410e213cde1d61f61fbfda706ee4ee2e1db6e0b2376e3206dabc71d
- F src/test1.c cfb303eeddd3670409af6b58d2ddb928b8e9e70822d681d3df88dfaabb7bea6a
+ F src/test1.c f4e0be5c344587b2beac474a58018a3833208fb6bbec35d37d58b1270a7a5917
  F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
  F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
  F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
@@@ -586,31 -587,31 +589,31 @@@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f
  F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
  F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e
  F src/treeview.c 56724725c62a0d0f408f7c257475dc33309198afee36a1d18be1bc268b09055e
 -F src/trigger.c bb034c08eca111e66a19cda045903a12547c1be2294b5570d794b869d9c44a73
 +F src/trigger.c 020d7ad68bee5c3f0f2244eb8c2b53394f908a4f63fe0017dc8cd001e4998931
- F src/update.c 0b973357d88092140531e07ff641139c26fb4380b0b9f5ed98c5f7691b4604d1
+ F src/update.c 3cb9150d2cf661d938e2f1b1749945f3faa767f88febdb739ab1793bbf895ff2
  F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
  F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507
- F src/util.c e12939405e77906d06ab0b78c5f513dcd2b7cec2fbb553877b0abfece6067141
- F src/vacuum.c 36b6328b64e571eaa8d8e82d57658bb5b381539303f15c05a28cc80d8862e908
- F src/vdbe.c 47d08dda2ade559d85c75ccc4623c6aa7f5c063bf323a382b307145ed66ae7ab
+ F src/util.c 4c0669e042b4e50a08a9e5fd14cecc76e5f877efa288533dccddb6fe98f4d6b5
 -F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf
 -F src/vdbe.c d14841dc77e5b0cbd5cb857dee026f17b07a9d1ab147c1c2c9557227be6a52c9
 -F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
++F src/vacuum.c 5b9b4771ffb47aaef038c4ad5f1acd76dfbc9e0a4f101c1ba7f7ac9c2ba96374
++F src/vdbe.c 28d2d2a821c8b2b125c0f3bad976cb50db384f8c912eb1c7676ca96828f9cd2e
 +F src/vdbe.h 323218c4bfd64c719ba85d05fbc87cdd126991cadb39e73ccac7b59f30c3d53e
- F src/vdbeInt.h 2c12704db9740c8e899786ecfc7a5797a9d067563496eb1b6ed03c592d7b8d90
- F src/vdbeapi.c 2ddd60f4a351f15ee98d841e346af16111ad59dfa4d25d2dd4012e9875bf7d92
- F src/vdbeaux.c 793111f45c2973491bcad36e345514cdaa0b16f0a7b2e9ae887a7050e4d6efdf
+ F src/vdbeInt.h 3ba14553508d66f58753952d6dd287dce4ec735de02c6440858b4891aed51c17
+ F src/vdbeapi.c f9161e5c77f512fbb80091ce8af621d19c9556bda5e734cffaac1198407400da
 -F src/vdbeaux.c d444f4a3ff9c571965329a186701a57fe445e4c3f4c42f87402aca75386ba358
 -F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
++F src/vdbeaux.c 95cabb0e8c49b762f4ced25a54b38036a3975e65140e623ce034979cc3e7d93b
 +F src/vdbeblob.c 08e58c6bef990008b8c2dbad4c99c56d3b622ee79433004484cce29b536e2ab9
- F src/vdbemem.c 8e6889761e344babdb8a56dd1ac8911501fa648396544d1644f1cd6a87c80dc0
- F src/vdbesort.c 31c7794a517e8b0a1704988f1f7596b74c6fc07eeb7bb85776f50a391ed9d94f
- F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
- F src/vtab.c 9fe701febd1cfb44af4810b7f1bcc2db327c3a818e070b53aad132dd193d61a0
+ F src/vdbemem.c b76b42ac9d6a36fc55a0797929fc94cc33e1334eea2792f5ee1eef868ce13320
+ F src/vdbesort.c 66592d478dbb46f19aed0b42222325eadb84deb40a90eebe25c6e7c1d8468f47
+ F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
 -F src/vtab.c 1fa256c6ddad7a81e2a4dc080d015d4b0a7135767717d311298e47f6fca64bb3
++F src/vtab.c 4bb7440736c84abc5500ab0bf4946db4f5e48775513d58b28df212043ba5c2d1
  F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
- F src/wal.c 9eccc7ebb532a7b0fd3cabc16cff576b9afa763472272db67d84fb8cec96f5c0
+ F src/wal.c b09a2a9cab50efa08451a8c81d47052120ad5da174048c6d0b08d405384abdf2
  F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
  F src/walker.c 7607f1a68130c028255d8d56094ea602fc402c79e1e35a46e6282849d90d5fe4
- F src/where.c ff2955dc2743c1af05ba5a8232ab72724d9a63b76dbee256368f40fd3ef82db5
- F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
- F src/wherecode.c 83be72e8d1c0231d0db06ffe5cfd32c7834bd00d2ed869306a2c1e0828488752
- F src/whereexpr.c 90859652920f153d2c03f075488744be2926625ebd36911bcbcb17d0d29c891c
- F src/window.c 038c248267e74ff70a2bb9b1884d40fd145c5183b017823ecb6cbb14bc781478
+ F src/where.c 99c7b718ef846ac952016083aaf4e22ede2290beceaf4730a2df55c023251369
+ F src/whereInt.h 1b728f71654ebf8421a1715497a587f02d6f538e819af58dc826908f8577e810
+ F src/wherecode.c 37a1004237d630d785c47bba2290eac652a7a8b0047518eba3cb7c808b604c4a
+ F src/whereexpr.c 4219bdd5d310ba6424166d918efef301c21e1b7f6444e964b415c4a5b877a8fe
+ F src/window.c 5be2cf7d8763cc97137fc44d015aed8a1a4a56fe9700d7933ed560172617c756
  F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
  F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
  F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@@ -1759,8 -1758,8 +1766,8 @@@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc8
  F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
  F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
  F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
- F tool/mkpragmatab.tcl a3ca473c1ddf1fd6b95e2670907b7856c26c52091a5daa78e88b21a471c39e48
- F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5
 -F tool/mkpragmatab.tcl d8887dfbd5a40c9e5de2c011db989af52152b9bcc64059d9e93b28edf38af9b9
++F tool/mkpragmatab.tcl 34f68553b3903fda0707fa282dd6eb267de07dbafd1f05342014a82f87fc8a96
+ F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b7325712
  F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b
  F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
  F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
@@@ -1826,7 -1825,7 +1833,7 @@@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a9
  F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
  F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
  F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P 9f591ac07871958d173ae4cf9065c8000a9efb80676d158935d2700fff61a361 734192d876e0489cb34e454aaa4a9c6858145791a49959b31dee2917a8e41a7d
- R afca53b9169e39309b1923b1610dd287
 -P 228e1087c0602470e450586499de5a3e87e266c688bc828f20e3bad2fdc65ff1
 -R d132bb7525b36863c7f0dbefbbac4ccc
 -U dan
 -Z 61ab05a485e7c528107861afc63f60a9
++P 5c6c9e7f6f83d565b317e3442e8bc664478adb407fe416d068fe0dcd17ffa5b5 bc7d2c1656396bb4f5f1f814e60dbf816cc91c5a521b54ad593cd3da0fe8dcb4
++R 253230c497ea5d35d5c003fbd477012b
 +U drh
- Z c8407b9bef52280edc181feafa94c840
++Z fae651c1a82209099a4f420d4dbb336e
diff --cc manifest.uuid
index 9d0192aec4e606c5511ed720cf66bf1ff6448712,a58fb53a14d1958b71389cc415d002cbb527715d..61c703c36b596daaf4e3ab2e886be7ddfb79339f
@@@ -1,1 -1,1 +1,1 @@@
- 5c6c9e7f6f83d565b317e3442e8bc664478adb407fe416d068fe0dcd17ffa5b5
 -bc7d2c1656396bb4f5f1f814e60dbf816cc91c5a521b54ad593cd3da0fe8dcb4
++018f3199b9ba043fbbf88ec46b4fa16728f6507e000f4813ed346aaf6665add6
diff --cc src/alter.c
Simple merge
diff --cc src/attach.c
index 51e51c107d0c59bd5ce67b6d485bec886e6bed52,55e0eb53634a3c822e3d94fe9b28c3927981b295..7a396740818b7a1a12dec623672a00e07d8b7a8d
@@@ -231,17 -231,17 +231,17 @@@ static void attachFunc
    ** way we found it.
    */
    if( rc==SQLITE_OK ){
 -    sqlite3BtreeEnterAll(db);
      db->init.iDb = 0;
      db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
 -    if( !REOPEN_AS_MEMDB(db) ){
 +    if( !IsSharedSchema(db) && !REOPEN_AS_MEMDB(db) ){
 +      sqlite3BtreeEnterAll(db);
        rc = sqlite3Init(db, &zErrDyn);
 +      sqlite3BtreeLeaveAll(db);
 +      assert( zErrDyn==0 || rc!=SQLITE_OK );
      }
 -    sqlite3BtreeLeaveAll(db);
 -    assert( zErrDyn==0 || rc!=SQLITE_OK );
    }
  #ifdef SQLITE_USER_AUTHENTICATION
-   if( rc==SQLITE_OK ){
+   if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
      u8 newAuth = 0;
      rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
      if( newAuth<db->auth.authLevel ){
diff --cc src/build.c
Simple merge
diff --cc src/fkey.c
Simple merge
diff --cc src/main.c
Simple merge
diff --cc src/pragma.c
Simple merge
diff --cc src/pragma.h
Simple merge
diff --cc src/shell.c.in
index 4051a2fd2747b0be28a1d47df178d9142852dfd2,f9f82b01caa30caeed674aed2ee689a338d93976..07e21d829ed009c11bd84f25596fcd4cb27c3cb1
@@@ -1071,14 -1075,13 +1075,14 @@@ struct ShellState 
  
  /* Allowed values for ShellState.openMode
  */
- #define SHELL_OPEN_UNSPEC       0    /* No open-mode specified */
- #define SHELL_OPEN_NORMAL       1    /* Normal database file */
- #define SHELL_OPEN_APPENDVFS    2    /* Use appendvfs */
- #define SHELL_OPEN_ZIPFILE      3    /* Use the zipfile virtual table */
- #define SHELL_OPEN_READONLY     4    /* Open a normal database read-only */
- #define SHELL_OPEN_DESERIALIZE  5    /* Open using sqlite3_deserialize() */
- #define SHELL_OPEN_HEXDB        6    /* Use "dbtotxt" output as data source */
- #define SHELL_OPEN_SHAREDSCHEMA 7    /* Open for schema reuse */
 -#define SHELL_OPEN_UNSPEC      0      /* No open-mode specified */
 -#define SHELL_OPEN_NORMAL      1      /* Normal database file */
 -#define SHELL_OPEN_APPENDVFS   2      /* Use appendvfs */
 -#define SHELL_OPEN_ZIPFILE     3      /* Use the zipfile virtual table */
 -#define SHELL_OPEN_READONLY    4      /* Open a normal database read-only */
 -#define SHELL_OPEN_DESERIALIZE 5      /* Open using sqlite3_deserialize() */
 -#define SHELL_OPEN_HEXDB       6      /* Use "dbtotxt" output as data source */
++#define SHELL_OPEN_UNSPEC       0     /* No open-mode specified */
++#define SHELL_OPEN_NORMAL       1     /* Normal database file */
++#define SHELL_OPEN_APPENDVFS    2     /* Use appendvfs */
++#define SHELL_OPEN_ZIPFILE      3     /* Use the zipfile virtual table */
++#define SHELL_OPEN_READONLY     4     /* Open a normal database read-only */
++#define SHELL_OPEN_DESERIALIZE  5     /* Open using sqlite3_deserialize() */
++#define SHELL_OPEN_HEXDB        6     /* Use "dbtotxt" output as data source */
++#define SHELL_OPEN_SHAREDSCHEMA 7     /* Open for schema reuse */
  
  /* Allowed values for ShellState.eTraceType
  */
@@@ -6163,130 -6060,759 +6066,990 @@@ static int arCreateOrUpdateCommand
      rc = arExecSql(pAr, zSql2);
      sqlite3_free(zSql2);
    }
- end_ar_transaction:
-   if( rc!=SQLITE_OK ){
-     sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
-   }else{
-     rc = arExecSql(pAr, "RELEASE ar;");
-     if( pAr->bZip && pAr->zFile ){
-       zSql = sqlite3_mprintf("DROP TABLE %s", zTemp);
-       arExecSql(pAr, zSql);
-       sqlite3_free(zSql);
+ end_ar_transaction:
+   if( rc!=SQLITE_OK ){
+     sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
+   }else{
+     rc = arExecSql(pAr, "RELEASE ar;");
+     if( pAr->bZip && pAr->zFile ){
+       zSql = sqlite3_mprintf("DROP TABLE %s", zTemp);
+       arExecSql(pAr, zSql);
+       sqlite3_free(zSql);
+     }
+   }
+   sqlite3_free(zExists);
+   return rc;
+ }
+ /*
+ ** Implementation of ".ar" dot command.
+ */
+ static int arDotCommand(
+   ShellState *pState,             /* Current shell tool state */
+   int fromCmdLine,                /* True if -A command-line option, not .ar cmd */
+   char **azArg,                   /* Array of arguments passed to dot command */
+   int nArg                        /* Number of entries in azArg[] */
+ ){
+   ArCommand cmd;
+   int rc;
+   memset(&cmd, 0, sizeof(cmd));
+   cmd.fromCmdLine = fromCmdLine;
+   rc = arParseCommand(azArg, nArg, &cmd);
+   if( rc==SQLITE_OK ){
+     int eDbType = SHELL_OPEN_UNSPEC;
+     cmd.p = pState;
+     cmd.db = pState->db;
+     if( cmd.zFile ){
+       eDbType = deduceDatabaseType(cmd.zFile, 1);
+     }else{
+       eDbType = pState->openMode;
+     }
+     if( eDbType==SHELL_OPEN_ZIPFILE ){
+       if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
+         if( cmd.zFile==0 ){
+           cmd.zSrcTable = sqlite3_mprintf("zip");
+         }else{
+           cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
+         }
+       }
+       cmd.bZip = 1;
+     }else if( cmd.zFile ){
+       int flags;
+       if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
+       if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT 
+            || cmd.eCmd==AR_CMD_UPDATE ){
+         flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
+       }else{
+         flags = SQLITE_OPEN_READONLY;
+       }
+       cmd.db = 0;
+       if( cmd.bDryRun ){
+         utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
+              eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
+       }
+       rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 
+              eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
+       if( rc!=SQLITE_OK ){
+         utf8_printf(stderr, "cannot open file: %s (%s)\n", 
+             cmd.zFile, sqlite3_errmsg(cmd.db)
+         );
+         goto end_ar_command;
+       }
+       sqlite3_fileio_init(cmd.db, 0, 0);
+       sqlite3_sqlar_init(cmd.db, 0, 0);
+       sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
+                               shellPutsFunc, 0, 0);
+     }
+     if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
+       if( cmd.eCmd!=AR_CMD_CREATE
+        && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
+       ){
+         utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
+         rc = SQLITE_ERROR;
+         goto end_ar_command;
+       }
+       cmd.zSrcTable = sqlite3_mprintf("sqlar");
+     }
+     switch( cmd.eCmd ){
+       case AR_CMD_CREATE:
+         rc = arCreateOrUpdateCommand(&cmd, 0, 0);
+         break;
+       case AR_CMD_EXTRACT:
+         rc = arExtractCommand(&cmd);
+         break;
+       case AR_CMD_LIST:
+         rc = arListCommand(&cmd);
+         break;
+       case AR_CMD_HELP:
+         arUsage(pState->out);
+         break;
+       case AR_CMD_INSERT:
+         rc = arCreateOrUpdateCommand(&cmd, 1, 0);
+         break;
+       default:
+         assert( cmd.eCmd==AR_CMD_UPDATE );
+         rc = arCreateOrUpdateCommand(&cmd, 1, 1);
+         break;
+     }
+   }
+ end_ar_command:
+   if( cmd.db!=pState->db ){
+     close_db(cmd.db);
+   }
+   sqlite3_free(cmd.zSrcTable);
+   return rc;
+ }
+ /* End of the ".archive" or ".ar" command logic
+ **********************************************************************************/
+ #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
+ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+ /*
+ ** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op.
+ ** Otherwise, the SQL statement or statements in zSql are executed using
+ ** database connection db and the error code written to *pRc before
+ ** this function returns.
+ */
+ static void shellExec(sqlite3 *db, int *pRc, const char *zSql){
+   int rc = *pRc;
+   if( rc==SQLITE_OK ){
+     char *zErr = 0;
+     rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+     if( rc!=SQLITE_OK ){
+       raw_printf(stderr, "SQL error: %s\n", zErr);
+     }
+     *pRc = rc;
+   }
+ }
+ /*
+ ** Like shellExec(), except that zFmt is a printf() style format string.
+ */
+ static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){
+   char *z = 0;
+   if( *pRc==SQLITE_OK ){
+     va_list ap;
+     va_start(ap, zFmt);
+     z = sqlite3_vmprintf(zFmt, ap);
+     va_end(ap);
+     if( z==0 ){
+       *pRc = SQLITE_NOMEM;
+     }else{
+       shellExec(db, pRc, z);
+     }
+     sqlite3_free(z);
+   }
+ }
+ /*
+ ** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+ ** Otherwise, an attempt is made to allocate, zero and return a pointer
+ ** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set
+ ** to SQLITE_NOMEM and NULL returned.
+ */
+ static void *shellMalloc(int *pRc, sqlite3_int64 nByte){
+   void *pRet = 0;
+   if( *pRc==SQLITE_OK ){
+     pRet = sqlite3_malloc64(nByte);
+     if( pRet==0 ){
+       *pRc = SQLITE_NOMEM;
+     }else{
+       memset(pRet, 0, nByte);
+     }
+   }
+   return pRet;
+ }
+ /*
+ ** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+ ** Otherwise, zFmt is treated as a printf() style string. The result of
+ ** formatting it along with any trailing arguments is written into a 
+ ** buffer obtained from sqlite3_malloc(), and pointer to which is returned.
+ ** It is the responsibility of the caller to eventually free this buffer
+ ** using a call to sqlite3_free().
+ ** 
+ ** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL 
+ ** pointer returned.
+ */
+ static char *shellMPrintf(int *pRc, const char *zFmt, ...){
+   char *z = 0;
+   if( *pRc==SQLITE_OK ){
+     va_list ap;
+     va_start(ap, zFmt);
+     z = sqlite3_vmprintf(zFmt, ap);
+     va_end(ap);
+     if( z==0 ){
+       *pRc = SQLITE_NOMEM;
+     }
+   }
+   return z;
+ }
++static int sharedSchemaFix(ShellState *pState, const char *zDb, int eFix){
++  int rc = SQLITE_OK;
++  i64 iLast = 0;
++  int iCookie = 0;
++  int iAutoVacuum = 0;
++  sqlite3_stmt *pStmt = 0;
++
++  shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb);
++  shellExecPrintf(pState->db, &rc, "PRAGMA writable_schema = 1");
++  shellExecPrintf(pState->db, &rc, "BEGIN");
++  shellPreparePrintf(pState->db, &rc, &pStmt, 
++      "SELECT max(rowid) FROM _shared_schema_tmp.sqlite_master"
++  );
++  sqlite3_step(pStmt);
++  iLast = sqlite3_column_int64(pStmt, 0);
++  shellFinalize(&rc, pStmt);
++  shellPreparePrintf(pState->db, &rc, &pStmt,
++      "INSERT INTO _shared_schema_tmp.sqlite_master SELECT "
++      "  type, name, tbl_name, ("
++      "    SELECT rootpage FROM _shared_schema_tmp.sqlite_master WHERE "
++      "      type IS o.type AND name IS o.name AND rowid<=?"
++      "  ), sql FROM main.sqlite_master AS o"
++  );
++  sqlite3_bind_int64(pStmt, 1, iLast);
++  sqlite3_step(pStmt);
++  shellFinalize(&rc, pStmt);
++
++  shellExecPrintf(pState->db, &rc,
++      "DELETE FROM _shared_schema_tmp.sqlite_master WHERE rowid<=%lld",
++      iLast
++  );
++  shellExecPrintf(pState->db, &rc, "COMMIT");
++  sqlite3_exec(pState->db, "PRAGMA writable_schema = 0", 0, 0, 0);
++
++  /* Copy the auto-vacuum setting from main to the target db */
++  shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.auto_vacuum");
++  sqlite3_step(pStmt);
++  iAutoVacuum = sqlite3_column_int(pStmt, 0);
++  shellFinalize(&rc, pStmt);
++  shellExecPrintf(pState->db, &rc, 
++      "PRAGMA _shared_schema_tmp.auto_vacuum = %d", iAutoVacuum
++  );
++
++  /* Vacuum the db in order to standardize the rootpage numbers. */
++  shellExecPrintf(pState->db, &rc, "VACUUM _shared_schema_tmp");
++
++  /* Set the schema-cookie value to the same as database "main" */
++  shellPreparePrintf(pState->db, &rc, &pStmt, "PRAGMA main.schema_version");
++  sqlite3_step(pStmt);
++  iCookie = sqlite3_column_int(pStmt, 0);
++  shellFinalize(&rc, pStmt);
++  shellExecPrintf(pState->db, &rc, 
++      "PRAGMA _shared_schema_tmp.schema_version = %d", iCookie
++  );
++
++  sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0);
++  return rc;
++}
++
++static int sharedSchemaCheck(ShellState *pState, const char *zDb, int *peFix){
++  int rc = SQLITE_OK;
++  int bFailed = 0;
++  sqlite3_stmt *pStmt = 0;
++
++  if( peFix ) *peFix = 0;
++  shellExecPrintf(pState->db, &rc, "ATTACH '%q' AS _shared_schema_tmp", zDb);
++
++  /* Check if this database has the same set of objects as the current db */
++  shellPreparePrintf(pState->db, &rc, &pStmt, 
++    "SELECT type, name FROM _shared_schema_tmp.sqlite_master AS o "
++    "WHERE NOT EXISTS ("
++    "  SELECT 1 FROM main.sqlite_master "
++    "    WHERE name IS o.name AND type IS o.type"
++    ")"
++    " UNION ALL "
++    "SELECT type, name FROM main.sqlite_master AS o "
++    "WHERE NOT EXISTS ("
++    "  SELECT 1 FROM _shared_schema_tmp.sqlite_master "
++    "    WHERE name IS o.name AND type IS o.type"
++    ")"
++  );
++  if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++    utf8_printf(pState->out, "%s is NOT compatible (objects)\n", zDb);
++    bFailed = 1;
++  }
++  shellFinalize(&rc, pStmt);
++
++  /* Check if this database has the same set of SQL statements as the 
++  ** current db. */
++  if( bFailed==0 ){
++    shellPreparePrintf(pState->db, &rc, &pStmt, 
++        "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o "
++        "WHERE sql IS NOT ("
++        "  SELECT sql FROM main.sqlite_master "
++        "    WHERE name IS o.name AND type IS o.type"
++        ")"
++    );
++    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++      utf8_printf(pState->out, "%s is NOT compatible (SQL)\n", zDb);
++      bFailed = 1;
++    }
++    shellFinalize(&rc, pStmt);
++  }
++
++  /* Check if this database has the same set of root pages as the current 
++  ** db. */
++  if( bFailed==0 ){
++    shellPreparePrintf(pState->db, &rc, &pStmt, 
++        "SELECT 1 FROM _shared_schema_tmp.sqlite_master AS o "
++        "WHERE rootpage IS NOT ("
++        "  SELECT rootpage FROM main.sqlite_master "
++        "    WHERE name IS o.name AND type IS o.type"
++        ")"
++    );
++    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++      if( peFix==0 ){
++        utf8_printf(pState->out, "%s is NOT compatible (root pages)\n", zDb);
++      }
++      bFailed = 1;
++      if( peFix ) *peFix = 1;
++    }
++    shellFinalize(&rc, pStmt);
++  }
++
++  if( bFailed==0 ){
++    shellPreparePrintf(pState->db, &rc, &pStmt, 
++        "SELECT 1 WHERE ("
++        "  SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') "
++        "  FROM _shared_schema_tmp.sqlite_master"
++        ") IS NOT ("
++        "  SELECT group_concat(rootpage || '.' || name || '.' || sql, '.') "
++        "  FROM main.sqlite_master"
++        ")"
++    );
++    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++      if( peFix==0 ){
++        utf8_printf(pState->out, 
++            "%s is NOT compatible (order of sqlite_master rows)\n", zDb
++        );
++      }
++      bFailed = 1;
++      if( peFix ) *peFix = 2;
++    }
++    shellFinalize(&rc, pStmt);
++  }
++
++  if( bFailed==0 ){
++    int iMain = -1;
++    int iNew = +1;
++    shellPreparePrintf(pState->db, &rc, &pStmt, 
++        "PRAGMA main.schema_version"
++    );
++    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++      iMain = sqlite3_column_int(pStmt, 0);
++    }
++    shellFinalize(&rc, pStmt);
++    shellPreparePrintf(pState->db, &rc, &pStmt, 
++        "PRAGMA _shared_schema_tmp.schema_version"
++    );
++    if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
++      iNew = sqlite3_column_int(pStmt, 0);
++    }
++    shellFinalize(&rc, pStmt);
++    if( rc==SQLITE_OK && iMain!=iNew ){
++      if( peFix==0 ){
++        utf8_printf(pState->out, 
++            "%s is NOT compatible (schema cookie)\n", zDb
++        );
++      }
++      bFailed = 1;
++      if( peFix ) *peFix = 3;
++    }
++  }
++
++  if( rc==SQLITE_OK && bFailed==0 ){
++    utf8_printf(pState->out, "%s is compatible\n", zDb);
++  }
++
++  sqlite3_exec(pState->db, "DETACH _shared_schema_tmp", 0, 0, 0);
++  return rc;
++}
++
++/*
++** .shared-schema check|fix DB1 DB2...
++*/
++static int sharedSchemaDotCommand(
++  ShellState *pState,             /* Current shell tool state */
++  char **azArg,                   /* Array of arguments passed to dot command */
++  int nArg                        /* Number of entries in azArg[] */
++){
++  int rc = SQLITE_OK;
++  int bFix = 0;                   /* Fix databases if possible */
++  int n1;
++  int i;
++  if( nArg<3 ){
++    goto shared_schema_usage;
++  }
++
++  n1 = (int)strlen(azArg[1]);
++  if( n1>0 && n1<=3 && memcmp("fix", azArg[1], n1)==0 ){
++    bFix = 1;
++  }else if( n1==0 || n1>5 || memcmp("check", azArg[1], n1) ){
++    goto shared_schema_usage;
++  }
++
++  for(i=2; rc==SQLITE_OK && i<nArg; i++){
++    int eFix = 0;
++    rc = sharedSchemaCheck(pState, azArg[i], bFix ? &eFix : 0);
++    if( rc==SQLITE_OK && bFix && eFix ){
++      utf8_printf(pState->out, "Fixing %s... ", azArg[i]);
++      fflush(pState->out);
++      rc = sharedSchemaFix(pState, azArg[i], eFix);
++      if( rc==SQLITE_OK ){
++        rc = sharedSchemaCheck(pState, azArg[i], &eFix);
++        if( rc==SQLITE_OK && eFix ){
++          utf8_printf(pState->out, "VACUUMing main... ");
++          fflush(pState->out);
++          rc = sqlite3_exec(pState->db, "VACUUM main", 0, 0, 0);
++          if( rc==SQLITE_OK ){
++            rc = sharedSchemaCheck(pState, azArg[i], 0);
++          }
++        }
++      }
 +    }
 +  }
-   sqlite3_free(zExists);
++
 +  return rc;
++ shared_schema_usage:
++  raw_printf(stderr, "usage: .shared-schema check|fix DB1 DB2...\n");
++  return SQLITE_ERROR;
 +}
  
  /*
- ** Implementation of ".ar" dot command.
+ ** When running the ".recover" command, each output table, and the special
+ ** orphaned row table if it is required, is represented by an instance
+ ** of the following struct.
  */
- static int arDotCommand(
-   ShellState *pState,             /* Current shell tool state */
-   int fromCmdLine,                /* True if -A command-line option, not .ar cmd */
-   char **azArg,                   /* Array of arguments passed to dot command */
-   int nArg                        /* Number of entries in azArg[] */
+ typedef struct RecoverTable RecoverTable;
+ struct RecoverTable {
+   char *zQuoted;                  /* Quoted version of table name */
+   int nCol;                       /* Number of columns in table */
+   char **azlCol;                  /* Array of column lists */
+   int iPk;                        /* Index of IPK column */
+ };
+ /*
+ ** Free a RecoverTable object allocated by recoverFindTable() or
+ ** recoverOrphanTable().
+ */
+ static void recoverFreeTable(RecoverTable *pTab){
+   if( pTab ){
+     sqlite3_free(pTab->zQuoted);
+     if( pTab->azlCol ){
+       int i;
+       for(i=0; i<=pTab->nCol; i++){
+         sqlite3_free(pTab->azlCol[i]);
+       }
+       sqlite3_free(pTab->azlCol);
+     }
+     sqlite3_free(pTab);
+   }
+ }
+ /*
+ ** This function is a no-op if (*pRc) is not SQLITE_OK when it is called.
+ ** Otherwise, it allocates and returns a RecoverTable object based on the
+ ** final four arguments passed to this function. It is the responsibility
+ ** of the caller to eventually free the returned object using
+ ** recoverFreeTable().
+ */
+ static RecoverTable *recoverNewTable(
+   int *pRc,                       /* IN/OUT: Error code */
+   const char *zName,              /* Name of table */
+   const char *zSql,               /* CREATE TABLE statement */
+   int bIntkey, 
+   int nCol
  ){
-   ArCommand cmd;
-   int rc;
-   memset(&cmd, 0, sizeof(cmd));
-   cmd.fromCmdLine = fromCmdLine;
-   rc = arParseCommand(azArg, nArg, &cmd);
+   sqlite3 *dbtmp = 0;             /* sqlite3 handle for testing CREATE TABLE */
+   int rc = *pRc;
+   RecoverTable *pTab = 0;
+   pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable));
    if( rc==SQLITE_OK ){
-     int eDbType = SHELL_OPEN_UNSPEC;
-     cmd.p = pState;
-     cmd.db = pState->db;
-     if( cmd.zFile ){
-       eDbType = deduceDatabaseType(cmd.zFile, 1);
-     }else{
-       eDbType = pState->openMode;
+     int nSqlCol = 0;
+     int bSqlIntkey = 0;
+     sqlite3_stmt *pStmt = 0;
+     
+     rc = sqlite3_open("", &dbtmp);
+     if( rc==SQLITE_OK ){
+       rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0);
      }
-     if( eDbType==SHELL_OPEN_ZIPFILE ){
-       if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
-         if( cmd.zFile==0 ){
-           cmd.zSrcTable = sqlite3_mprintf("zip");
-         }else{
-           cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
+     if( rc==SQLITE_OK ){
+       rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0);
+       if( rc==SQLITE_ERROR ){
+         rc = SQLITE_OK;
+         goto finished;
+       }
+     }
+     shellPreparePrintf(dbtmp, &rc, &pStmt, 
+         "SELECT count(*) FROM pragma_table_info(%Q)", zName
+     );
+     if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+       nSqlCol = sqlite3_column_int(pStmt, 0);
+     }
+     shellFinalize(&rc, pStmt);
+     if( rc!=SQLITE_OK || nSqlCol<nCol ){
+       goto finished;
+     }
+     shellPreparePrintf(dbtmp, &rc, &pStmt, 
+       "SELECT ("
+       "  SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage"
+       ") FROM sqlite_master WHERE name = %Q", zName
+     );
+     if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+       bSqlIntkey = sqlite3_column_int(pStmt, 0);
+     }
+     shellFinalize(&rc, pStmt);
+     if( bIntkey==bSqlIntkey ){
+       int i;
+       const char *zPk = "_rowid_";
+       sqlite3_stmt *pPkFinder = 0;
+       /* If this is an intkey table and there is an INTEGER PRIMARY KEY,
+       ** set zPk to the name of the PK column, and pTab->iPk to the index
+       ** of the column, where columns are 0-numbered from left to right.
+       ** Or, if this is a WITHOUT ROWID table or if there is no IPK column,
+       ** leave zPk as "_rowid_" and pTab->iPk at -2.  */
+       pTab->iPk = -2;
+       if( bIntkey ){
+         shellPreparePrintf(dbtmp, &rc, &pPkFinder, 
+           "SELECT cid, name FROM pragma_table_info(%Q) "
+           "  WHERE pk=1 AND type='integer' COLLATE nocase"
+           "  AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)"
+           , zName, zName
+         );
+         if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){
+           pTab->iPk = sqlite3_column_int(pPkFinder, 0);
+           zPk = (const char*)sqlite3_column_text(pPkFinder, 1);
          }
        }
-       cmd.bZip = 1;
-     }else if( cmd.zFile ){
-       int flags;
-       if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
-       if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT 
-            || cmd.eCmd==AR_CMD_UPDATE ){
-         flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
+       pTab->zQuoted = shellMPrintf(&rc, "%Q", zName);
+       pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1));
+       pTab->nCol = nSqlCol;
+       if( bIntkey ){
+         pTab->azlCol[0] = shellMPrintf(&rc, "%Q", zPk);
        }else{
-         flags = SQLITE_OPEN_READONLY;
+         pTab->azlCol[0] = shellMPrintf(&rc, "");
        }
-       cmd.db = 0;
-       if( cmd.bDryRun ){
-         utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
-              eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
+       i = 1;
+       shellPreparePrintf(dbtmp, &rc, &pStmt, 
+           "SELECT %Q || group_concat(name, ', ') "
+           "  FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) "
+           "FROM pragma_table_info(%Q)", 
+           bIntkey ? ", " : "", pTab->iPk, 
+           bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ",
+           zName
+       );
+       while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+         const char *zText = (const char*)sqlite3_column_text(pStmt, 0);
+         pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText);
+         i++;
        }
-       rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, 
-              eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
-       if( rc!=SQLITE_OK ){
-         utf8_printf(stderr, "cannot open file: %s (%s)\n", 
-             cmd.zFile, sqlite3_errmsg(cmd.db)
+       shellFinalize(&rc, pStmt);
+       shellFinalize(&rc, pPkFinder);
+     }
+   }
+  finished:
+   sqlite3_close(dbtmp);
+   *pRc = rc;
+   if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){
+     recoverFreeTable(pTab);
+     pTab = 0;
+   }
+   return pTab;
+ }
+ /*
+ ** This function is called to search the schema recovered from the
+ ** sqlite_master table of the (possibly) corrupt database as part
+ ** of a ".recover" command. Specifically, for a table with root page
+ ** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the
+ ** table must be a WITHOUT ROWID table, or if non-zero, not one of
+ ** those.
+ **
+ ** If a table is found, a (RecoverTable*) object is returned. Or, if
+ ** no such table is found, but bIntkey is false and iRoot is the 
+ ** root page of an index in the recovered schema, then (*pbNoop) is
+ ** set to true and NULL returned. Or, if there is no such table or
+ ** index, NULL is returned and (*pbNoop) set to 0, indicating that
+ ** the caller should write data to the orphans table.
+ */
+ static RecoverTable *recoverFindTable(
+   ShellState *pState,             /* Shell state object */
+   int *pRc,                       /* IN/OUT: Error code */
+   int iRoot,                      /* Root page of table */
+   int bIntkey,                    /* True for an intkey table */
+   int nCol,                       /* Number of columns in table */
+   int *pbNoop                     /* OUT: True if iRoot is root of index */
+ ){
+   sqlite3_stmt *pStmt = 0;
+   RecoverTable *pRet = 0;
+   int bNoop = 0;
+   const char *zSql = 0;
+   const char *zName = 0;
+   /* Search the recovered schema for an object with root page iRoot. */
+   shellPreparePrintf(pState->db, pRc, &pStmt,
+       "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot
+   );
+   while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+     const char *zType = (const char*)sqlite3_column_text(pStmt, 0);
+     if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){
+       bNoop = 1;
+       break;
+     }
+     if( sqlite3_stricmp(zType, "table")==0 ){
+       zName = (const char*)sqlite3_column_text(pStmt, 1);
+       zSql = (const char*)sqlite3_column_text(pStmt, 2);
+       pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
+       break;
+     }
+   }
+   shellFinalize(pRc, pStmt);
+   *pbNoop = bNoop;
+   return pRet;
+ }
+ /*
+ ** Return a RecoverTable object representing the orphans table.
+ */
+ static RecoverTable *recoverOrphanTable(
+   ShellState *pState,             /* Shell state object */
+   int *pRc,                       /* IN/OUT: Error code */
+   const char *zLostAndFound,      /* Base name for orphans table */
+   int nCol                        /* Number of user data columns */
+ ){
+   RecoverTable *pTab = 0;
+   if( nCol>=0 && *pRc==SQLITE_OK ){
+     int i;
+     /* This block determines the name of the orphan table. The prefered
+     ** name is zLostAndFound. But if that clashes with another name
+     ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1
+     ** and so on until a non-clashing name is found.  */
+     int iTab = 0;
+     char *zTab = shellMPrintf(pRc, "%s", zLostAndFound);
+     sqlite3_stmt *pTest = 0;
+     shellPrepare(pState->db, pRc,
+         "SELECT 1 FROM recovery.schema WHERE name=?", &pTest
+     );
+     if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
+     while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){
+       shellReset(pRc, pTest);
+       sqlite3_free(zTab);
+       zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++);
+       sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
+     }
+     shellFinalize(pRc, pTest);
+     pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable));
+     if( pTab ){
+       pTab->zQuoted = shellMPrintf(pRc, "%Q", zTab);
+       pTab->nCol = nCol;
+       pTab->iPk = -2;
+       if( nCol>0 ){
+         pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1));
+         if( pTab->azlCol ){
+           pTab->azlCol[nCol] = shellMPrintf(pRc, "");
+           for(i=nCol-1; i>=0; i--){
+             pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]);
+           }
+         }
+       }
+       if( *pRc!=SQLITE_OK ){
+         recoverFreeTable(pTab);
+         pTab = 0;
+       }else{
+         raw_printf(pState->out, 
+             "CREATE TABLE %s(rootpgno INTEGER, "
+             "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted
          );
-         goto end_ar_command;
+         for(i=0; i<nCol; i++){
+           raw_printf(pState->out, ", c%d", i);
+         }
+         raw_printf(pState->out, ");\n");
        }
-       sqlite3_fileio_init(cmd.db, 0, 0);
-       sqlite3_sqlar_init(cmd.db, 0, 0);
-       sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
-                               shellPutsFunc, 0, 0);
+     }
+     sqlite3_free(zTab);
+   }
+   return pTab;
+ }
+ /*
+ ** This function is called to recover data from the database. A script
+ ** to construct a new database containing all recovered data is output
+ ** on stream pState->out.
+ */
+ static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
+   int rc = SQLITE_OK;
+   sqlite3_stmt *pLoop = 0;        /* Loop through all root pages */
+   sqlite3_stmt *pPages = 0;       /* Loop through all pages in a group */
+   sqlite3_stmt *pCells = 0;       /* Loop through all cells in a page */
+   const char *zRecoveryDb = "";   /* Name of "recovery" database */
+   const char *zLostAndFound = "lost_and_found";
+   int i;
+   int nOrphan = -1;
+   RecoverTable *pOrphan = 0;
  
+   int bFreelist = 1;              /* 0 if --freelist-corrupt is specified */
+   for(i=1; i<nArg; i++){
+     char *z = azArg[i];
+     int n;
+     if( z[0]=='-' && z[1]=='-' ) z++;
+     n = strlen(z);
+     if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){
+       bFreelist = 0;
+     }else
+     if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
+       i++;
+       zRecoveryDb = azArg[i];
+     }else
+     if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
+       i++;
+       zLostAndFound = azArg[i];
      }
-     if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
-       if( cmd.eCmd!=AR_CMD_CREATE
-        && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
-       ){
-         utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
-         rc = SQLITE_ERROR;
-         goto end_ar_command;
-       }
-       cmd.zSrcTable = sqlite3_mprintf("sqlar");
+     else{
+       raw_printf(stderr, "unexpected option: %s\n", azArg[i]); 
+       raw_printf(stderr, "options are:\n");
+       raw_printf(stderr, "    --freelist-corrupt\n");
+       raw_printf(stderr, "    --recovery-db DATABASE\n");
+       raw_printf(stderr, "    --lost-and-found TABLE-NAME\n");
+       return 1;
      }
+   }
  
-     switch( cmd.eCmd ){
-       case AR_CMD_CREATE:
-         rc = arCreateOrUpdateCommand(&cmd, 0, 0);
-         break;
+   shellExecPrintf(pState->db, &rc,
+     /* Attach an in-memory database named 'recovery'. Create an indexed 
+     ** cache of the sqlite_dbptr virtual table. */
+     "ATTACH %Q AS recovery;"
+     "DROP TABLE IF EXISTS recovery.dbptr;"
+     "DROP TABLE IF EXISTS recovery.freelist;"
+     "DROP TABLE IF EXISTS recovery.map;"
+     "DROP TABLE IF EXISTS recovery.schema;"
+     "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb
+   );
  
-       case AR_CMD_EXTRACT:
-         rc = arExtractCommand(&cmd);
-         break;
+   if( bFreelist ){
+     shellExec(pState->db, &rc,
+       "WITH trunk(pgno) AS ("
+       "  SELECT shell_int32("
+       "      (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x "
+       "      WHERE x>0"
+       "    UNION"
+       "  SELECT shell_int32("
+       "      (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x "
+       "      FROM trunk WHERE x>0"
+       "),"
+       "freelist(data, n, freepgno) AS ("
+       "  SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno "
+       "      FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno"
+       "    UNION ALL"
+       "  SELECT data, n-1, shell_int32(data, 2+n) "
+       "      FROM freelist WHERE n>=0"
+       ")"
+       "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;"
+     );
+   }
  
-       case AR_CMD_LIST:
-         rc = arListCommand(&cmd);
-         break;
+   shellExec(pState->db, &rc, 
+     "CREATE TABLE recovery.dbptr("
+     "      pgno, child, PRIMARY KEY(child, pgno)"
+     ") WITHOUT ROWID;"
+     "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) "
+     "    SELECT * FROM sqlite_dbptr"
+     "      WHERE pgno NOT IN freelist AND child NOT IN freelist;"
  
-       case AR_CMD_HELP:
-         arUsage(pState->out);
-         break;
+     /* Delete any pointer to page 1. This ensures that page 1 is considered
+     ** a root page, regardless of how corrupt the db is. */
+     "DELETE FROM recovery.dbptr WHERE child = 1;"
  
-       case AR_CMD_INSERT:
-         rc = arCreateOrUpdateCommand(&cmd, 1, 0);
-         break;
+     /* Delete all pointers to any pages that have more than one pointer
+     ** to them. Such pages will be treated as root pages when recovering
+     ** data.  */
+     "DELETE FROM recovery.dbptr WHERE child IN ("
+     "  SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1"
+     ");"
  
-       default:
-         assert( cmd.eCmd==AR_CMD_UPDATE );
-         rc = arCreateOrUpdateCommand(&cmd, 1, 1);
-         break;
+     /* Create the "map" table that will (eventually) contain instructions
+     ** for dealing with each page in the db that contains one or more 
+     ** records. */
+     "CREATE TABLE recovery.map("
+       "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT"
+     ");"
+     /* Populate table [map]. If there are circular loops of pages in the
+     ** database, the following adds all pages in such a loop to the map
+     ** as individual root pages. This could be handled better.  */
+     "WITH pages(i, maxlen) AS ("
+     "  SELECT page_count, ("
+     "    SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count"
+     "  ) FROM pragma_page_count WHERE page_count>0"
+     "    UNION ALL"
+     "  SELECT i-1, ("
+     "    SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1"
+     "  ) FROM pages WHERE i>=2"
+     ")"
+     "INSERT INTO recovery.map(pgno, maxlen, intkey, root) "
+     "  SELECT i, maxlen, NULL, ("
+     "    WITH p(orig, pgno, parent) AS ("
+     "      SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)"
+     "        UNION "
+     "      SELECT i, p.parent, "
+     "        (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p"
+     "    )"
+     "    SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)"
+     ") "
+     "FROM pages WHERE maxlen > 0 AND i NOT IN freelist;"
+     "UPDATE recovery.map AS o SET intkey = ("
+     "  SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno"
+     ");"
+     /* Extract data from page 1 and any linked pages into table
+     ** recovery.schema. With the same schema as an sqlite_master table.  */
+     "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
+     "INSERT INTO recovery.schema SELECT "
+     "  max(CASE WHEN field=0 THEN value ELSE NULL END),"
+     "  max(CASE WHEN field=1 THEN value ELSE NULL END),"
+     "  max(CASE WHEN field=2 THEN value ELSE NULL END),"
+     "  max(CASE WHEN field=3 THEN value ELSE NULL END),"
+     "  max(CASE WHEN field=4 THEN value ELSE NULL END)"
+     "FROM sqlite_dbdata WHERE pgno IN ("
+     "  SELECT pgno FROM recovery.map WHERE root=1"
+     ")"
+     "GROUP BY pgno, cell;"
+     "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);"
+   );
+   /* Open a transaction, then print out all non-virtual, non-"sqlite_%" 
+   ** CREATE TABLE statements that extracted from the existing schema.  */
+   if( rc==SQLITE_OK ){
+     sqlite3_stmt *pStmt = 0;
+     raw_printf(pState->out, "BEGIN;\n");
+     raw_printf(pState->out, "PRAGMA writable_schema = on;\n");
+     shellPrepare(pState->db, &rc,
+         "SELECT sql FROM recovery.schema "
+         "WHERE type='table' AND sql LIKE 'create table%'", &pStmt
+     );
+     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+       const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0);
+       raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n", 
+           &zCreateTable[12]
+       );
      }
+     shellFinalize(&rc, pStmt);
    }
- end_ar_command:
-   if( cmd.db!=pState->db ){
-     close_db(cmd.db);
+   /* Figure out if an orphan table will be required. And if so, how many
+   ** user columns it should contain */
+   shellPrepare(pState->db, &rc, 
+       "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1"
+       , &pLoop
+   );
+   if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
+     nOrphan = sqlite3_column_int(pLoop, 0);
+   }
+   shellFinalize(&rc, pLoop);
+   pLoop = 0;
+   shellPrepare(pState->db, &rc,
+       "SELECT pgno FROM recovery.map WHERE root=?", &pPages
+   );
+   shellPrepare(pState->db, &rc,
+       "SELECT max(field), group_concat(shell_escape_crnl(quote(value)), ', ')"
+       "FROM sqlite_dbdata WHERE pgno = ? AND field != ?"
+       "GROUP BY cell", &pCells
+   );
+   /* Loop through each root page. */
+   shellPrepare(pState->db, &rc, 
+       "SELECT root, intkey, max(maxlen) FROM recovery.map" 
+       " WHERE root>1 GROUP BY root, intkey ORDER BY root=("
+       "  SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'"
+       ")", &pLoop
+   );
+   while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
+     int iRoot = sqlite3_column_int(pLoop, 0);
+     int bIntkey = sqlite3_column_int(pLoop, 1);
+     int nCol = sqlite3_column_int(pLoop, 2);
+     int bNoop = 0;
+     RecoverTable *pTab;
+     pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop);
+     if( bNoop || rc ) continue;
+     if( pTab==0 ){
+       if( pOrphan==0 ){
+         pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
+       }
+       pTab = pOrphan;
+       if( pTab==0 ) break;
+     }
+     if( 0==sqlite3_stricmp(pTab->zQuoted, "'sqlite_sequence'") ){
+       raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
+     }
+     sqlite3_bind_int(pPages, 1, iRoot);
+     sqlite3_bind_int(pCells, 2, pTab->iPk);
+     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){
+       int iPgno = sqlite3_column_int(pPages, 0);
+       sqlite3_bind_int(pCells, 1, iPgno);
+       while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){
+         int nField = sqlite3_column_int(pCells, 0);
+         const char *zVal = (const char*)sqlite3_column_text(pCells, 1);
+         nField = nField+1;
+         if( pTab==pOrphan ){
+           raw_printf(pState->out, 
+               "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
+               pTab->zQuoted, iRoot, iPgno, nField, 
+               bIntkey ? "" : "NULL, ", zVal, pTab->azlCol[nField]
+           );
+         }else{
+           raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n", 
+               pTab->zQuoted, pTab->azlCol[nField], zVal
+           );
+         }
+       }
+       shellReset(&rc, pCells);
+     }
+     shellReset(&rc, pPages);
+     if( pTab!=pOrphan ) recoverFreeTable(pTab);
+   }
+   shellFinalize(&rc, pLoop);
+   shellFinalize(&rc, pPages);
+   shellFinalize(&rc, pCells);
+   recoverFreeTable(pOrphan);
+   /* The rest of the schema */
+   if( rc==SQLITE_OK ){
+     sqlite3_stmt *pStmt = 0;
+     shellPrepare(pState->db, &rc, 
+         "SELECT sql, name FROM recovery.schema "
+         "WHERE sql NOT LIKE 'create table%'", &pStmt
+     );
+     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+       const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
+       if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){
+         const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
+         char *zPrint = shellMPrintf(&rc, 
+           "INSERT INTO sqlite_master VALUES('table', %Q, %Q, 0, %Q)",
+           zName, zName, zSql
+         );
+         raw_printf(pState->out, "%s;\n", zPrint);
+         sqlite3_free(zPrint);
+       }else{
+         raw_printf(pState->out, "%s;\n", zSql);
+       }
+     }
+     shellFinalize(&rc, pStmt);
    }
-   sqlite3_free(cmd.zSrcTable);
  
+   if( rc==SQLITE_OK ){
+     raw_printf(pState->out, "PRAGMA writable_schema = off;\n");
+     raw_printf(pState->out, "COMMIT;\n");
+   }
+   sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0);
    return rc;
  }
- /* End of the ".archive" or ".ar" command logic
- **********************************************************************************/
- #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
+ #endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
  
  
  /*
diff --cc src/sqlite.h.in
Simple merge
diff --cc src/sqliteInt.h
Simple merge
diff --cc src/vacuum.c
Simple merge
diff --cc src/vdbe.c
Simple merge
diff --cc src/vdbeaux.c
Simple merge
diff --cc src/vtab.c
Simple merge
Simple merge