Compare commits

...

13 Commits

Author SHA1 Message Date
dan f1153208df Consolidate the two sqlite3SchemaToIndex() routines.
FossilOrigin-Name: dfab7170edf23de33013ea2af2f512ee978a689a6d218f6f490d46e48b9213b3
2018-11-20 16:02:52 +00:00
dan 0ddce3f141 Fix a problem with virtual tables in shared schemas.
FossilOrigin-Name: 84be9220db4adaf4873cf38d7259a321900608d63be4d08603e74f8b7ae120ac
2018-11-19 20:41:26 +00:00
dan 8e7576eaae Fix another name resolution problem occurring when two or more attached
databases use the same Schema object.

FossilOrigin-Name: 5328f89951b34c9543a7289efd830acb252422a976819eadd036725c1553ec0f
2018-11-17 19:15:25 +00:00
dan f6938fa62b Merge latest trunk changes into this branch.
FossilOrigin-Name: 9fdd186897abea8ebfe575b9b3ce705033a06b2b00b50beb54ebaf892543c227
2018-11-17 18:45:43 +00:00
dan d2b7a58c96 Fix further problems with the feature on this branch.
FossilOrigin-Name: 6d7a7e5faf1c0ff19e4b0681bc25abb909ed60998e635aea03ece5ba51a5ac52
2018-11-17 18:11:09 +00:00
dan e2c2f7c378 Fix further REUSE_SCHEMA issues.
FossilOrigin-Name: 9780829a77a49b199a55e56d21a51d33fee50321621337afabe5a6f977a65eee
2018-11-16 17:04:58 +00:00
dan 11424c94bb Fix some problems with the feature on this branch. Many problems remain.
FossilOrigin-Name: 31b6aee755c81d69aeaf3ae197e510d38e5e3bb83ded44c33379bcd0d4c23300
2018-11-15 21:20:56 +00:00
dan d000f2286d Merge latest trunk changes with this branch.
FossilOrigin-Name: ae88f8e1ffc33748e45308c21ba83499228ae05344df81e41dd61e14a1270588
2018-11-09 18:44:45 +00:00
drh 8874678ecd Add the ability to open a database connection in -reuseschema mode in the CLI.
Adjust memory allocation accounting so that a shared schema is allocated
across each database sharing it.

FossilOrigin-Name: 3869b2106b9a639b5e739dc9f9acd2f7a9223d3ce562297b877c5d4d2bf76468
2018-10-08 23:29:05 +00:00
dan 8612853f70 Fix a problem with using virtual tables via reuse-schema connections.
FossilOrigin-Name: e5897dafda2b003c34eeecb44e091e2ac0d8589c9db728a0b02fb56966cfc9b7
2018-10-08 20:57:35 +00:00
drh 62012c0b34 Merge fixes from trunk.
FossilOrigin-Name: 9c8255a199d6544b02302bfe3ecd253098821170646a509d2e3dc6cf4e43289b
2018-10-08 20:37:21 +00:00
dan 7d3159668c Merge latest trunk changes into this branch.
FossilOrigin-Name: 2ac72114a1f5344b42472b941c60f460c28c981a22ea40909b30f7bf4eb4b11b
2018-10-08 18:58:51 +00:00
dan d6af93a92c Add experimental sqlite3_open_v2() flag SQLITE_OPEN_REUSE_SCHEMA. For sharing
identical in-memory schema objects between connections.

FossilOrigin-Name: a625698048c05375f12ea8875892fdbf3518291f10917fe68dd2294280cd3b42
2017-08-09 20:35:10 +00:00
35 changed files with 932 additions and 283 deletions
+39 -38
View File
@@ -1,5 +1,5 @@
C Fix\sthe\sregexp\sused\sto\srecognize\slibdl\serrors\son\sOS-X.
D 2018-11-17T14:59:35.957
C Consolidate\sthe\stwo\ssqlite3SchemaToIndex()\sroutines.
D 2018-11-20T16:02:52.908
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in b730006b54c990461d864c5387f2e6f13aadb0236804555fb010ed6865a5f058
@@ -440,37 +440,37 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 61c1ace40a9e39c45a975cb6c57a1a283a262ea21bbe3fb5b473708b790a8d43
F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
F src/alter.c f4ba663ee11eaf3a17c0b21a8e377a9e8991627b0afe994fcce8f44faf566669
F src/analyze.c 09c9684253a328735c63f714e1c50360e977b4020b7b1325d11dd46f2f192123
F src/attach.c 92b51739a885da8bd84bc9a05485f1e48148bce5c15432f059b45af98fff75cd
F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
F src/auth.c 6ea0bfef8f2d972358f40c349a7ae431649adb3ca2aac73dc2f3b4e8fb4c33b8
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btmutex.c 786ad5319e5a889711043db3136c8b7f58bcdd53327410dd2330d02be1eab69d
F src/btree.c 3ef104ecae8b1b5f0458be1f5fa7c1ecf25fdc322a9d63bb8151f89eb32d381e
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
F src/build.c 5bc91901b05ac7a33a324854bd2aa892311e71b82a887f99f390bead39e29175
F src/callback.c 789bd33d188146f66c0dd8306472a72d1c05f71924b24a91caf6bd45cf9aba73
F src/build.c d31ac32f9fe0e35f3953bd4f287c8d025ad89af6a78697e054ea8d59f07a4577
F src/callback.c e5031c28f6e8eb2f290298e262eb1eb5f201ef2ae25db54b396882ae2059e944
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
F src/delete.c cec65c0e74be7492cafba1b77580732b0b1a41a4dbc4ac70909ac44b65b2a20b
F src/expr.c 9aacc0b72348ba90010b672dcbbbe2fa56e1182043bc917a3a147b2bc57a5497
F src/delete.c 65e16dc1cf64eab1b6761aefbacefc4b983d2f9ed7265f050b88689a271c1741
F src/expr.c 38c50318213e42b579189a7438a53c19833486ecbe97da9bfac3bd39242a0c56
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 972a4ba14296bef2303a0abbad1e3d82bc3c61f9e6ce4e8e9528bdee68748812
F src/fkey.c 2c112c00667b3c4668023a000489261d5b72441c67f969b526a1af831d297d96
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
F src/hash.c 931ec82d7e070654a8facb42549bbb3a25720171d73ba94c3d3160580d01ef1f
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 6b81aae27b196925d8ff78824f4bbd435d6a40cd38dc324685e21735bb402109
F src/insert.c 037e39bd36cef876e376663e3c1fb74b19267b0f13036c304fbb2b01c4aaff05
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 448eab53ecdb566a1259ee2d45ebff9c0bc4a2cf393774488775c33e4fbe89bf
F src/main.c 0efc9f6fba87f7b406135062c9a1f00c5f73487730e38794c698be5f78cfea54
F src/main.c 63ec9559c244c7e10eafc0efe0f66387fc40b8683ba20aeb0422e334f4eb0a52
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -499,23 +499,23 @@ F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179
F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
F src/pragma.c 3a5f39517cbe90af3271fb5dd2866a50fbcf4ced6cb464dcc80a6f763b415206
F src/pragma.c f9b6a7f8136a1df3830d3e91e526a43c75a2b1db24795813871fbc86dd683db7
F src/pragma.h fdd03d78a7497f74a3f652909f945328480089189526841ae829ce7313d98d13
F src/prepare.c f81f8d707e583192c28fea0b2e19385415b7d188123b23f49b038076408d7a69
F src/prepare.c fc8c448c4df0c23d5087e8069a2e03598ed1be9a567c9bc70f49b829e76b61ad
F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073
F src/resolve.c 23c3d8c311b71da12b57be43b27e84a97b500dabda4eabb74d2bbc750a5ab7c1
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f
F src/shell.c.in 6a9d8a56700d136addc14d1cd25863b8112e5c12e1877f373750bda476ff6314
F src/sqlite.h.in 61035b527eab8097017ce77180bbfa88d76cd5661aa366c752d0bdc8a60da8d1
F src/select.c 88f6aab4f5f0d1c13fef55d07ff6dcfb8d44aec8b65ca8e7038ef3f889f9e324
F src/shell.c.in 91ccfc85bcd28015c5db01449275e7fba3e9f97aa2533b53b73e81906eebaac0
F src/sqlite.h.in 3baffc1c299e0c10dc63f31ce4b322d14548dae6ac73b0719ba505b37966bac3
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
F src/sqliteInt.h c10361d952c33521111861ed4b0d625b62ad29b5fc4ee5e296a74cb032dc3cf3
F src/sqliteInt.h a499dea6afe4123faf1ef1461b9b23738b6578009a648bbab0fab1e7c2e696ad
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/status.c b651e68af3cb859e4083c79e0e7177e2aeb35ed23e3892d7bbe5b732d38bf2b9
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6
F src/tclsqlite.c b15e46bdc1b14e994a358d51ce0bf8b7d7d4615cda96634ca0498ee39bc83b9c
F src/test1.c b95363b0bc9e1ecc61964ca5a22c137422af4808a54a7bbb1a4f7d6d6257f704
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
@@ -571,30 +571,30 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 9e781e1ca80eefe7b5d6a9e2cd5c678c847da55fd6f093781fad7950934d4c83
F src/treeview.c 7b12ac059de54c939b6eb0dbffc9410c29c80d2470cee5cbe07d5ff9ea2d9253
F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd
F src/update.c 1816d56c1bca1ba4e0ef98cac2f49be62858e9df1dc08844c7067eb41cc44274
F src/trigger.c e143e102daa1791d990a447ef4bfb0fb5f6a502bebf98fee7f868e66f6664c38
F src/update.c 792c3c1ccef5794a63a9b2cb0fc183b9357dd64b3614c7aa1460dd3becd177c5
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 836cadc922de866c849e23a75f93d344cdc143d388339305d09a3fed27e8798d
F src/vdbe.c 005e691ea4c7d51e6c1a69d9389aeb34700884c85f51681817ddea3fdc2fc39b
F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
F src/vdbeInt.h 437e6c6af679fdf157867eb83a8adc6cf5145d6774453c2214cfd0bd01d92980
F src/vacuum.c 87907c331ea9acdd887504869a91449d90df6a7debbabb9e52e6e71aa42178ff
F src/vdbe.c 103913320325dc5848449a8f9a8470b1b67d74dc47d67ade1c7d6024b50517a5
F src/vdbe.h fda06d544a79e684797e7d433e5c410e563f8d3897098826e4c23cdb3be4193e
F src/vdbeInt.h edfb25fc654f9d6d31ba47b161326f984f897e4b6e49cb8e9ee8708215023e0b
F src/vdbeapi.c ecccfce6f614c33a95952efeec969d163e8349eac314ee2b7b163eda921b5eb0
F src/vdbeaux.c f547901b1aa9e2d81c63f06893f633648e434180666a827aacb547d7d6c8a601
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbeaux.c 5e83d8a9e6513d14f17810c70a87d4876bf9f2b55eb78bec8571fe37a37ade1a
F src/vdbeblob.c bef4668e92c33b47933aa24ffa9a982617f59a5330d927fd5d33ab42bc3e01c6
F src/vdbemem.c 7b3305bc4a5139f4536ac9b5f61da0f915e49d2e3fdfa87dfdfa9d7aba8bc1e9
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 70188a745dc4e57d26e942681ff4b2912b7c8249ad5de3f60f0677b4337bcfaa
F src/vtab.c 9b380532e2e9fa5c559e2f59b702c4e87b32a6146a9e273e299315547fbd705c
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
F src/where.c 3818e8a736a05d2cb194e64399af707e367fbcc5c251d785804d02eaf121288e
F src/where.c fded04f3d811ced6281f7d24cc2d03d9fc4d5ce403d616cfef7dbcccbdbaf4c3
F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
F src/wherecode.c c45f03aefc2266b990df0fc4d7acc4e27f56f881f4fc0fc355b7cbc4d7189da5
F src/whereexpr.c 491f0894ad9903750cdecb7894437a0cabdffdd88f574d2b1c9ac85d14fe4b9c
F src/whereexpr.c 833b58f9d34fa8118bf671b695a9929028707e13bf7e16e932d80c9c64d5f0a3
F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
@@ -1207,6 +1207,7 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl c5b474f9880073fc3b69729ee05d5284653a9ee101af572204917d9dcb1d9015 x
F test/resetdb.test 373a9eb8fcbd58bf87affec6a88c6353038f98a5d25be5ab75a0b9636c462a36
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/reuse1.test 85c107d2c45a99e148f639d28e7b839b9981a5aa6856c4ec969072ce5b64eaf4
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
@@ -1346,7 +1347,7 @@ F test/tabfunc01.test 54300134f76db817685194d2f0e63e3fbf7380b45e0d426e00a9aee752
F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
F test/tclsqlite.test dca8aa30d84175e7d8c8fc43d3ffa11fa56e23fbdac2679d03833a0f326edf34
F test/tclsqlite.test 049da602775bebfadfa2fae0710e1099a38ef2fc9f76c7546be3ba8fdbb02263
F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
F test/tempdb2.test 4749545409c6d7438b435c3f05cdd139cf4145a954a6908d19e3443ffd8724b3
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
@@ -1778,7 +1779,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 5fff00b0d5eb634d40e767671d5a0e8bd263d15d88abe531f6072f01bc789568
R 76c317bc545b1ccc5ede987ad2f5f352
U drh
Z 5574305e87d3c067cc9d9e5ce2644399
P 84be9220db4adaf4873cf38d7259a321900608d63be4d08603e74f8b7ae120ac
R 6da38ba0540b642f9b1cc73aec9a5fb5
U dan
Z 47b1db7061e0aabc455eabfcd73eae34
+1 -1
View File
@@ -1 +1 @@
1740025307531a52e4f0641e2e74dc14715130858f2e9236be13b66924f00220
dfab7170edf23de33013ea2af2f512ee978a689a6d218f6f490d46e48b9213b3
+43 -39
View File
@@ -74,8 +74,8 @@ static void renameReloadSchema(Parse *pParse, int iDb){
Vdbe *v = pParse->pVdbe;
if( v ){
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
sqlite3VdbeAddParseSchemaOp(pParse, iDb, 0);
if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse, 1, 0);
}
}
@@ -106,7 +106,7 @@ void sqlite3AlterRenameTable(
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema, 0);
zDb = db->aDb[iDb].zDbSName;
db->mDbFlags |= DBFLAG_PreferBuiltin;
@@ -148,11 +148,11 @@ void sqlite3AlterRenameTable(
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
if( sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
goto exit_rename_table;
}
if( IsVirtual(pTab) ){
pVTab = sqlite3GetVTable(db, pTab);
pVTab = sqlite3GetVTable(db, -1, pTab);
if( pVTab->pVtab->pModule->xRename==0 ){
pVTab = 0;
}
@@ -276,7 +276,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
assert( pNew );
assert( sqlite3BtreeHoldsAllMutexes(db) );
iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
iDb = sqlite3SchemaToIndex(db, pNew->pSchema, 0);
zDb = db->aDb[iDb].zDbSName;
zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
pCol = &pNew->aCol[pNew->nCol-1];
@@ -429,7 +429,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
}
assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
/* Put a copy of the Table struct in Parse.pNewTable for the
** sqlite3AddColumn() function and friends to modify. But modify
@@ -530,7 +530,7 @@ void sqlite3AlterRenameColumn(
if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
/* Which schema holds the table to be altered */
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
assert( iSchema>=0 );
zDb = db->aDb[iSchema].zDbSName;
@@ -1058,13 +1058,14 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
sNC.pParse = pParse;
assert( pNew->pTabSchema );
pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema, 0)].zDbSName
);
pParse->eTriggerOp = pNew->op;
/* ALWAYS() because if the table of the trigger does not exist, the
** error would have been hit before this point */
if( ALWAYS(pParse->pTriggerTab) ){
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
int iDb = sqlite3SchemaToIndex(db, pParse->pTriggerTab->pSchema, 0);
rc = sqlite3ViewGetColumnNames(pParse, iDb, pParse->pTriggerTab);
}
/* Resolve symbols in WHEN clause */
@@ -1081,38 +1082,41 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
if( pTarget==0 ){
rc = SQLITE_ERROR;
}else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
SrcList sSrc;
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = pStep->zTarget;
sSrc.a[0].pTab = pTarget;
sNC.pSrcList = &sSrc;
if( pStep->pWhere ){
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
}
if( rc==SQLITE_OK ){
rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
}
assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
if( pStep->pUpsert ){
Upsert *pUpsert = pStep->pUpsert;
assert( rc==SQLITE_OK );
pUpsert->pUpsertSrc = &sSrc;
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
if( rc==SQLITE_OK ){
ExprList *pUpsertSet = pUpsert->pUpsertSet;
rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
}else{
int iDb = sqlite3SchemaToIndex(db, pTarget->pSchema, 0);
if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, iDb, pTarget)) ){
SrcList sSrc;
memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1;
sSrc.a[0].zName = pStep->zTarget;
sSrc.a[0].pTab = pTarget;
sNC.pSrcList = &sSrc;
if( pStep->pWhere ){
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
}
if( rc==SQLITE_OK ){
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
}
if( rc==SQLITE_OK ){
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
if( pStep->pUpsert ){
Upsert *pUpsert = pStep->pUpsert;
assert( rc==SQLITE_OK );
pUpsert->pUpsertSrc = &sSrc;
sNC.uNC.pUpsert = pUpsert;
sNC.ncFlags = NC_UUpsert;
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
if( rc==SQLITE_OK ){
ExprList *pUpsertSet = pUpsert->pUpsertSet;
rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
}
if( rc==SQLITE_OK ){
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
}
if( rc==SQLITE_OK ){
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
}
sNC.ncFlags = 0;
}
sNC.ncFlags = 0;
}
}
}
@@ -1575,7 +1579,7 @@ static void renameTableTest(
rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
}
if( rc==SQLITE_OK ){
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema, 0);
int i2 = sqlite3FindDbName(db, zDb);
if( i1==i2 ) sqlite3_result_int(context, 1);
}
+9 -10
View File
@@ -979,6 +979,7 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
*/
static void analyzeOneTable(
Parse *pParse, /* Parser context */
int iDb, /* Database that contains table pTab */
Table *pTab, /* Table whose indices are to be analyzed */
Index *pOnlyIdx, /* If not NULL, only analyze this one index */
int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
@@ -992,7 +993,6 @@ static void analyzeOneTable(
Vdbe *v; /* The virtual machine being built up */
int i; /* Loop counter */
int jZeroRows = -1; /* Jump from here if number of rows is zero */
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 */
@@ -1023,7 +1023,6 @@ static void analyzeOneTable(
return;
}
assert( sqlite3BtreeHoldsAllMutexes(db) );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb>=0 );
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -1118,7 +1117,7 @@ static void analyzeOneTable(
pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
assert( db->aDb[iDb].pSchema==pIdx->pSchema );
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
@@ -1348,7 +1347,7 @@ static void analyzeDatabase(Parse *pParse, int iDb){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
analyzeOneTable(pParse, iDb, pTab, 0, iStatCur, iMem, iTab);
}
loadAnalysis(pParse, iDb);
}
@@ -1358,13 +1357,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
** a database. If pOnlyIdx is not NULL then it is a single index
** in pTab that should be analyzed.
*/
static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
int iDb;
static void analyzeTable(Parse *pParse, int iDb, Table *pTab, Index *pOnlyIdx){
int iStatCur;
assert( pTab!=0 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab;
pParse->nTab += 3;
@@ -1373,7 +1370,9 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
}else{
openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
}
analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab);
analyzeOneTable(pParse, iDb, pTab,
pOnlyIdx, iStatCur, pParse->nMem+1, pParse->nTab
);
loadAnalysis(pParse, iDb);
}
@@ -1424,9 +1423,9 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
z = sqlite3NameFromToken(db, pTableName);
if( z ){
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
analyzeTable(pParse, pIdx->pTable, pIdx);
analyzeTable(pParse, iDb, pIdx->pTable, pIdx);
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
analyzeTable(pParse, pTab, 0);
analyzeTable(pParse, iDb, pTab, 0);
}
sqlite3DbFree(db, z);
}
+1 -1
View File
@@ -153,7 +153,7 @@ void sqlite3AuthRead(
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
if( db->xAuth==0 ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
iDb = sqlite3SchemaToIndex(pParse->db, pSchema, 0); /* TODO! */
if( iDb<0 ){
/* An attempt to read a column out of a subquery or other
** temporary table. */
+2 -1
View File
@@ -252,7 +252,8 @@ int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
if( pSchema && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) ) return 1;
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema, 0);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
if( iDb==1 ) return 1;
+54 -41
View File
@@ -191,7 +191,7 @@ void sqlite3FinishCoding(Parse *pParse){
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<pParse->nVtabLock; i++){
char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
char *vtab = (char *)pParse->apVtabLock[i];
sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
}
pParse->nVtabLock = 0;
@@ -266,7 +266,9 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
sqlite3RunParser(pParse, zSql, &zErrMsg);
sqlite3DbFree(db, zErrMsg);
if( zErrMsg ){
sqlite3ErrorMsg(pParse, "%z", zErrMsg);
}
sqlite3DbFree(db, zSql);
memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
pParse->nested--;
@@ -395,9 +397,14 @@ Table *sqlite3LocateTableItem(
struct SrcList_item *p
){
const char *zDb;
assert( p->pSchema==0 || p->zDatabase==0 );
if( p->pSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
if( pParse->iFixDb && pParse->iFixDb!=2 ){
zDb = pParse->db->aDb[pParse->iFixDb-1].zDbSName;
assert( p->zDatabase==0 || sqlite3StrICmp(p->zDatabase, zDb)==0 );
if( p->zDatabase==0 ){
p->zDatabase = sqlite3DbStrDup(pParse->db, zDb);
}
}else if( p->pSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema, 0);
zDb = pParse->db->aDb[iDb].zDbSName;
}else{
zDb = p->zDatabase;
@@ -527,11 +534,14 @@ void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
DbSetProperty(db, 1, DB_ResetWanted);
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
}
if( db->nSchemaLock==0 ){
for(i=0; i<db->nDb; i++){
if( DbHasProperty(db, i, DB_ResetWanted) ){
sqlite3SchemaClear(db->aDb[i].pSchema);
if( i==1 ){
sqlite3SchemaClear(db->aDb[1].pSchema);
}else{
sqlite3SchemaUnuse(db, i);
}
}
}
}
@@ -545,12 +555,10 @@ void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
int i;
sqlite3BtreeEnterAll(db);
assert( db->nSchemaLock==0 );
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pSchema ){
sqlite3SchemaClear(pDb->pSchema);
}
for(i=0; i<db->nDb; i=(i?i+1:2)){
sqlite3SchemaUnuse(db, i);
}
sqlite3SchemaClear(db->aDb[1].pSchema);
db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
@@ -1996,7 +2004,7 @@ void sqlite3EndTable(
}
}
iDb = sqlite3SchemaToIndex(db, p->pSchema);
iDb = sqlite3SchemaToIndex(db, p->pSchema, 0);
#ifndef SQLITE_OMIT_CHECK
/* Resolve names in all CHECK constraint expressions.
@@ -2150,7 +2158,7 @@ void sqlite3EndTable(
#endif
/* Reparse everything to update our internal data structures */
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
}
@@ -2216,7 +2224,7 @@ void sqlite3CreateView(
p = pParse->pNewTable;
if( p==0 || pParse->nErr ) goto create_view_fail;
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
iDb = sqlite3SchemaToIndex(db, p->pSchema);
iDb = sqlite3SchemaToIndex(db, p->pSchema, 0);
sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;
@@ -2269,7 +2277,7 @@ create_view_fail:
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int sqlite3ViewGetColumnNames(Parse *pParse, int iDb, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
@@ -2286,7 +2294,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#ifndef SQLITE_OMIT_VIRTUALTABLE
db->nSchemaLock++;
rc = sqlite3VtabCallConnect(pParse, pTable);
rc = sqlite3VtabCallConnect(pParse, iDb, pTable);
db->nSchemaLock--;
if( rc ){
return 1;
@@ -2533,7 +2541,7 @@ static void destroyTable(Parse *pParse, Table *pTab){
if( iLargest==0 ){
return;
}else{
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema, 0);
assert( iDb>=0 && iDb<pParse->db->nDb );
destroyRootPage(pParse, iLargest, iDb);
iDestroyed = iLargest;
@@ -2660,13 +2668,14 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
goto exit_drop_table;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
assert( iDb>=0 && iDb<db->nDb );
sqlite3SchemaWritable(pParse, iDb);
/* If pTab is a virtual table, call ViewGetColumnNames() to ensure
** it is initialized.
*/
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, pTab) ){
if( IsVirtual(pTab) && sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
goto exit_drop_table;
}
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -2687,7 +2696,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
#ifndef SQLITE_OMIT_VIRTUALTABLE
}else if( IsVirtual(pTab) ){
code = SQLITE_DROP_VTABLE;
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
zArg2 = sqlite3GetVTable(db, -1, pTab)->pMod->zName;
#endif
}else{
if( !OMIT_TEMPDB && iDb==1 ){
@@ -2908,7 +2917,12 @@ void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
** the index already exists and must be cleared before being refilled and
** the root page number of the index is taken from pIndex->tnum.
*/
static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
static void sqlite3RefillIndex(
Parse *pParse,
int iDb,
Index *pIndex,
int memRootPage
){
Table *pTab = pIndex->pTable; /* The table that is indexed */
int iTab = pParse->nTab++; /* Btree cursor used for pTab */
int iIdx = pParse->nTab++; /* Btree cursor used for pIndex */
@@ -2921,7 +2935,6 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
KeyInfo *pKey; /* KeyInfo for index */
int regRecord; /* Register holding assembled index record */
sqlite3 *db = pParse->db; /* The database connection */
int iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
@@ -3055,7 +3068,6 @@ void sqlite3CreateIndex(
char *zName = 0; /* Name of the index */
int nName; /* Number of characters in zName */
int i, j;
DbFixer sFix; /* For assigning database names to pTable */
int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */
sqlite3 *db = pParse->db;
Db *pDb; /* The specific table containing the indexed database */
@@ -3104,13 +3116,9 @@ void sqlite3CreateIndex(
}
#endif
sqlite3FixInit(&sFix, pParse, iDb, "index", pName);
if( sqlite3FixSrcList(&sFix, pTblName) ){
/* Because the parser constructs pTblName from a single identifier,
** sqlite3FixSrcList can never fail. */
assert(0);
}
if( iDb!=1 ) pTblName->a[0].zDatabase = db->aDb[iDb].zDbSName;
pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
pTblName->a[0].zDatabase = 0;
assert( db->mallocFailed==0 || pTab==0 );
if( pTab==0 ) goto exit_create_index;
if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
@@ -3125,7 +3133,7 @@ void sqlite3CreateIndex(
assert( pStart==0 );
pTab = pParse->pNewTable;
if( !pTab ) goto exit_create_index;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
}
pDb = &db->aDb[iDb];
@@ -3548,9 +3556,9 @@ void sqlite3CreateIndex(
** to invalidate all pre-compiled statements.
*/
if( pTblName ){
sqlite3RefillIndex(pParse, pIndex, iMem);
sqlite3RefillIndex(pParse, iDb, pIndex, iMem);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
}
@@ -3563,7 +3571,7 @@ void sqlite3CreateIndex(
** 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.
** UPDATE and INSERT statements.
*/
if( db->init.busy || pTblName==0 ){
if( onError!=OE_Replace || pTab->pIndex==0
@@ -3674,7 +3682,8 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
"or PRIMARY KEY constraint cannot be dropped", 0);
goto exit_drop_index;
}
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema);
iDb = sqlite3SchemaToIndex(db, pIndex->pSchema, 0);
sqlite3SchemaWritable(pParse, iDb);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_INDEX;
@@ -4407,14 +4416,18 @@ static int collationMatch(const char *zColl, Index *pIndex){
** If pColl==0 then recompute all indices of pTab.
*/
#ifndef SQLITE_OMIT_REINDEX
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
static void reindexTable(
Parse *pParse,
int iDb,
Table *pTab,
char const *zColl
){
Index *pIndex; /* An index associated with pTab */
for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
if( zColl==0 || collationMatch(zColl, pIndex) ){
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
sqlite3RefillIndex(pParse, iDb, pIndex, -1);
}
}
}
@@ -4438,7 +4451,7 @@ static void reindexDatabases(Parse *pParse, char const *zColl){
assert( pDb!=0 );
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
pTab = (Table*)sqliteHashData(k);
reindexTable(pParse, pTab, zColl);
reindexTable(pParse, iDb, pTab, zColl);
}
}
}
@@ -4497,7 +4510,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
zDb = db->aDb[iDb].zDbSName;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
reindexTable(pParse, iDb, pTab, 0);
sqlite3DbFree(db, z);
return;
}
@@ -4505,7 +4518,7 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
sqlite3DbFree(db, z);
if( pIndex ){
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
sqlite3RefillIndex(pParse, iDb, pIndex, -1);
return;
}
sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed");
+106 -1
View File
@@ -479,13 +479,117 @@ void sqlite3SchemaClear(void *p){
pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
/*
** Global linked list of sharable Schema objects. Read and write access must
** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex.
*/
static Schema *SQLITE_WSD sharedSchemaList = 0;
/*
** Check that the schema of db iDb is writable (either because it is the temp
** db schema or because the db handle was opened without
** SQLITE_OPEN_REUSE_SCHEMA). If so, do nothing. Otherwise, leave an
** error in the Parse object.
*/
void sqlite3SchemaWritable(Parse *pParse, int iDb){
if( iDb!=1 && (pParse->db->openFlags & SQLITE_OPEN_REUSE_SCHEMA)
&& IN_DECLARE_VTAB==0
){
sqlite3ErrorMsg(pParse, "attempt to modify read-only schema");
}
}
/*
** Replace the Schema object currently associated with database iDb with
** an empty schema object, ready to be populated. If there are multiple
** users of the Schema, this means decrementing the current objects ref
** count and replacing it with a pointer to a new, empty, object. Or, if
** the database handle passed as the first argument of the schema object
** is the only user, remove it from the shared list (if applicable) and
** clear it in place.
*/
void sqlite3SchemaUnuse(sqlite3 *db, int iDb){
Db *pDb = &db->aDb[iDb];
Schema *pSchema;
assert( iDb!=1 );
if( (pSchema = pDb->pSchema) ){
if( (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) ){
sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
assert( pSchema->nRef>=1 );
if( pSchema->nRef==1 ){
Schema **pp;
for(pp=&sharedSchemaList; (*pp); pp=&(*pp)->pNext){
if( *pp==pSchema ){
*pp = pSchema->pNext;
break;
}
}
pSchema->pNext = 0;
}else{
assert( db->openFlags & SQLITE_OPEN_REUSE_SCHEMA );
pSchema->nRef--;
pDb->pSchema = pSchema = 0;
}
sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
}
if( pSchema==0 ){
db->aDb[iDb].pSchema = sqlite3SchemaGet(db, 0);
}else{
sqlite3SchemaClear(pSchema);
}
}
}
/*
** The schema for database iDb of database handle db, which was opened
** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function
** checks the global list (sharedSchemaList) for a matching schema and,
** if one is found, frees the newly parsed Schema object and adds a pointer
** to the existing shared schema in its place. Or, if there is no matching
** schema in the list, then the new schema is added to it.
*/
void sqlite3SchemaReuse(sqlite3 *db, int iDb){
Schema *pSchema = db->aDb[iDb].pSchema;
Schema *p;
assert( pSchema && iDb!=1 );
sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_SCHEMA_REUSE) );
for(p=sharedSchemaList; p; p=p->pNext){
if( p->cksum==pSchema->cksum
&& p->schema_cookie==pSchema->schema_cookie
){
break;
}
}
if( !p ){
/* No matching schema was found. */
pSchema->pNext = sharedSchemaList;
sharedSchemaList = pSchema;
}else{
/* Found a matching schema. Increase its ref count. */
p->nRef++;
}
sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_SCHEMA_REUSE) );
/* If a matching schema was found in the shared schema list, free the
** schema object just parsed, and add a pointer to the matching schema
** to the db handle. */
if( p ){
sqlite3SchemaClear(pSchema);
sqlite3DbFree(0, pSchema);
db->aDb[iDb].pSchema = p;
}
}
/*
** Find and return the schema associated with a BTree. Create
** a new one if necessary.
*/
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Schema * p;
if( pBt ){
if( pBt && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA)==0 ){
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
}else{
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
@@ -498,6 +602,7 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
sqlite3HashInit(&p->trigHash);
sqlite3HashInit(&p->fkeyHash);
p->enc = SQLITE_UTF8;
p->nRef = 1;
}
return p;
}
+18 -19
View File
@@ -62,7 +62,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlite3 *db;
if( IsVirtual(pTab) ){
return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
return sqlite3GetVTable(pParse->db, -1, pTab)->pMod->pModule->xUpdate==0;
}
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db;
@@ -103,6 +103,7 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
*/
void sqlite3MaterializeView(
Parse *pParse, /* Parsing context */
int iDb, /* Database in which view resides */
Table *pView, /* View definition */
Expr *pWhere, /* Optional WHERE clause to be added */
ExprList *pOrderBy, /* Optional ORDER BY clause */
@@ -113,7 +114,6 @@ void sqlite3MaterializeView(
Select *pSel;
SrcList *pFrom;
sqlite3 *db = pParse->db;
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
pWhere = sqlite3ExprDup(db, pWhere, 0);
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
if( pFrom ){
@@ -318,17 +318,17 @@ void sqlite3DeleteFrom(
}
#endif
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pTabList->a[0].zDatabase);
assert( iDb<db->nDb );
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
if( sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
goto delete_from_cleanup;
}
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
db->aDb[iDb].zDbSName);
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
@@ -365,9 +365,7 @@ void sqlite3DeleteFrom(
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
sqlite3MaterializeView(pParse, pTab,
pWhere, pOrderBy, pLimit, iTabCur
);
sqlite3MaterializeView(pParse, iDb, pTab, pWhere, pOrderBy, pLimit,iTabCur);
iDataCur = iIdxCur = iTabCur;
pOrderBy = 0;
pLimit = 0;
@@ -531,8 +529,8 @@ void sqlite3DeleteFrom(
iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
testcase( IsVirtual(pTab) );
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
iTabCur, aToOpen, &iDataCur, &iIdxCur);
sqlite3OpenTableAndIndices(pParse, iDb, pTab, OP_OpenWrite,
OPFLAG_FORDELETE, iTabCur, aToOpen, &iDataCur, &iIdxCur);
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
@@ -565,8 +563,8 @@ void sqlite3DeleteFrom(
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
const char *pVTab = (const char *)sqlite3GetVTable(db, iDb, pTab);
sqlite3VtabMakeWritable(pParse, iDb, pTab);
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
sqlite3MayAbort(pParse);
if( eOnePass==ONEPASS_SINGLE ){
@@ -581,7 +579,7 @@ void sqlite3DeleteFrom(
#endif
{
int count = (pParse->nested==0); /* True to count changes */
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
sqlite3GenerateRowDelete(pParse, iDb, pTab, pTrigger, iDataCur, iIdxCur,
iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
}
@@ -680,6 +678,7 @@ delete_from_cleanup:
*/
void sqlite3GenerateRowDelete(
Parse *pParse, /* Parsing context */
int iDb, /* Database containing pTab */
Table *pTab, /* Table containing the row to be deleted */
Trigger *pTrigger, /* List of triggers to (potentially) fire */
int iDataCur, /* Cursor from which column data is extracted */
@@ -722,7 +721,7 @@ void sqlite3GenerateRowDelete(
/* TODO: Could use temporary registers here. Also could attempt to
** avoid copying the contents of the rowid register. */
mask = sqlite3TriggerColmask(
pParse, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf
pParse, iDb, pTrigger, 0, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onconf
);
mask |= sqlite3FkOldmask(pParse, pTab);
iOld = pParse->nMem+1;
@@ -741,7 +740,7 @@ void sqlite3GenerateRowDelete(
/* Invoke BEFORE DELETE trigger programs. */
addrStart = sqlite3VdbeCurrentAddr(v);
sqlite3CodeRowTrigger(pParse, pTrigger,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger,
TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
);
@@ -764,7 +763,7 @@ void sqlite3GenerateRowDelete(
/* Do FK processing. This call checks that any FK constraints that
** refer to this table (i.e. constraints attached to other tables)
** are not violated by deleting this row. */
sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
sqlite3FkCheck(pParse, iDb, pTab, iOld, 0, 0, 0);
}
/* Delete the index and table entries. Skip this step if pTab is really
@@ -797,10 +796,10 @@ void sqlite3GenerateRowDelete(
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
** handle rows (possibly in other tables) that refer via a foreign key
** to the row just deleted. */
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
sqlite3FkActions(pParse, iDb, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
sqlite3CodeRowTrigger(pParse, pTrigger,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger,
TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
);
+1 -1
View File
@@ -2369,7 +2369,7 @@ int sqlite3FindInIndex(
pTab = p->pSrc->a[0].pTab;
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, p->pSrc->a[0].zDatabase);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+3 -4
View File
@@ -862,6 +862,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
*/
void sqlite3FkCheck(
Parse *pParse, /* Parse context */
int iDb, /* Database containing pTab */
Table *pTab, /* Row is being deleted from this table */
int regOld, /* Previous row data is stored here */
int regNew, /* New row data is stored here */
@@ -870,7 +871,6 @@ void sqlite3FkCheck(
){
sqlite3 *db = pParse->db; /* Database handle */
FKey *pFKey; /* Used to iterate through FKs */
int iDb; /* Index of database containing pTab */
const char *zDb; /* Name of database containing pTab */
int isIgnoreErrors = pParse->disableTriggers;
@@ -879,8 +879,6 @@ void sqlite3FkCheck(
/* If foreign-keys are disabled, this function is a no-op. */
if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName;
/* Loop through all the foreign key constraints for which pTab is the
@@ -1359,6 +1357,7 @@ static Trigger *fkActionTrigger(
*/
void sqlite3FkActions(
Parse *pParse, /* Parse context */
int iDb, /* Database in which pTab resides */
Table *pTab, /* Table being updated or deleted from */
ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */
int regOld, /* Address of array containing old row */
@@ -1375,7 +1374,7 @@ void sqlite3FkActions(
if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){
Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges);
if( pAct ){
sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0);
sqlite3CodeRowTriggerDirect(pParse, iDb, pAct,pTab,regOld,OE_Abort,0);
}
}
}
+18 -17
View File
@@ -168,7 +168,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
int i;
int iEnd = sqlite3VdbeCurrentAddr(v);
#ifndef SQLITE_OMIT_VIRTUALTABLE
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, iDb, pTab) : 0;
#endif
for(i=1; i<iEnd; i++){
@@ -568,7 +568,7 @@ void sqlite3Insert(
if( pTab==0 ){
goto insert_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pTabList->a[0].zDatabase);
assert( iDb<db->nDb );
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
db->aDb[iDb].zDbSName) ){
@@ -596,7 +596,7 @@ void sqlite3Insert(
/* If pTab is really a view, make sure it has been initialized.
** ViewGetColumnNames() is a no-op if pTab is not a view.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
if( sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
goto insert_cleanup;
}
@@ -811,7 +811,7 @@ void sqlite3Insert(
/* If this is not a view, open the table and and all indices */
if( !isView ){
int nIdx;
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
nIdx = sqlite3OpenTableAndIndices(pParse, iDb, pTab, OP_OpenWrite, 0, -1, 0,
&iDataCur, &iIdxCur);
aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
if( aRegIdx==0 ){
@@ -927,7 +927,7 @@ void sqlite3Insert(
}
/* Fire BEFORE or INSTEAD OF triggers */
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
pTab, regCols-pTab->nCol-1, onError, endOfLoop);
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
@@ -1027,8 +1027,8 @@ void sqlite3Insert(
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
const char *pVTab = (const char *)sqlite3GetVTable(db, iDb, pTab);
sqlite3VtabMakeWritable(pParse, iDb, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
@@ -1037,10 +1037,11 @@ void sqlite3Insert(
{
int isReplace; /* Set to true if constraints may cause a replace */
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
sqlite3GenerateConstraintChecks(pParse, iDb, pTab, aRegIdx, iDataCur,
iIdxCur, regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace,
0, pUpsert
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
sqlite3FkCheck(pParse, iDb, pTab, 0, regIns, 0, 0);
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a
@@ -1067,7 +1068,7 @@ void sqlite3Insert(
if( pTrigger ){
/* Code AFTER triggers */
sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
pTab, regData-2-pTab->nCol, onError, endOfLoop);
}
@@ -1274,6 +1275,7 @@ int sqlite3ExprReferencesUpdatedColumn(
*/
void sqlite3GenerateConstraintChecks(
Parse *pParse, /* The parser context */
int iDb, /* Databse that contains pTab */
Table *pTab, /* The table being inserted or updated */
int *aRegIdx, /* Use register aRegIdx[i] for index i. 0 for unused */
int iDataCur, /* Canonical data cursor (main table or PK index) */
@@ -1557,8 +1559,8 @@ void sqlite3GenerateConstraintChecks(
}
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regNewData, 1, 0, OE_Replace, 1, -1);
sqlite3GenerateRowDelete(pParse, iDb, pTab, pTrigger, iDataCur,
iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1);
}else{
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
assert( HasRowid(pTab) );
@@ -1806,7 +1808,7 @@ void sqlite3GenerateConstraintChecks(
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
sqlite3GenerateRowDelete(pParse, iDb, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
seenReplace = 1;
@@ -1967,6 +1969,7 @@ void sqlite3CompleteInsertion(
*/
int sqlite3OpenTableAndIndices(
Parse *pParse, /* Parsing context */
int iDb, /* Database to open pTab in */
Table *pTab, /* Table to be opened */
int op, /* OP_OpenRead or OP_OpenWrite */
u8 p5, /* P5 value for OP_Open* opcodes (except on WITHOUT ROWID) */
@@ -1976,7 +1979,6 @@ int sqlite3OpenTableAndIndices(
int *piIdxCur /* Write the first index cursor number here */
){
int i;
int iDb;
int iDataCur;
Index *pIdx;
Vdbe *v;
@@ -1989,7 +1991,6 @@ int sqlite3OpenTableAndIndices(
** can detect if they are used by mistake in the caller. */
return 0;
}
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
@@ -2284,7 +2285,7 @@ static int xferOptimization(
#ifdef SQLITE_TEST
sqlite3_xferopt_count++;
#endif
iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema);
iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema, pItem->zDatabase);
v = sqlite3GetVdbe(pParse);
sqlite3CodeVerifySchema(pParse, iDbSrc);
iSrc = pParse->nTab++;
+4
View File
@@ -1185,6 +1185,10 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
if( j!=1 ){
if( db->openFlags & SQLITE_OPEN_REUSE_SCHEMA ){
sqlite3SchemaUnuse(db, j);
sqlite3DbFree(0, pDb->pSchema);
}
pDb->pSchema = 0;
}
}
+4 -3
View File
@@ -1088,11 +1088,12 @@ void sqlite3Pragma(
if( pTab ){
int i, k;
int nHidden = 0;
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema, zDb);
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
pParse->nMem = 7;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3ViewGetColumnNames(pParse, pTab);
sqlite3CodeVerifySchema(pParse, iTabDb);
sqlite3ViewGetColumnNames(pParse, iTabDb, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
int isHidden = IsHiddenColumn(pCol);
if( isHidden && pPragma->iArg==0 ){
@@ -1552,7 +1553,7 @@ void sqlite3Pragma(
if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
sqlite3OpenTableAndIndices(pParse, i, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
** reg[8+i] counts the number of entries in the i-th index
+48 -3
View File
@@ -44,6 +44,26 @@ static void corruptSchema(
}
}
/*
** Update the Schema.cksum checksum to account for the database object
** specified by the three arguments following the first.
*/
void schemaUpdateChecksum(
Schema *pSchema, /* Schema object being parsed */
const char *zName, /* Name of new database object */
const char *zRoot, /* Root page of new database object */
const char *zSql /* SQL used to create new database object */
){
int i;
u64 cksum = pSchema->cksum;
if( zName ){
for(i=0; zName[i]; i++) cksum += (cksum<<3) + zName[i];
}
if( zRoot ) for(i=0; zRoot[i]; i++) cksum += (cksum<<3) + zRoot[i];
if( zSql ) for(i=0; zSql[i]; i++) cksum += (cksum<<3) + zSql[i];
pSchema->cksum = cksum;
}
/*
** This is the callback routine for the code that initializes the
** database. See sqlite3Init() below for additional information.
@@ -129,6 +149,16 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
corruptSchema(pData, argv[0], "invalid rootpage");
}
}
if( iDb!=1 && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) ){
/* If this schema might be used by multiple connections, ensure that
** the affinity string is allocated here. Otherwise, there might be
** a race condition where two threads attempt to allocate it
** simultaneously. */
Index *pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
if( pIndex ) sqlite3IndexAffinityStr(db, pIndex);
schemaUpdateChecksum(db->aDb[iDb].pSchema, argv[0], argv[1], argv[2]);
}
return 0;
}
@@ -340,6 +370,10 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
rc = SQLITE_OK;
}
if( iDb!=1 && (db->openFlags & SQLITE_OPEN_REUSE_SCHEMA) ){
sqlite3SchemaReuse(db, iDb);
}
/* Jump here for an error that occurs after successfully allocating
** curMain and calling sqlite3BtreeEnter(). For an error that occurs
** before that point, jump to error_out.
@@ -474,8 +508,18 @@ static void schemaIsValid(Parse *pParse){
** If the same database is attached more than once, the first
** attached database is returned.
*/
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
int i = -1000000;
int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema, const char *zDb){
int i;
assert( sqlite3_mutex_held(db->mutex) );
if( zDb ){
int i;
for(i=0; i<db->nDb; i++){
if( i==1 ) continue;
if( sqlite3StrICmp(zDb, db->aDb[i].zDbSName)==0 ) return i;
}
assert( sqlite3StrICmp(zDb, "temp")==0 );
}
/* If pSchema is NULL, then return -1000000. This happens when code in
** expr.c is trying to resolve a reference to a transient table (i.e. one
@@ -487,7 +531,6 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
** more likely to cause a segfault than -1 (of course there are assert()
** statements too, but it never hurts to play the odds).
*/
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
for(i=0; 1; i++){
assert( i<db->nDb );
@@ -496,6 +539,8 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
}
}
assert( i>=0 && i<db->nDb );
}else{
i = -1000000;
}
return i;
}
+5 -2
View File
@@ -196,6 +196,7 @@ static int lookupName(
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table hold the row */
Column *pCol; /* A column of pTab */
int iDb = -1;
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
@@ -223,6 +224,7 @@ static int lookupName(
assert( db->aDb[i].zDbSName );
if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
pSchema = db->aDb[i].pSchema;
iDb = i;
break;
}
}
@@ -254,8 +256,9 @@ static int lookupName(
}
if( hit || zTab==0 ) continue;
}
if( zDb && pTab->pSchema!=pSchema ){
continue;
if( zDb && (pTab->pSchema || pSchema) ){
int ii = sqlite3SchemaToIndex(db, pTab->pSchema, pItem->zDatabase);
if( ii!=iDb ) continue;
}
if( zTab ){
const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
+15 -5
View File
@@ -1445,7 +1445,7 @@ static void generateSortTail(
/* Open any cursors needed for sorter-reference expressions */
for(i=0; i<pSort->nDefer; i++){
Table *pTab = pSort->aDefer[i].pTab;
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema, 0); /* TODO */
sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead);
nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey);
}
@@ -1713,7 +1713,8 @@ static const char *columnTypeImpl(
}
zOrigTab = pTab->zName;
if( pNC->pParse && pTab->pSchema ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
/* TODO: Fix the following for REUSE schemas */
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema, 0);
zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
@@ -4886,13 +4887,20 @@ static int selectExpander(Walker *pWalker, Select *p){
}
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
if( IsVirtual(pTab) || pTab->pSelect ){
int iSave = pParse->iFixDb;
i16 nCol;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pFrom->zDatabase);
pParse->iFixDb = 1 + iDb;
if( sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
pParse->iFixDb = iSave;
return WRC_Abort;
}
assert( pFrom->pSelect==0 );
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
nCol = pTab->nCol;
pTab->nCol = -1;
sqlite3WalkSelect(pWalker, pFrom->pSelect);
pParse->iFixDb = iSave;
pTab->nCol = nCol;
}
#endif
@@ -4984,7 +4992,7 @@ static int selectExpander(Walker *pWalker, Select *p){
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pFrom->zDatabase);
zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
}
for(j=0; j<pTab->nCol; j++){
@@ -6475,7 +6483,9 @@ int sqlite3Select(
** is better to execute the op on an index, as indexes are almost
** always spread across less pages than their corresponding tables.
*/
const int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
const int iDb = sqlite3SchemaToIndex(
pParse->db, pTab->pSchema, pTabList->a[0].zDatabase
);
const int iCsr = pParse->nTab++; /* Cursor to scan b-tree */
Index *pIdx; /* Iterator variable */
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
+13
View File
@@ -1065,6 +1065,7 @@ struct ShellState {
#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_REUSESCHEMA 6 /* Open for schema reuse */
/*
** These are the allowed shellFlgs values
@@ -3745,6 +3746,11 @@ static void open_db(ShellState *p, int openFlags){
sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0);
break;
}
case SHELL_OPEN_REUSESCHEMA: {
sqlite3_open_v2(p->zDbFilename, &p->db,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_REUSE_SCHEMA, 0);
break;
}
case SHELL_OPEN_UNSPEC:
case SHELL_OPEN_NORMAL: {
sqlite3_open(p->zDbFilename, &p->db);
@@ -6679,6 +6685,9 @@ static int do_meta_command(char *zLine, ShellState *p){
p->openMode = SHELL_OPEN_APPENDVFS;
}else if( optionMatch(z, "readonly") ){
p->openMode = SHELL_OPEN_READONLY;
}else if( optionMatch(z, "reuseschema") ){
p->openMode = SHELL_OPEN_REUSESCHEMA;
}else if( z[0]=='-' ){
#ifdef SQLITE_ENABLE_DESERIALIZE
}else if( optionMatch(z, "deserialize") ){
p->openMode = SHELL_OPEN_DESERIALIZE;
@@ -8657,6 +8666,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
}else if( strcmp(z,"-reuseschema")==0 ){
data.openMode = SHELL_OPEN_REUSESCHEMA;
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
}else if( strncmp(z, "-A",2)==0 ){
/* All remaining command-line arguments are passed to the ".archive"
@@ -8756,6 +8767,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}else if( strcmp(z,"-readonly")==0 ){
data.openMode = SHELL_OPEN_READONLY;
}else if( strcmp(z,"-reuseschema")==0 ){
data.openMode = SHELL_OPEN_REUSESCHEMA;
}else if( strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
+2
View File
@@ -567,6 +567,8 @@ int sqlite3_exec(
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
/* Reserved: 0x00F00000 */
#define SQLITE_OPEN_REUSE_SCHEMA 0x01000000 /* Ok for sqlite3_open_v2() */
/*
** CAPI3REF: Device Characteristics
+39 -24
View File
@@ -1059,6 +1059,11 @@ struct BusyHandler {
#define UNUSED_PARAMETER(x) (void)(x)
#define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y)
/*
** The static mutex with which to protect reusable schemas.
*/
#define SQLITE_MUTEX_SCHEMA_REUSE SQLITE_MUTEX_STATIC_APP1
/*
** Forward references to structures
*/
@@ -1233,6 +1238,10 @@ struct Schema {
u8 enc; /* Text encoding used by this database */
u16 schemaFlags; /* Flags associated with this schema */
int cache_size; /* Number of pages to use in the cache */
int nRef; /* Number of connections using this schema */
u64 cksum; /* Checksum for this database schema */
Schema *pNext; /* Next schema in shared schema list */
};
/*
@@ -1932,7 +1941,8 @@ struct CollSeq {
** the first argument.
*/
struct VTable {
sqlite3 *db; /* Database connection associated with this table */
sqlite3 *db; /* Database that owns this virtual table */
Btree *pBt; /* Btree backend associated with this table */
Module *pMod; /* Pointer to module implementation */
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
@@ -2999,6 +3009,7 @@ struct AutoincInfo {
struct TriggerPrg {
Trigger *pTrigger; /* Trigger this program was coded from */
TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */
int iFixDb; /* Value of Parse.iFixDb when this was coded */
SubProgram *pProgram; /* Program implementing pTrigger/orconf */
int orconf; /* Default ON CONFLICT policy */
u32 aColmask[2]; /* Masks of old.*, new.* columns accessed */
@@ -3127,7 +3138,7 @@ struct Parse {
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
Token sArg; /* Complete text of a module argument */
Table **apVtabLock; /* Pointer to virtual tables needing locking */
VTable **apVtabLock; /* Pointer to virtual tables needing locking */
#endif
Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
@@ -3136,6 +3147,7 @@ struct Parse {
#ifndef SQLITE_OMIT_ALTERTABLE
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
#endif
int iFixDb;
};
#define PARSE_MODE_NORMAL 0
@@ -3887,9 +3899,9 @@ int sqlite3RowSetNext(RowSet*, i64*);
void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*);
int sqlite3ViewGetColumnNames(Parse*,int,Table*);
#else
# define sqlite3ViewGetColumnNames(A,B) 0
# define sqlite3ViewGetColumnNames(A,B,C) 0
#endif
#if SQLITE_MAX_ATTACHED>30
@@ -4021,12 +4033,12 @@ int sqlite3IsRowid(const char*);
int sqlite3IsRowidN(const char*, int);
#endif
void sqlite3GenerateRowDelete(
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
Parse*,int,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
void sqlite3ResolvePartIdxLabel(Parse*,int);
int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
void sqlite3GenerateConstraintChecks(Parse*,int,Table*,int*,int,int,int,int,
u8,u8,int,int*,int*,Upsert*);
#ifdef SQLITE_ENABLE_NULL_TRIM
void sqlite3SetMakeRecordP5(Vdbe*,Table*);
@@ -4034,7 +4046,7 @@ void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
# define sqlite3SetMakeRecordP5(A,B)
#endif
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
int sqlite3OpenTableAndIndices(Parse*, int, Table*, int, u8, int,u8*,int*,int*);
void sqlite3BeginWriteOperation(Parse*, int, int);
void sqlite3MultiWrite(Parse*);
void sqlite3MayAbort(Parse*);
@@ -4059,7 +4071,7 @@ int sqlite3SafetyCheckSickOrOk(sqlite3*);
void sqlite3ChangeCookie(Parse*, int);
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
void sqlite3MaterializeView(Parse*, int, Table*, Expr*, ExprList*,Expr*,int);
#endif
#ifndef SQLITE_OMIT_TRIGGER
@@ -4070,9 +4082,9 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
void sqlite3DropTriggerPtr(Parse*, Trigger*);
Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask);
Trigger *sqlite3TriggerList(Parse *, Table *);
void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *,
int, int, int);
void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
void sqlite3CodeRowTrigger(Parse*, int, Trigger *, int, ExprList*, int,
Table *, int, int, int);
void sqlite3CodeRowTriggerDirect(Parse*, int, Trigger*, Table*, int, int,int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
@@ -4086,7 +4098,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
const char*,const char*);
void sqlite3DeleteTrigger(sqlite3*, Trigger*);
void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
u32 sqlite3TriggerColmask(Parse*,int,Trigger*,ExprList*,int,int,Table*,int);
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
#else
@@ -4094,12 +4106,12 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
# define sqlite3DeleteTrigger(A,B)
# define sqlite3DropTriggerPtr(A,B)
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I)
# define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F)
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I,J)
# define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F,G)
# define sqlite3TriggerList(X, Y) 0
# define sqlite3ParseToplevel(p) p
# define sqlite3IsToplevel(p) 1
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
# define sqlite3TriggerColmask(A,B,C,D,E,F,G,H) 0
#endif
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
@@ -4286,8 +4298,11 @@ void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
void sqlite3SchemaClear(void *);
void sqlite3SchemaUnuse(sqlite3*, int);
void sqlite3SchemaReuse(sqlite3*, int);
void sqlite3SchemaWritable(Parse*, int);
Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *, const char*);
KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);
void sqlite3KeyInfoUnref(KeyInfo*);
KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
@@ -4375,7 +4390,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
# define sqlite3VtabUnlock(X)
# define sqlite3VtabUnlockList(X)
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
# define sqlite3GetVTable(X,Y) ((VTable*)0)
# define sqlite3GetVTable(X,Y,Z) ((VTable*)0)
#else
void sqlite3VtabClear(sqlite3 *db, Table*);
void sqlite3VtabDisconnect(sqlite3 *db, Table *p);
@@ -4387,7 +4402,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
void sqlite3VtabUnlockList(sqlite3*);
int sqlite3VtabSavepoint(sqlite3 *, int, int);
void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
VTable *sqlite3GetVTable(sqlite3*, Table*);
VTable *sqlite3GetVTable(sqlite3*, int, Table*);
Module *sqlite3VtabCreateModule(
sqlite3*,
const char*,
@@ -4399,13 +4414,13 @@ void sqlite3AutoLoadExtensions(sqlite3*);
#endif
int sqlite3VtabEponymousTableInit(Parse*,Module*);
void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
void sqlite3VtabMakeWritable(Parse*,Table*);
void sqlite3VtabMakeWritable(Parse*,int,Table*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
void sqlite3VtabArgExtend(Parse*, Token*);
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallConnect(Parse*, int, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
@@ -4454,15 +4469,15 @@ const char *sqlite3JournalModename(int);
** provided (enforcement of FK constraints requires the triggers sub-system).
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
void sqlite3FkCheck(Parse*, int, Table*, int, int, int*, int);
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
void sqlite3FkActions(Parse*, int, Table*, ExprList*, int, int*, int);
int sqlite3FkRequired(Parse*, Table*, int*, int);
u32 sqlite3FkOldmask(Parse*, Table*);
FKey *sqlite3FkReferences(Table *);
#else
#define sqlite3FkActions(a,b,c,d,e,f)
#define sqlite3FkCheck(a,b,c,d,e,f)
#define sqlite3FkActions(a,b,c,d,e,f,g)
#define sqlite3FkCheck(a,b,c,d,e,f,g)
#define sqlite3FkDropTable(a,b,c)
#define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c,d) 0
+4
View File
@@ -282,6 +282,7 @@ int sqlite3_db_status(
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
HashElem *p;
int nStart = nByte;
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
pSchema->tblHash.count
@@ -300,6 +301,9 @@ int sqlite3_db_status(
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
}
if( pSchema->nRef>1 ){
nByte -= (nByte - nStart)*(pSchema->nRef-1)/pSchema->nRef;
}
}
}
db->pnBytesFreed = 0;
+9
View File
@@ -3443,6 +3443,7 @@ static int sqliteCmdUsage(
Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
" ?-reuse-schema BOOLEAN?"
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
" ?-key CODECKEY?"
#endif
@@ -3577,6 +3578,14 @@ static int SQLITE_TCLAPI DbMain(
}else{
flags &= ~SQLITE_OPEN_URI;
}
}else if( strcmp(zArg, "-reuse-schema")==0 ){
int b;
if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR;
if( b ){
flags |= SQLITE_OPEN_REUSE_SCHEMA;
}else{
flags &= ~SQLITE_OPEN_REUSE_SCHEMA;
}
}else{
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
return TCL_ERROR;
+30 -23
View File
@@ -215,7 +215,7 @@ void sqlite3BeginTrigger(
#ifndef SQLITE_OMIT_AUTHORIZATION
if( !IN_RENAME_OBJECT ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zDbSName;
const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb;
@@ -291,7 +291,7 @@ void sqlite3FinishTrigger(
pParse->pNewTrigger = 0;
if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup;
zName = pTrig->zName;
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema, 0);
pTrig->step_list = pStepList;
while( pStepList ){
pStepList->pTrig = pTrig;
@@ -332,7 +332,7 @@ void sqlite3FinishTrigger(
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3VdbeAddParseSchemaOp(pParse, iDb,
sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
}
@@ -610,8 +610,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
sqlite3 *db = pParse->db;
int iDb;
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema, 0);
assert( iDb>=0 && iDb<db->nDb );
sqlite3SchemaWritable(pParse, iDb);
pTable = tableOfTrigger(pTrigger);
assert( pTable );
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
@@ -728,20 +729,12 @@ static SrcList *targetSrcList(
TriggerStep *pStep /* The trigger containing the target token */
){
sqlite3 *db = pParse->db;
int iDb; /* Index of the database to use */
SrcList *pSrc; /* SrcList to be returned */
pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
if( pSrc ){
assert( pSrc->nSrc>0 );
pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
const char *zDb;
assert( iDb<db->nDb );
zDb = db->aDb[iDb].zDbSName;
pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
}
}
return pSrc;
}
@@ -903,6 +896,7 @@ static TriggerPrg *codeRowTrigger(
pPrg->orconf = orconf;
pPrg->aColmask[0] = 0xffffffff;
pPrg->aColmask[1] = 0xffffffff;
pPrg->iFixDb = pParse->iFixDb;
/* Allocate and populate a new Parse context to use for coding the
** trigger sub-program. */
@@ -916,11 +910,12 @@ static TriggerPrg *codeRowTrigger(
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
pSubParse->nQueryLoop = pParse->nQueryLoop;
pSubParse->iFixDb = pParse->iFixDb;
v = sqlite3GetVdbe(pSubParse);
if( v ){
VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
pTrigger->zName, onErrorText(orconf),
VdbeComment((v, "Start: %s.%s (%d) (%s %s%s%s ON %s)",
pTrigger->zName, onErrorText(orconf), pParse->iFixDb-1,
(pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
(pTrigger->op==TK_UPDATE ? "UPDATE" : ""),
(pTrigger->op==TK_INSERT ? "INSERT" : ""),
@@ -966,6 +961,7 @@ static TriggerPrg *codeRowTrigger(
pProgram->nMem = pSubParse->nMem;
pProgram->nCsr = pSubParse->nTab;
pProgram->token = (void *)pTrigger;
pProgram->itoken = pParse->iFixDb;
pPrg->aColmask[0] = pSubParse->oldmask;
pPrg->aColmask[1] = pSubParse->newmask;
sqlite3VdbeDelete(v);
@@ -987,12 +983,15 @@ static TriggerPrg *codeRowTrigger(
*/
static TriggerPrg *getRowTrigger(
Parse *pParse, /* Current parse context */
int iDb, /* Database containing pTab */
Trigger *pTrigger, /* Trigger to code */
Table *pTab, /* The table trigger pTrigger is attached to */
int orconf /* ON CONFLICT algorithm. */
){
Parse *pRoot = sqlite3ParseToplevel(pParse);
TriggerPrg *pPrg;
int iFixDb = pParse->iFixDb;
pParse->iFixDb = (pTrigger->pSchema==pRoot->db->aDb[1].pSchema)?0:(iDb+1);
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
@@ -1000,16 +999,19 @@ static TriggerPrg *getRowTrigger(
** process of being coded). If this is the case, then an entry with
** a matching TriggerPrg.pTrigger field will be present somewhere
** in the Parse.pTriggerPrg list. Search for such an entry. */
for(pPrg=pRoot->pTriggerPrg;
pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf);
pPrg=pPrg->pNext
);
for(pPrg=pRoot->pTriggerPrg; pPrg; pPrg=pPrg->pNext){
if( pPrg->pTrigger==pTrigger
&& pPrg->orconf==orconf
&& pParse->iFixDb==pPrg->iFixDb
) break;
}
/* If an existing TriggerPrg could not be located, create a new one. */
if( !pPrg ){
pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf);
}
pParse->iFixDb = iFixDb;
return pPrg;
}
@@ -1021,6 +1023,7 @@ static TriggerPrg *getRowTrigger(
*/
void sqlite3CodeRowTriggerDirect(
Parse *pParse, /* Parse context */
int iDb, /* Database containing pTrigger */
Trigger *p, /* Trigger to code */
Table *pTab, /* The table to code triggers from */
int reg, /* Reg array containing OLD.* and NEW.* values */
@@ -1029,7 +1032,8 @@ void sqlite3CodeRowTriggerDirect(
){
Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
TriggerPrg *pPrg;
pPrg = getRowTrigger(pParse, p, pTab, orconf);
pPrg = getRowTrigger(pParse, iDb, p, pTab, orconf);
assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
@@ -1039,8 +1043,9 @@ void sqlite3CodeRowTriggerDirect(
sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem,
(const char *)pPrg->pProgram, P4_SUBPROGRAM);
VdbeComment(
(v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
VdbeComment((v, "Call: %s.%s (%d)",
(p->zName?p->zName:"fkey"), onErrorText(orconf), iDb
));
/* Set the P5 operand of the OP_Program instruction to non-zero if
** recursive invocation of this trigger program is disallowed. Recursive
@@ -1093,6 +1098,7 @@ void sqlite3CodeRowTriggerDirect(
*/
void sqlite3CodeRowTrigger(
Parse *pParse, /* Parse context */
int iDb,
Trigger *pTrigger, /* List of triggers on table pTab */
int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
@@ -1123,7 +1129,7 @@ void sqlite3CodeRowTrigger(
&& p->tr_tm==tr_tm
&& checkColumnOverlap(p->pColumns, pChanges)
){
sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
sqlite3CodeRowTriggerDirect(pParse, iDb, p, pTab, reg, orconf,ignoreJump);
}
}
}
@@ -1155,6 +1161,7 @@ void sqlite3CodeRowTrigger(
*/
u32 sqlite3TriggerColmask(
Parse *pParse, /* Parse context */
int iDb,
Trigger *pTrigger, /* List of triggers on table pTab */
ExprList *pChanges, /* Changes list for any UPDATE OF triggers */
int isNew, /* 1 for new.* ref mask, 0 for old.* ref mask */
@@ -1172,7 +1179,7 @@ u32 sqlite3TriggerColmask(
&& checkColumnOverlap(p->pColumns,pChanges)
){
TriggerPrg *pPrg;
pPrg = getRowTrigger(pParse, p, pTab, orconf);
pPrg = getRowTrigger(pParse, iDb, p, pTab, orconf);
if( pPrg ){
mask |= pPrg->aColmask[isNew];
}
+19 -17
View File
@@ -18,6 +18,7 @@
/* Forward declaration */
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
int iDb,
SrcList *pSrc, /* The virtual table to be modified */
Table *pTab, /* The virtual table */
ExprList *pChanges, /* The columns to change in the UPDATE statement */
@@ -211,7 +212,7 @@ void sqlite3Update(
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pTabList->a[0].zDatabase);
/* Figure out if we have any triggers and if the table being
** updated is a view.
@@ -240,7 +241,7 @@ void sqlite3Update(
}
#endif
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
if( sqlite3ViewGetColumnNames(pParse, iDb, pTab) ){
goto update_cleanup;
}
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
@@ -416,7 +417,7 @@ void sqlite3Update(
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
sqlite3MaterializeView(pParse, pTab,
sqlite3MaterializeView(pParse, iDb, pTab,
pWhere, pOrderBy, pLimit, iDataCur
);
pOrderBy = 0;
@@ -434,7 +435,7 @@ void sqlite3Update(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Virtual tables must be handled separately */
if( IsVirtual(pTab) ){
updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
updateVirtualTable(pParse, iDb, pTabList, pTab, pChanges, pRowidExpr, aXRef,
pWhere, onError);
goto update_cleanup;
}
@@ -563,7 +564,7 @@ void sqlite3Update(
if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
sqlite3OpenTableAndIndices(pParse, iDb, pTab, OP_OpenWrite, 0, iBaseCur,
aToOpen, 0, 0);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
}
@@ -610,7 +611,7 @@ void sqlite3Update(
** information is needed */
if( chngPk || hasFK || pTrigger ){
u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
oldmask |= sqlite3TriggerColmask(pParse,
oldmask |= sqlite3TriggerColmask(pParse, iDb,
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
);
for(i=0; i<pTab->nCol; i++){
@@ -643,7 +644,7 @@ void sqlite3Update(
** be used eliminates some redundant opcodes.
*/
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
pParse, iDb, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
for(i=0; i<pTab->nCol; i++){
if( i==pTab->iPKey ){
@@ -672,7 +673,7 @@ void sqlite3Update(
*/
if( tmask&TRIGGER_BEFORE ){
sqlite3TableAffinity(v, pTab, regNew);
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger, TK_UPDATE, pChanges,
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
/* The row-trigger may have deleted the row being updated. In this
@@ -710,13 +711,13 @@ void sqlite3Update(
/* Do constraint checks. */
assert( regOldRowid>0 );
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
aXRef, 0);
sqlite3GenerateConstraintChecks(pParse, iDb, pTab, aRegIdx, iDataCur,
iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue,
&bReplace, aXRef, 0);
/* Do FK constraint checks. */
if( hasFK ){
sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
sqlite3FkCheck(pParse, iDb, pTab, regOldRowid, 0, aXRef, chngKey);
}
/* Delete the index entries associated with the current record. */
@@ -762,7 +763,7 @@ void sqlite3Update(
}
if( hasFK ){
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey);
sqlite3FkCheck(pParse, iDb, pTab, 0, regNewRowid, aXRef, chngKey);
}
/* Insert the new index entries and the new record. */
@@ -776,7 +777,7 @@ void sqlite3Update(
** handle rows (possibly in other tables) that refer via a foreign key
** to the row just updated. */
if( hasFK ){
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey);
sqlite3FkActions(pParse, iDb, pTab, pChanges, regOldRowid, aXRef,chngKey);
}
}
@@ -786,7 +787,7 @@ void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
sqlite3CodeRowTrigger(pParse, iDb, pTrigger, TK_UPDATE, pChanges,
TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
/* Repeat the above with the next record to be updated, until
@@ -869,6 +870,7 @@ update_cleanup:
*/
static void updateVirtualTable(
Parse *pParse, /* The parsing context */
int iDb,
SrcList *pSrc, /* The virtual table to be modified */
Table *pTab, /* The virtual table */
ExprList *pChanges, /* The columns to change in the UPDATE statement */
@@ -881,7 +883,7 @@ static void updateVirtualTable(
int ephemTab; /* Table holding the result of the SELECT */
int i; /* Loop counter */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
const char *pVTab = (const char*)sqlite3GetVTable(db, iDb, pTab);
WhereInfo *pWInfo;
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
@@ -972,7 +974,7 @@ static void updateVirtualTable(
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
}
}
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VtabMakeWritable(pParse, iDb, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
sqlite3MayAbort(pParse);
+1
View File
@@ -123,6 +123,7 @@ void sqlite3Vacuum(Parse *pParse, Token *pNm){
#endif
}
if( iDb!=1 ){
sqlite3SchemaWritable(pParse, iDb);
sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
sqlite3VdbeUsesBtree(v, iDb);
}
+6 -1
View File
@@ -6038,6 +6038,7 @@ case OP_Program: { /* jump */
VdbeFrame *pFrame; /* New vdbe frame to execute in */
SubProgram *pProgram; /* Sub-program to execute */
void *t; /* Token identifying trigger */
int i; /* Second part of token identifying trigger */
pProgram = pOp->p4.pProgram;
pRt = &aMem[pOp->p3];
@@ -6056,7 +6057,10 @@ case OP_Program: { /* jump */
** variable. */
if( pOp->p5 ){
t = pProgram->token;
for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent);
i = pProgram->itoken;
for(pFrame=p->pFrame;
pFrame && (pFrame->token!=t || pFrame->itoken!=i);
pFrame=pFrame->pParent);
if( pFrame ) break;
}
@@ -6104,6 +6108,7 @@ case OP_Program: { /* jump */
pFrame->aOp = p->aOp;
pFrame->nOp = p->nOp;
pFrame->token = pProgram->token;
pFrame->itoken = pProgram->itoken;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pFrame->anExec = p->anExec;
#endif
+2 -1
View File
@@ -90,6 +90,7 @@ struct SubProgram {
int nCsr; /* Number of cursors required */
u8 *aOnce; /* Array of OP_Once flags */
void *token; /* id that may be used to recursive triggers */
int itoken; /* Second part of id to identify rec. trig. */
SubProgram *pNext; /* Next sub-program already visited */
};
@@ -216,7 +217,7 @@ VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
#endif
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeAddParseSchemaOp(Parse*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
+1
View File
@@ -167,6 +167,7 @@ struct VdbeFrame {
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
u8 *aOnce; /* Bitmask used by OP_Once */
void *token; /* Copy of SubProgram.token */
int itoken; /* Copy of SubProgram.itoken */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#if SQLITE_DEBUG
+3 -1
View File
@@ -358,8 +358,10 @@ void sqlite3VdbeExplainPop(Parse *pParse){
** The zWhere string must have been obtained from sqlite3_malloc().
** This routine will take ownership of the allocated memory.
*/
void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
void sqlite3VdbeAddParseSchemaOp(Parse *pParse, int iDb, char *zWhere){
Vdbe *p = pParse->pVdbe;
int j;
sqlite3SchemaWritable(pParse, iDb);
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
}
+2 -2
View File
@@ -183,7 +183,7 @@ int sqlite3_blob_open(
goto blob_open_out;
}
pBlob->pTab = pTab;
pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db,pTab->pSchema,zDb)].zDbSName;
/* Now search pTab for the exact column. */
for(iCol=0; iCol<pTab->nCol; iCol++) {
@@ -270,7 +270,7 @@ int sqlite3_blob_open(
{OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema, zDb);
VdbeOp *aOp;
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
+29 -21
View File
@@ -141,10 +141,15 @@ void sqlite3VtabLock(VTable *pVTab){
** Return a pointer to the VTable object used by connection db to access
** this virtual-table, if one has been created, or NULL otherwise.
*/
VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
VTable *sqlite3GetVTable(sqlite3 *db, int iDb, Table *pTab){
VTable *pVtab;
assert( IsVirtual(pTab) );
for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
if( iDb>=0 ){
Btree *pBt = db->aDb[iDb].pBt;
for(pVtab=pTab->pVTable; pVtab && pVtab->pBt!=pBt; pVtab=pVtab->pNext);
}else{
for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
}
return pVtab;
}
@@ -218,17 +223,19 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
*/
void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
VTable **ppVTab;
VTable **ppNext;
assert( IsVirtual(p) );
assert( sqlite3BtreeHoldsAllMutexes(db) );
assert( sqlite3_mutex_held(db->mutex) );
for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){
for(ppVTab=&p->pVTable; *ppVTab; ){
if( (*ppVTab)->db==db ){
VTable *pVTab = *ppVTab;
*ppVTab = pVTab->pNext;
sqlite3VtabUnlock(pVTab);
break;
}else{
ppVTab = &(*ppVTab)->pNext;
}
}
}
@@ -356,7 +363,7 @@ void sqlite3VtabBeginParse(
** The second call, to obtain permission to create the table, is made now.
*/
if( pTable->azModuleArg ){
int iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
int iDb = sqlite3SchemaToIndex(db, pTable->pSchema, 0); /* TODO */
assert( iDb>=0 ); /* The database the table is being created in */
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
@@ -418,7 +425,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** entry in the sqlite_master table tht was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, 0);
sqlite3NestedParse(pParse,
"UPDATE %Q.%s "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
@@ -435,7 +442,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp0(v, OP_Expire);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
sqlite3VdbeAddParseSchemaOp(pParse, iDb, zWhere);
iReg = ++pParse->nMem;
sqlite3VdbeLoadString(v, iReg, pTab->zName);
@@ -494,6 +501,7 @@ void sqlite3VtabArgExtend(Parse *pParse, Token *p){
*/
static int vtabCallConstructor(
sqlite3 *db,
int iDb, /* Database containing pTab */
Table *pTab,
Module *pMod,
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
@@ -506,7 +514,6 @@ static int vtabCallConstructor(
int nArg = pTab->nModuleArg;
char *zErr = 0;
char *zModuleName;
int iDb;
VtabCtx *pCtx;
/* Check that the virtual-table is not already being initialized */
@@ -531,9 +538,9 @@ static int vtabCallConstructor(
return SQLITE_NOMEM_BKPT;
}
pVTable->db = db;
pVTable->pBt = db->aDb[iDb].pBt;
pVTable->pMod = pMod;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
/* Invoke the virtual table constructor */
@@ -622,14 +629,14 @@ static int vtabCallConstructor(
**
** This call is a no-op if table pTab is not a virtual table.
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
int sqlite3VtabCallConnect(Parse *pParse, int iDb, Table *pTab){
sqlite3 *db = pParse->db;
const char *zMod;
Module *pMod;
int rc;
assert( pTab );
if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
if( !IsVirtual(pTab) || sqlite3GetVTable(db, iDb, pTab) ){
return SQLITE_OK;
}
@@ -643,7 +650,7 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
rc = SQLITE_ERROR;
}else{
char *zErr = 0;
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
rc = vtabCallConstructor(db, iDb, pTab, pMod,pMod->pModule->xConnect,&zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
pParse->rc = rc;
@@ -714,15 +721,15 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
*pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
rc = SQLITE_ERROR;
}else{
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
rc = vtabCallConstructor(db, iDb, pTab, pMod, pMod->pModule->xCreate,pzErr);
}
/* Justification of ALWAYS(): The xConstructor method is required to
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){
if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, iDb, pTab)) ){
rc = growVTrans(db);
if( rc==SQLITE_OK ){
addToVTrans(db, sqlite3GetVTable(db, pTab));
addToVTrans(db, sqlite3GetVTable(db, iDb, pTab));
}
}
@@ -1055,7 +1062,7 @@ FuncDef *sqlite3VtabOverloadFunction(
pTab = pExpr->y.pTab;
if( pTab==0 ) return pDef;
if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
pVtab = sqlite3GetVTable(db, -1, pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
@@ -1104,20 +1111,21 @@ FuncDef *sqlite3VtabOverloadFunction(
** array if it is missing. If pTab is already in the array, this routine
** is a no-op.
*/
void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
void sqlite3VtabMakeWritable(Parse *pParse, int iDb, Table *pTab){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
VTable *pVTab = sqlite3GetVTable(pParse->db, iDb, pTab);
int i, n;
Table **apVtabLock;
VTable **apVtabLock;
assert( IsVirtual(pTab) );
for(i=0; i<pToplevel->nVtabLock; i++){
if( pTab==pToplevel->apVtabLock[i] ) return;
if( pVTab==pToplevel->apVtabLock[i] ) return;
}
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
if( apVtabLock ){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pVTab;
}else{
sqlite3OomFault(pToplevel->db);
}
@@ -1160,7 +1168,7 @@ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
addModuleArgument(db, pTab, 0);
addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
rc = vtabCallConstructor(db, 0, pTab, pMod, pModule->xConnect, &zErr);
if( rc ){
sqlite3ErrorMsg(pParse, "%s", zErr);
sqlite3DbFree(db, zErr);
+11 -5
View File
@@ -1041,8 +1041,14 @@ static sqlite3_index_info *allocateIndexInfo(
** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
** that this is required.
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
static int vtabBestIndex(
Parse *pParse,
struct SrcList_item *pSrc,
sqlite3_index_info *p
){
Table *pTab = pSrc->pTab;
int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema, pSrc->zDatabase);
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, iDb, pTab)->pVtab;
int rc;
TRACE_IDX_INPUTS(p);
@@ -3132,7 +3138,7 @@ static int whereLoopAddVirtualOne(
pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
/* Invoke the virtual table xBestIndex() method */
rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
rc = vtabBestIndex(pParse, pSrc, pIdxInfo);
if( rc ){
if( rc==SQLITE_CONSTRAINT ){
/* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
@@ -4942,14 +4948,14 @@ WhereInfo *sqlite3WhereBegin(
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
iDb = sqlite3SchemaToIndex(db, pTab->pSchema, pTabItem->zDatabase);
pLoop = pLevel->pWLoop;
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
/* Do nothing */
}else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
const char *pVTab = (const char *)sqlite3GetVTable(db, iDb, pTab);
int iCur = pTabItem->iCursor;
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB);
}else if( IsVirtual(pTab) ){
+1 -1
View File
@@ -409,7 +409,7 @@ static int isAuxiliaryVtabOperator(
sqlite3_module *pMod;
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
void *pNotUsed;
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
pVtab = sqlite3GetVTable(db, -1, pCol->y.pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
+388
View File
@@ -0,0 +1,388 @@
# 2017 August 9
#
# 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.
#
#***********************************************************************
#
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix reuse1
forcedelete test.db2
sqlite3 db2 test.db2
do_execsql_test 1.0 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
CREATE INDEX i1 ON t1(z);
PRAGMA schema_version;
} {2}
do_execsql_test -db db2 1.1 {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z);
CREATE INDEX i1 ON t1(z);
PRAGMA schema_version;
} {2}
do_test 1.2 {
db close
db2 close
sqlite3 db2 test.db2 -reuse-schema 1
sqlite3 db test.db -reuse-schema 1
} {}
do_execsql_test -db db2 1.3.1 {
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(4, 5, 6);
}
do_execsql_test 1.3.2 {
SELECT * FROM t1;
PRAGMA integrity_check;
} {ok}
do_execsql_test -db db2 1.3.3 {
SELECT * FROM t1;
PRAGMA integrity_check;
} {1 2 3 4 5 6 ok}
sqlite3 db3 test.db2
do_execsql_test -db db3 1.4.1 {
ALTER TABLE t1 ADD COLUMN a;
}
do_execsql_test -db db2 1.4.2 {
SELECT * FROM t1;
} {1 2 3 {} 4 5 6 {}}
do_execsql_test 1.4.3 {
SELECT * FROM t1;
} {}
db3 close
sqlite3 db3 test.db
do_execsql_test -db db3 1.5.0 {
CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN
SELECT 1, 2, 3;
END;
}
# Check that the schema cannot be modified if the db was opened with
# SQLITE_OPEN_REUSE_SCHEMA.
#
foreach {tn sql} {
1 { CREATE TABLE t2(x, y) }
2 { CREATE INDEX i2 ON t1(z) }
3 { CREATE VIEW v2 AS SELECT * FROM t2 }
4 { ALTER TABLE t1 RENAME TO t3 }
5 { ALTER TABLE t1 ADD COLUMN xyz }
6 { VACUUM }
7 { DROP INDEX i1 }
8 { DROP TABLE t1 }
9 { DROP TRIGGER tr1 }
10 { ANALYZE }
} {
do_catchsql_test 1.5.$tn $sql {1 {attempt to modify read-only schema}}
}
#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
ifcapable fts5 {
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE ft USING fts5(a);
INSERT INTO ft VALUES('one'), ('two'), ('three');
ATTACH 'test.db2' AS aux;
CREATE VIRTUAL TABLE aux.ft USING fts5(a);
INSERT INTO aux.ft VALUES('aux1'), ('aux2'), ('aux3');
}
db close
sqlite3 db test.db -reuse-schema 1
do_execsql_test 2.1 {
ATTACH 'test.db2' AS aux;
SELECT * FROM main.ft;
} {one two three}
do_execsql_test 2.2 {
SELECT * FROM aux.ft;
} {aux1 aux2 aux3}
do_execsql_test 2.2 {
SELECT * FROM aux.ft_content;
} {1 aux1 2 aux2 3 aux3}
}
#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 3.0 {
CREATE TABLE t1(a PRIMARY KEY, b, c);
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE TRIGGER v1_ins INSTEAD OF INSERT ON v1 BEGIN
INSERT INTO t1 VALUES(new.a, new.b, new.c);
END;
CREATE TRIGGER v1_del INSTEAD OF DELETE ON v1 BEGIN
DELETE FROM t1 WHERE a=old.a;
END;
CREATE TRIGGER v1_up INSTEAD OF UPDATE ON v1 BEGIN
UPDATE t1 SET a=new.a, b=new.b, c=new.c WHERE a=old.a;
END;
}
forcecopy test.db test.db2
do_test 3.1 {
sqlite3 db2 test.db2
execsql { INSERT INTO t1 VALUES(1, 2, 3) } db
execsql { INSERT INTO t1 VALUES(4, 5, 6) } db2
db2 close
execsql { ATTACH 'test.db2' AS aux; }
} {}
do_execsql_test 3.2 {
SELECT * FROM main.v1;
} {1 2 3}
do_execsql_test 3.3 {
SELECT * FROM aux.v1;
} {4 5 6}
db close
sqlite3 db test.db -reuse-schema 1
do_execsql_test 3.4 { ATTACH 'test.db2' AS aux } {}
do_execsql_test 3.5 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.6 { SELECT * FROM aux.v1 } {4 5 6}
do_execsql_test 3.7.1 { INSERT INTO aux.t1 VALUES(8, 9, 10); }
do_execsql_test 3.7.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.7.3 { SELECT * FROM aux.v1 } {4 5 6 8 9 10}
do_execsql_test 3.8.1 { DELETE FROM aux.t1 WHERE b=5 }
do_execsql_test 3.8.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.8.3 { SELECT * FROM aux.v1 } {8 9 10}
do_execsql_test 3.9.1 { UPDATE aux.t1 SET b='abc' }
do_execsql_test 3.9.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.9.3 { SELECT * FROM aux.v1 } {8 abc 10}
do_execsql_test 3.10.1 { INSERT INTO aux.v1 VALUES(11, 12, 13) }
do_execsql_test 3.10.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.10.3 { SELECT * FROM aux.v1 } {8 abc 10 11 12 13}
do_execsql_test 3.11.1 { DELETE FROM aux.v1 WHERE b='abc' }
do_execsql_test 3.11.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.11.3 { SELECT * FROM aux.v1 } {11 12 13}
do_execsql_test 3.12.1 { UPDATE aux.v1 SET b='def' }
do_execsql_test 3.12.2 { SELECT * FROM main.v1 } {1 2 3}
do_execsql_test 3.12.3 { SELECT * FROM aux.v1 } {11 def 13}
do_execsql_test 3.13.1 {
CREATE TEMP TRIGGER xyz AFTER INSERT ON aux.t1 BEGIN
INSERT INTO v1 VALUES(new.a, new.b, new.c);
END;
}
do_execsql_test 3.13.2 {
INSERT INTO aux.v1 VALUES('x', 'y', 'z');
}
do_execsql_test 3.13.3 {
SELECT * FROM v1;
} {1 2 3 x y z}
#-------------------------------------------------------------------------
#
reset_db
forcedelete test.db2
do_execsql_test 4.0 {
CREATE TABLE t1(a PRIMARY KEY, b, c UNIQUE);
CREATE TABLE del(a, b, c);
CREATE TRIGGER tr1 AFTER DELETE ON t1 BEGIN
INSERT INTO del VALUES(old.a, old.b, old.c);
END;
}
forcecopy test.db test.db2
db close
sqlite3 db test.db -reuse-schema 1
execsql {
ATTACH 'test.db2' AS aux;
PRAGMA recursive_triggers = 1;
}
do_execsql_test 4.1 {
INSERT INTO main.t1 VALUES(1, 2, 3);
INSERT INTO aux.t1 VALUES(4, 5, 6);
}
do_execsql_test 4.2.1 {
INSERT OR REPLACE INTO aux.t1 VALUES('a', 'b', 6);
SELECT * FROM aux.t1;
} {a b 6}
do_execsql_test 4.2.2 { SELECT * FROM aux.del } {4 5 6}
do_execsql_test 4.2.3 { SELECT * FROM main.del } {}
do_execsql_test 4.3.1 {
INSERT INTO aux.t1 VALUES('x', 'y', 'z');
UPDATE OR REPLACE aux.t1 SET c='z' WHERE a='a';
} {}
do_execsql_test 4.3.2 { SELECT * FROM aux.del } {4 5 6 x y z}
do_execsql_test 4.3.3 { SELECT * FROM main.del } {}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
ANALYZE;
PRAGMA writable_schema = 1;
DELETE FROM sqlite_stat1;
}
db close
forcecopy test.db test.db2
sqlite3 db test.db -reuse-schema 1
execsql { ATTACH 'test.db2' AS aux }
foreach {tn sql} {
1 { CREATE TABLE t3(x) }
2 { DROP TABLE t2 }
3 { CREATE INDEX i2 ON t2(b) }
4 { DROP INDEX i1 }
5 { ALTER TABLE t1 ADD COLUMN d }
6 { ALTER TABLE t1 RENAME TO t3 }
7 { ALTER TABLE t1 RENAME c TO d }
} {
do_catchsql_test 5.1.$tn $sql {1 {attempt to modify read-only schema}}
}
do_execsql_test 5.2.1 { ANALYZE aux.t1 } {}
do_execsql_test 5.2.2 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}}
do_execsql_test 5.2.3 { SELECT * FROM main.sqlite_stat1 } {}
do_test 5.3.0 {
sqlite3 db2 test.db2
db2 eval {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_stat1;
}
} {}
do_execsql_test 5.3.1 { SELECT * FROM aux.sqlite_stat1 } {}
do_execsql_test 5.3.2 { ANALYZE aux } {}
do_execsql_test 5.3.3 { SELECT * FROM aux.sqlite_stat1 } {t1 i1 {2 1}}
do_execsql_test 5.3.4 { SELECT * FROM main.sqlite_stat1 } {}
#-------------------------------------------------------------------------
# Attempting to run ANALYZE when the required sqlite_statXX functions
# are missing is an error (because it would modify the database schema).
#
reset_db
do_execsql_test 5.4 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX i1 ON t1(b);
INSERT INTO t1 VALUES(1, 2, 3), (4, 5, 6);
}
db close
sqlite3 db test.db -reuse-schema 1
foreach {tn sql} {
1 { ANALYZE }
2 { ANALYZE t1 }
3 { ANALYZE i1 }
4 { ANALYZE main }
5 { ANALYZE main.t1 }
6 { ANALYZE main.i1 }
} {
do_catchsql_test 5.4.$tn $sql {1 {attempt to modify read-only schema}}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 6.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE VIEW v1 AS SELECT * FROM t1;
}
db close
forcecopy test.db test.db2
sqlite3 db test.db -reuse-schema 1
execsql { ATTACH 'test.db2' AS aux }
do_execsql_test 6.1 {
INSERT INTO main.t1(a) VALUES(1), (2), (3);
INSERT INTO aux.t1(a) VALUES(4), (5), (6);
CREATE TEMP TABLE t2(i,t);
INSERT INTO t2 VALUES(2, 'two'), (5, 'five');
}
do_execsql_test 6.2 {
SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.t1)
} {five}
do_execsql_test 6.3 {
SELECT t FROM t2 WHERE i IN (SELECT a FROM aux.v1)
} {five}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 7.0 {
CREATE TABLE p1(a PRIMARY KEY, b);
CREATE TABLE p2(a PRIMARY KEY, b);
CREATE TABLE c1(x REFERENCES p1 ON UPDATE CASCADE ON DELETE CASCADE);
}
db close
forcecopy test.db test.db2
sqlite3 db test.db -reuse-schema 1
execsql { ATTACH 'test.db2' AS aux }
do_execsql_test 7.1 {
INSERT INTO aux.p1 VALUES(1, 'one');
INSERT INTO aux.p1 VALUES(2, 'two');
PRAGMA foreign_keys = on;
}
do_execsql_test 7.2 {
INSERT INTO aux.c1 VALUES(2);
}
do_execsql_test 7.3.1 {
PRAGMA foreign_keys = off;
INSERT INTO main.p2 SELECT * FROM aux.p1;
}
do_execsql_test 7.3.2 {
SELECT * FROM main.p2;
} {1 one 2 two}
do_execsql_test 7.3.3 {
INSERT INTO aux.p2 VALUES(1, 2);
}
do_execsql_test 7.3.4 {
SELECT main.p2.a FROM main.p2, aux.p2;
} {1 2}
do_execsql_test 7.3.5 {
SELECT * FROM main.p2, aux.p2;
} {1 one 1 2 2 two 1 2}
do_execsql_test 7.4 {
SELECT count(*) FROM aux.p2;
} {1}
finish_test
+1 -1
View File
@@ -24,7 +24,7 @@ source $testdir/tester.tcl
# Check the error messages generated by tclsqlite
#
set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN? ?-reuse-schema BOOLEAN?"
if {[sqlite3 -has-codec]} {
append r " ?-key CODECKEY?"
}