mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Allow virtual tables to be used in shared-cache mode. (CVS 6928)
FossilOrigin-Name: 5d9e767a05e381235e064061043e30cc03a11a07
This commit is contained in:
42
manifest
42
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Simplifications\sto\spager.c\sin\ssupport\sof\sstructural\scoverage\stesting.\s(CVS\s6927)
|
C Allow\svirtual\stables\sto\sbe\sused\sin\sshared-cache\smode.\s(CVS\s6928)
|
||||||
D 2009-07-24T16:32:01
|
D 2009-07-24T17:58:53
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in df9359da7a726ccb67a45db905c5447d5c00c6ef
|
F Makefile.in df9359da7a726ccb67a45db905c5447d5c00c6ef
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -99,21 +99,21 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
|||||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||||
F src/alter.c 95f41d957f56407aac6224041ca5b954042318d1
|
F src/alter.c 8b42cace4f8e312de596807ba2685179da64fec4
|
||||||
F src/analyze.c e239496cfb5394ac8867f1c112905ddab8d01cd9
|
F src/analyze.c e239496cfb5394ac8867f1c112905ddab8d01cd9
|
||||||
F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f
|
F src/attach.c 13995348fc5a26cdd136a50806faf292aabc173f
|
||||||
F src/auth.c 802a9439dfa0b8c208b10055cba400e82ef18025
|
F src/auth.c 802a9439dfa0b8c208b10055cba400e82ef18025
|
||||||
F src/backup.c 6f1c2d9862c8a3feb7739dfcca02c1f5352e37f3
|
F src/backup.c 6f1c2d9862c8a3feb7739dfcca02c1f5352e37f3
|
||||||
F src/bitvec.c cfbf6af5b0ababb4f06ed3e75c616dadaf47fcbd
|
F src/bitvec.c cfbf6af5b0ababb4f06ed3e75c616dadaf47fcbd
|
||||||
F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7
|
F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7
|
||||||
F src/btree.c 64fbba1140bb06edbac2553cfd339145bbdc2665
|
F src/btree.c c1d3d67007f2f49697b4204bf44f2a8f45f750df
|
||||||
F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe
|
F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe
|
||||||
F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705
|
F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705
|
||||||
F src/build.c 867028ee9f63f7bc8eb8d4a720bb98cf9b9a12b4
|
F src/build.c a15de7c5d020a778b641fca0b2510126843f4b30
|
||||||
F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
|
F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
|
||||||
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
||||||
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
|
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
|
||||||
F src/delete.c fb05e577ab273cc8a63b44809aa5078f72f475c1
|
F src/delete.c 6f0192ecf2ae97dbbf4cccfa32639b504da70d4a
|
||||||
F src/expr.c f6f21604c1367354b28d03c983a83279071a2948
|
F src/expr.c f6f21604c1367354b28d03c983a83279071a2948
|
||||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||||
F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87
|
F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87
|
||||||
@@ -121,7 +121,7 @@ F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
|||||||
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
|
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
|
||||||
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
|
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
|
||||||
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
||||||
F src/insert.c 94e51344e01aea6be43e95cd24e8baa014d8c3d6
|
F src/insert.c a4bbd811a15f8b24a311753da947d61368685db1
|
||||||
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
||||||
F src/legacy.c 54a11649f27ae55f4fcd6e6b5ba836f839cb8704
|
F src/legacy.c 54a11649f27ae55f4fcd6e6b5ba836f839cb8704
|
||||||
F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
|
F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
|
||||||
@@ -154,16 +154,16 @@ F src/pcache.c 1dae135b70a029f81ed66f6e9b5d0db91480d5d0
|
|||||||
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
|
F src/pcache.h 9b927ccc5a538e31b4c3bc7eec4f976db42a1324
|
||||||
F src/pcache1.c 6dc833c89feac405dd8b4858232c97e679f182ec
|
F src/pcache1.c 6dc833c89feac405dd8b4858232c97e679f182ec
|
||||||
F src/pragma.c 9eb44ac1d3dc1ac3ea4f444abe1a10ae8acaa16c
|
F src/pragma.c 9eb44ac1d3dc1ac3ea4f444abe1a10ae8acaa16c
|
||||||
F src/prepare.c 12e556fc9f72a6563db7099697f657d75d4bb91c
|
F src/prepare.c 312ba96867ae9df6bd1a57cb84a9fd315e61cf8d
|
||||||
F src/printf.c 508a1c59433353552b6553cba175eaa7331f8fc1
|
F src/printf.c 508a1c59433353552b6553cba175eaa7331f8fc1
|
||||||
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
F src/random.c 676b9d7ac820fe81e6fb2394ac8c10cff7f38628
|
||||||
F src/resolve.c 4a61d03e49b15440878096e6030863fc628828f0
|
F src/resolve.c 4a61d03e49b15440878096e6030863fc628828f0
|
||||||
F src/rowset.c c64dafba1f9fd876836c8db8682966b9d197eb1f
|
F src/rowset.c c64dafba1f9fd876836c8db8682966b9d197eb1f
|
||||||
F src/select.c 71748b8e244112cf73df9446c4246c192276c30d
|
F src/select.c 71748b8e244112cf73df9446c4246c192276c30d
|
||||||
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
|
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
|
||||||
F src/sqlite.h.in 92a8960ca178cfbd73ce71cca65829c6262137ac
|
F src/sqlite.h.in 5672d9a6e19f80c1c7f1276dbe10e7d51c8fd97b
|
||||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||||
F src/sqliteInt.h c638fff6a05bb1c546f361e8527385fef0638917
|
F src/sqliteInt.h 11d239cc658823c719a3077ea2c7691795002c34
|
||||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||||
@@ -200,20 +200,20 @@ F src/test_thread.c b8a1ab7ca1a632f18e8a361880d5d65eeea08eac
|
|||||||
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
F src/test_wsd.c 3ae5101de6cbfda2720152ab659ea84079719241
|
||||||
F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b
|
F src/tokenize.c af8a56e6a50c5042fc305bfa796275e9bf26ff2b
|
||||||
F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b
|
F src/trigger.c c07c5157c58fcdb704f65d5f5e4775276e45bb8b
|
||||||
F src/update.c a1bbe774bce495d62dce3df3f42a5f04c1de173a
|
F src/update.c 7570d90842f0d9338906eeea443193358869ca97
|
||||||
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
|
F src/utf.c 9541d28f40441812c0b40f00334372a0542c00ff
|
||||||
F src/util.c 861d5b5c58be4921f0a254489ea94cb15f550ef8
|
F src/util.c 861d5b5c58be4921f0a254489ea94cb15f550ef8
|
||||||
F src/vacuum.c 3fe0eebea6d2311c1c2ab2962887d11f7a4dcfb0
|
F src/vacuum.c 3fe0eebea6d2311c1c2ab2962887d11f7a4dcfb0
|
||||||
F src/vdbe.c 3f4b02f59287cc65583c0bba371e9c7d047abad2
|
F src/vdbe.c 0ce57f8211899b59d1d6f1642f79e75fc212d6d0
|
||||||
F src/vdbe.h 35a648bc3279a120da24f34d9a25213ec15daf8a
|
F src/vdbe.h 457b6c70f02885cec1f5225b5e6441d067b55d3f
|
||||||
F src/vdbeInt.h 831c254a6eef237ef4664c8381a0137586567007
|
F src/vdbeInt.h 831c254a6eef237ef4664c8381a0137586567007
|
||||||
F src/vdbeapi.c 0ab8ada7260b32031ca97f338caecf0812460624
|
F src/vdbeapi.c 0ab8ada7260b32031ca97f338caecf0812460624
|
||||||
F src/vdbeaux.c a1ed07f91a9d59d39e97b2844554a07c91c9b809
|
F src/vdbeaux.c e3943dae17dd29d749a3e9bb42e4eb7b7eca43ed
|
||||||
F src/vdbeblob.c a3f3e0e877fc64ea50165eec2855f5ada4477611
|
F src/vdbeblob.c a3f3e0e877fc64ea50165eec2855f5ada4477611
|
||||||
F src/vdbemem.c bfc25f9ef4fa914b473303566459552bdb2e008a
|
F src/vdbemem.c bfc25f9ef4fa914b473303566459552bdb2e008a
|
||||||
F src/vtab.c 00902f289521041712fb0293d0bf8688c7af8e48
|
F src/vtab.c b19c4e96dcf2b89b5b2ba48e8ef624e654a59b2c
|
||||||
F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04
|
F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04
|
||||||
F src/where.c cf0d091748c2fa6f7df96e5b08d2db26fd2eb437
|
F src/where.c bf56a85ab4f1e17f0c8060c97bd579cb8e0fa000
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||||
@@ -703,7 +703,7 @@ F test/vtabC.test 1cf7896ab6859bfe3074244b2b0e12de5cbdd766
|
|||||||
F test/vtabD.test 74167b1578e5886fe4c886d6bef2fd1406444c42
|
F test/vtabD.test 74167b1578e5886fe4c886d6bef2fd1406444c42
|
||||||
F test/vtab_alter.test 3a299749fee97ca3d53bd55717f536e4a2284856
|
F test/vtab_alter.test 3a299749fee97ca3d53bd55717f536e4a2284856
|
||||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||||
F test/vtab_shared.test c19b2555b807ef2ee014c882cdda5bc8d84fcf48
|
F test/vtab_shared.test 561305eff0bb574a983c29029ef294a4a895a14c
|
||||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||||
F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820
|
F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820
|
||||||
F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
|
F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
|
||||||
@@ -741,7 +741,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
|||||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
|
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
|
||||||
P 2d2f42ca0a24ed8b33f9ad560c76a6c1301c757b
|
P 7222ad2667b95d6021d9ae47f548b76b224f46aa
|
||||||
R d83586425c23d3015fdf0b2326ebc67f
|
R 477ef377a502774f707ff161355dd337
|
||||||
U drh
|
U danielk1977
|
||||||
Z eeeb8d7f7200949823d967a49549fa65
|
Z b547740a8551902f628dba2106d37250
|
||||||
|
@@ -1 +1 @@
|
|||||||
7222ad2667b95d6021d9ae47f548b76b224f46aa
|
5d9e767a05e381235e064061043e30cc03a11a07
|
17
src/alter.c
17
src/alter.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that used to generate VDBE code
|
** This file contains C code routines that used to generate VDBE code
|
||||||
** that implements the ALTER TABLE command.
|
** that implements the ALTER TABLE command.
|
||||||
**
|
**
|
||||||
** $Id: alter.c,v 1.61 2009/06/03 11:25:07 danielk1977 Exp $
|
** $Id: alter.c,v 1.62 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ void sqlite3AlterRenameTable(
|
|||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
char *zWhere = 0; /* Where clause to locate temp triggers */
|
char *zWhere = 0; /* Where clause to locate temp triggers */
|
||||||
#endif
|
#endif
|
||||||
int isVirtualRename = 0; /* True if this is a v-table with an xRename() */
|
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
|
||||||
|
|
||||||
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
|
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
|
||||||
assert( pSrc->nSrc==1 );
|
assert( pSrc->nSrc==1 );
|
||||||
@@ -332,8 +332,11 @@ void sqlite3AlterRenameTable(
|
|||||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||||
goto exit_rename_table;
|
goto exit_rename_table;
|
||||||
}
|
}
|
||||||
if( IsVirtual(pTab) && pTab->pMod->pModule->xRename ){
|
if( IsVirtual(pTab) ){
|
||||||
isVirtualRename = 1;
|
pVTab = sqlite3GetVTable(db, pTab);
|
||||||
|
if( pVTab->pVtab->pModule->xRename==0 ){
|
||||||
|
pVTab = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -346,7 +349,7 @@ void sqlite3AlterRenameTable(
|
|||||||
if( v==0 ){
|
if( v==0 ){
|
||||||
goto exit_rename_table;
|
goto exit_rename_table;
|
||||||
}
|
}
|
||||||
sqlite3BeginWriteOperation(pParse, isVirtualRename, iDb);
|
sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb);
|
||||||
sqlite3ChangeCookie(pParse, iDb);
|
sqlite3ChangeCookie(pParse, iDb);
|
||||||
|
|
||||||
/* If this is a virtual table, invoke the xRename() function if
|
/* If this is a virtual table, invoke the xRename() function if
|
||||||
@@ -355,10 +358,10 @@ void sqlite3AlterRenameTable(
|
|||||||
** SQLite tables) that are identified by the name of the virtual table.
|
** SQLite tables) that are identified by the name of the virtual table.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( isVirtualRename ){
|
if( pVTab ){
|
||||||
int i = ++pParse->nMem;
|
int i = ++pParse->nMem;
|
||||||
sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
|
sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
|
||||||
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pTab->pVtab, P4_VTAB);
|
sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.701 2009/07/23 01:44:00 drh Exp $
|
** $Id: btree.c,v 1.702 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** See the header comment on "btreeInt.h" for additional information.
|
** See the header comment on "btreeInt.h" for additional information.
|
||||||
@@ -1700,7 +1700,6 @@ int sqlite3BtreeOpen(
|
|||||||
char *zFullPathname = sqlite3Malloc(nFullPathname);
|
char *zFullPathname = sqlite3Malloc(nFullPathname);
|
||||||
sqlite3_mutex *mutexShared;
|
sqlite3_mutex *mutexShared;
|
||||||
p->sharable = 1;
|
p->sharable = 1;
|
||||||
db->flags |= SQLITE_SharedCache;
|
|
||||||
if( !zFullPathname ){
|
if( !zFullPathname ){
|
||||||
sqlite3_free(p);
|
sqlite3_free(p);
|
||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.556 2009/07/01 16:12:08 danielk1977 Exp $
|
** $Id: build.c,v 1.557 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<pParse->nVtabLock; i++){
|
for(i=0; i<pParse->nVtabLock; i++){
|
||||||
char *vtab = (char *)pParse->apVtabLock[i]->pVtab;
|
char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
||||||
sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
||||||
}
|
}
|
||||||
pParse->nVtabLock = 0;
|
pParse->nVtabLock = 0;
|
||||||
@@ -424,6 +424,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
|
|||||||
}
|
}
|
||||||
assert( iDb==0 );
|
assert( iDb==0 );
|
||||||
db->flags &= ~SQLITE_InternChanges;
|
db->flags &= ~SQLITE_InternChanges;
|
||||||
|
sqlite3VtabUnlockList(db);
|
||||||
sqlite3BtreeLeaveAll(db);
|
sqlite3BtreeLeaveAll(db);
|
||||||
|
|
||||||
/* If one or more of the auxiliary database files has been closed,
|
/* If one or more of the auxiliary database files has been closed,
|
||||||
@@ -2002,7 +2003,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
|||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
}else if( IsVirtual(pTab) ){
|
}else if( IsVirtual(pTab) ){
|
||||||
code = SQLITE_DROP_VTABLE;
|
code = SQLITE_DROP_VTABLE;
|
||||||
zArg2 = pTab->pMod->zName;
|
zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName;
|
||||||
#endif
|
#endif
|
||||||
}else{
|
}else{
|
||||||
if( !OMIT_TEMPDB && iDb==1 ){
|
if( !OMIT_TEMPDB && iDb==1 ){
|
||||||
|
40
src/delete.c
40
src/delete.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** in order to generate code for DELETE FROM statements.
|
** in order to generate code for DELETE FROM statements.
|
||||||
**
|
**
|
||||||
** $Id: delete.c,v 1.204 2009/06/23 20:28:54 drh Exp $
|
** $Id: delete.c,v 1.205 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -43,16 +43,26 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
|||||||
** writable return 0;
|
** writable return 0;
|
||||||
*/
|
*/
|
||||||
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
||||||
if( ((pTab->tabFlags & TF_Readonly)!=0
|
/* A table is not writable under the following circumstances:
|
||||||
&& (pParse->db->flags & SQLITE_WriteSchema)==0
|
**
|
||||||
&& pParse->nested==0)
|
** 1) It is a virtual table and no implementation of the xUpdate method
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
** has been provided, or
|
||||||
|| (pTab->pMod && pTab->pMod->pModule->xUpdate==0)
|
** 2) It is a system table (i.e. sqlite_master), this call is not
|
||||||
#endif
|
** part of a nested parse and writable_schema pragma has not
|
||||||
|
** been specified.
|
||||||
|
**
|
||||||
|
** In either case leave an error message in pParse and return non-zero.
|
||||||
|
*/
|
||||||
|
if( ( IsVirtual(pTab)
|
||||||
|
&& sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
|
||||||
|
|| ( (pTab->tabFlags & TF_Readonly)!=0
|
||||||
|
&& (pParse->db->flags & SQLITE_WriteSchema)==0
|
||||||
|
&& pParse->nested==0 )
|
||||||
){
|
){
|
||||||
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIEW
|
#ifndef SQLITE_OMIT_VIEW
|
||||||
if( !viewOk && pTab->pSelect ){
|
if( !viewOk && pTab->pSelect ){
|
||||||
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
||||||
@@ -264,6 +274,12 @@ void sqlite3DeleteFrom(
|
|||||||
# define isView 0
|
# define isView 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If pTab is really a view, make sure it has been initialized.
|
||||||
|
*/
|
||||||
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||||
|
goto delete_from_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
||||||
goto delete_from_cleanup;
|
goto delete_from_cleanup;
|
||||||
}
|
}
|
||||||
@@ -277,12 +293,6 @@ void sqlite3DeleteFrom(
|
|||||||
}
|
}
|
||||||
assert(!isView || pTrigger);
|
assert(!isView || pTrigger);
|
||||||
|
|
||||||
/* If pTab is really a view, make sure it has been initialized.
|
|
||||||
*/
|
|
||||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
|
||||||
goto delete_from_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a cursor used to store the old.* data for a trigger.
|
/* Allocate a cursor used to store the old.* data for a trigger.
|
||||||
*/
|
*/
|
||||||
if( pTrigger ){
|
if( pTrigger ){
|
||||||
@@ -443,9 +453,9 @@ void sqlite3DeleteFrom(
|
|||||||
/* Delete the row */
|
/* Delete the row */
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( IsVirtual(pTab) ){
|
if( IsVirtual(pTab) ){
|
||||||
const char *pVtab = (const char *)pTab->pVtab;
|
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||||
sqlite3VtabMakeWritable(pParse, pTab);
|
sqlite3VtabMakeWritable(pParse, pTab);
|
||||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVtab, P4_VTAB);
|
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
34
src/insert.c
34
src/insert.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle INSERT statements in SQLite.
|
** to handle INSERT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: insert.c,v 1.269 2009/06/23 20:28:54 drh Exp $
|
** $Id: insert.c,v 1.270 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -131,9 +131,14 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
|||||||
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
||||||
** run without using temporary table for the results of the SELECT.
|
** run without using temporary table for the results of the SELECT.
|
||||||
*/
|
*/
|
||||||
static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
|
static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){
|
||||||
|
Vdbe *v = sqlite3GetVdbe(p);
|
||||||
int i;
|
int i;
|
||||||
int iEnd = sqlite3VdbeCurrentAddr(v);
|
int iEnd = sqlite3VdbeCurrentAddr(v);
|
||||||
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
|
VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
for(i=iStartAddr; i<iEnd; i++){
|
for(i=iStartAddr; i<iEnd; i++){
|
||||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
|
VdbeOp *pOp = sqlite3VdbeGetOp(v, i);
|
||||||
assert( pOp!=0 );
|
assert( pOp!=0 );
|
||||||
@@ -150,7 +155,7 @@ static int readsTable(Vdbe *v, int iStartAddr, int iDb, Table *pTab){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pTab->pVtab ){
|
if( pOp->opcode==OP_VOpen && pOp->p4.pVtab==pVTab ){
|
||||||
assert( pOp->p4.pVtab!=0 );
|
assert( pOp->p4.pVtab!=0 );
|
||||||
assert( pOp->p4type==P4_VTAB );
|
assert( pOp->p4type==P4_VTAB );
|
||||||
return 1;
|
return 1;
|
||||||
@@ -504,15 +509,6 @@ void sqlite3Insert(
|
|||||||
#endif
|
#endif
|
||||||
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
|
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
|
||||||
|
|
||||||
/* Ensure that:
|
|
||||||
* (a) the table is not read-only,
|
|
||||||
* (b) that if it is a view then ON INSERT triggers exist
|
|
||||||
*/
|
|
||||||
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
|
|
||||||
goto insert_cleanup;
|
|
||||||
}
|
|
||||||
assert( pTab!=0 );
|
|
||||||
|
|
||||||
/* If pTab is really a view, make sure it has been initialized.
|
/* If pTab is really a view, make sure it has been initialized.
|
||||||
** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
|
** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
|
||||||
** module table).
|
** module table).
|
||||||
@@ -521,6 +517,14 @@ void sqlite3Insert(
|
|||||||
goto insert_cleanup;
|
goto insert_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure that:
|
||||||
|
* (a) the table is not read-only,
|
||||||
|
* (b) that if it is a view then ON INSERT triggers exist
|
||||||
|
*/
|
||||||
|
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
|
||||||
|
goto insert_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate a VDBE
|
/* Allocate a VDBE
|
||||||
*/
|
*/
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
@@ -620,7 +624,7 @@ void sqlite3Insert(
|
|||||||
** of the tables being read by the SELECT statement. Also use a
|
** of the tables being read by the SELECT statement. Also use a
|
||||||
** temp table in the case of row triggers.
|
** temp table in the case of row triggers.
|
||||||
*/
|
*/
|
||||||
if( pTrigger || readsTable(v, addrSelect, iDb, pTab) ){
|
if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){
|
||||||
useTempTable = 1;
|
useTempTable = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,9 +980,9 @@ void sqlite3Insert(
|
|||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( IsVirtual(pTab) ){
|
if( IsVirtual(pTab) ){
|
||||||
|
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||||
sqlite3VtabMakeWritable(pParse, pTab);
|
sqlite3VtabMakeWritable(pParse, pTab);
|
||||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns,
|
sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB);
|
||||||
(const char*)pTab->pVtab, P4_VTAB);
|
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
** interface, and routines that contribute to loading the database schema
|
** interface, and routines that contribute to loading the database schema
|
||||||
** from disk.
|
** from disk.
|
||||||
**
|
**
|
||||||
** $Id: prepare.c,v 1.128 2009/07/03 19:19:50 drh Exp $
|
** $Id: prepare.c,v 1.129 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -581,6 +581,7 @@ static int sqlite3Prepare(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite3VtabUnlockList(db);
|
||||||
|
|
||||||
pParse->db = db;
|
pParse->db = db;
|
||||||
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
** the version number) and changes its name to "sqlite3.h" as
|
** the version number) and changes its name to "sqlite3.h" as
|
||||||
** part of the build process.
|
** part of the build process.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h.in,v 1.459 2009/07/15 11:26:44 drh Exp $
|
** @(#) $Id: sqlite.h.in,v 1.460 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE3_H_
|
#ifndef _SQLITE3_H_
|
||||||
#define _SQLITE3_H_
|
#define _SQLITE3_H_
|
||||||
@@ -4331,7 +4331,7 @@ SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
|
|||||||
*/
|
*/
|
||||||
struct sqlite3_vtab {
|
struct sqlite3_vtab {
|
||||||
const sqlite3_module *pModule; /* The module for this virtual table */
|
const sqlite3_module *pModule; /* The module for this virtual table */
|
||||||
int nRef; /* Used internally */
|
int nRef; /* NO LONGER USED */
|
||||||
char *zErrMsg; /* Error message from sqlite3_mprintf() */
|
char *zErrMsg; /* Error message from sqlite3_mprintf() */
|
||||||
/* Virtual table implementations will typically add additional fields */
|
/* Virtual table implementations will typically add additional fields */
|
||||||
};
|
};
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.893 2009/07/13 15:52:38 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.894 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -613,6 +613,7 @@ typedef struct TriggerStack TriggerStack;
|
|||||||
typedef struct TriggerStep TriggerStep;
|
typedef struct TriggerStep TriggerStep;
|
||||||
typedef struct Trigger Trigger;
|
typedef struct Trigger Trigger;
|
||||||
typedef struct UnpackedRecord UnpackedRecord;
|
typedef struct UnpackedRecord UnpackedRecord;
|
||||||
|
typedef struct VTable VTable;
|
||||||
typedef struct Walker Walker;
|
typedef struct Walker Walker;
|
||||||
typedef struct WherePlan WherePlan;
|
typedef struct WherePlan WherePlan;
|
||||||
typedef struct WhereInfo WhereInfo;
|
typedef struct WhereInfo WhereInfo;
|
||||||
@@ -839,8 +840,9 @@ struct sqlite3 {
|
|||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
Hash aModule; /* populated by sqlite3_create_module() */
|
Hash aModule; /* populated by sqlite3_create_module() */
|
||||||
Table *pVTab; /* vtab with active Connect/Create method */
|
Table *pVTab; /* vtab with active Connect/Create method */
|
||||||
sqlite3_vtab **aVTrans; /* Virtual tables with open transactions */
|
VTable **aVTrans; /* Virtual tables with open transactions */
|
||||||
int nVTrans; /* Allocated size of aVTrans */
|
int nVTrans; /* Allocated size of aVTrans */
|
||||||
|
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
|
||||||
#endif
|
#endif
|
||||||
FuncDefHash aFunc; /* Hash table of connection functions */
|
FuncDefHash aFunc; /* Hash table of connection functions */
|
||||||
Hash aCollSeq; /* All collating sequences */
|
Hash aCollSeq; /* All collating sequences */
|
||||||
@@ -905,7 +907,6 @@ struct sqlite3 {
|
|||||||
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
|
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
|
||||||
|
|
||||||
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
|
#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
|
||||||
#define SQLITE_SharedCache 0x00080000 /* Cache sharing is enabled */
|
|
||||||
#define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */
|
#define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1114,6 +1115,56 @@ struct CollSeq {
|
|||||||
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
|
#define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */
|
||||||
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
|
#define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An object of this type is created for each virtual table present in
|
||||||
|
** the database schema.
|
||||||
|
**
|
||||||
|
** If the database schema is shared, then there is one instance of this
|
||||||
|
** structure for each database connection (sqlite3*) that uses the shared
|
||||||
|
** schema. This is because each database connection requires its own unique
|
||||||
|
** instance of the sqlite3_vtab* handle used to access the virtual table
|
||||||
|
** implementation. sqlite3_vtab* handles can not be shared between
|
||||||
|
** database connections, even when the rest of the in-memory database
|
||||||
|
** schema is shared, as the implementation often stores the database
|
||||||
|
** connection handle passed to it via the xConnect() or xCreate() method
|
||||||
|
** during initialization internally. This database connection handle may
|
||||||
|
** then used by the virtual table implementation to access real tables
|
||||||
|
** within the database. So that they appear as part of the callers
|
||||||
|
** transaction, these accesses need to be made via the same database
|
||||||
|
** connection as that used to execute SQL operations on the virtual table.
|
||||||
|
**
|
||||||
|
** All VTable objects that correspond to a single table in a shared
|
||||||
|
** database schema are initially stored in a linked-list pointed to by
|
||||||
|
** the Table.pVTable member variable of the corresponding Table object.
|
||||||
|
** When an sqlite3_prepare() operation is required to access the virtual
|
||||||
|
** table, it searches the list for the VTable that corresponds to the
|
||||||
|
** database connection doing the preparing so as to use the correct
|
||||||
|
** sqlite3_vtab* handle in the compiled query.
|
||||||
|
**
|
||||||
|
** When an in-memory Table object is deleted (for example when the
|
||||||
|
** schema is being reloaded for some reason), the VTable objects are not
|
||||||
|
** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
|
||||||
|
** immediately. Instead, they are moved from the Table.pVTable list to
|
||||||
|
** another linked list headed by the sqlite3.pDisconnect member of the
|
||||||
|
** corresponding sqlite3 structure. They are then deleted/xDisconnected
|
||||||
|
** next time a statement is prepared using said sqlite3*. This is done
|
||||||
|
** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
|
||||||
|
** Refer to comments above function sqlite3VtabUnlockList() for an
|
||||||
|
** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
|
||||||
|
** list without holding the corresponding sqlite3.mutex mutex.
|
||||||
|
**
|
||||||
|
** The memory for objects of this type is always allocated by
|
||||||
|
** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
|
||||||
|
** the first argument.
|
||||||
|
*/
|
||||||
|
struct VTable {
|
||||||
|
sqlite3 *db; /* Database connection 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 */
|
||||||
|
VTable *pNext; /* Next in linked list (see above) */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Each SQL table is represented in memory by an instance of the
|
** Each SQL table is represented in memory by an instance of the
|
||||||
** following structure.
|
** following structure.
|
||||||
@@ -1165,8 +1216,7 @@ struct Table {
|
|||||||
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
|
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
|
||||||
#endif
|
#endif
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
Module *pMod; /* Pointer to the implementation of the module */
|
VTable *pVTable; /* List of VTable objects. */
|
||||||
sqlite3_vtab *pVtab; /* Pointer to the module instance */
|
|
||||||
int nModuleArg; /* Number of arguments to the module */
|
int nModuleArg; /* Number of arguments to the module */
|
||||||
char **azModuleArg; /* Text of all module args. [0] is module name */
|
char **azModuleArg; /* Text of all module args. [0] is module name */
|
||||||
#endif
|
#endif
|
||||||
@@ -2812,21 +2862,25 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
||||||
# define sqlite3VtabClear(X)
|
# define sqlite3VtabClear(Y)
|
||||||
# define sqlite3VtabSync(X,Y) SQLITE_OK
|
# define sqlite3VtabSync(X,Y) SQLITE_OK
|
||||||
# define sqlite3VtabRollback(X)
|
# define sqlite3VtabRollback(X)
|
||||||
# define sqlite3VtabCommit(X)
|
# define sqlite3VtabCommit(X)
|
||||||
# define sqlite3VtabInSync(db) 0
|
# define sqlite3VtabInSync(db) 0
|
||||||
|
# define sqlite3VtabLock(X)
|
||||||
|
# define sqlite3VtabUnlock(X)
|
||||||
|
# define sqlite3VtabUnlockList(X)
|
||||||
#else
|
#else
|
||||||
void sqlite3VtabClear(Table*);
|
void sqlite3VtabClear(Table*);
|
||||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||||
int sqlite3VtabRollback(sqlite3 *db);
|
int sqlite3VtabRollback(sqlite3 *db);
|
||||||
int sqlite3VtabCommit(sqlite3 *db);
|
int sqlite3VtabCommit(sqlite3 *db);
|
||||||
|
void sqlite3VtabLock(VTable *);
|
||||||
|
void sqlite3VtabUnlock(VTable *);
|
||||||
|
void sqlite3VtabUnlockList(sqlite3*);
|
||||||
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
|
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
|
||||||
#endif
|
#endif
|
||||||
void sqlite3VtabMakeWritable(Parse*,Table*);
|
void sqlite3VtabMakeWritable(Parse*,Table*);
|
||||||
void sqlite3VtabLock(sqlite3_vtab*);
|
|
||||||
void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*);
|
|
||||||
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
|
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
|
||||||
void sqlite3VtabFinishParse(Parse*, Token*);
|
void sqlite3VtabFinishParse(Parse*, Token*);
|
||||||
void sqlite3VtabArgInit(Parse*);
|
void sqlite3VtabArgInit(Parse*);
|
||||||
@@ -2834,7 +2888,7 @@ void sqlite3VtabArgExtend(Parse*, Token*);
|
|||||||
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
|
int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
|
||||||
int sqlite3VtabCallConnect(Parse*, Table*);
|
int sqlite3VtabCallConnect(Parse*, Table*);
|
||||||
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
|
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
|
||||||
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
|
int sqlite3VtabBegin(sqlite3 *, VTable *);
|
||||||
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
|
||||||
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
|
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
|
||||||
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
||||||
@@ -2842,6 +2896,7 @@ int sqlite3Reprepare(Vdbe*);
|
|||||||
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
||||||
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
||||||
int sqlite3TempInMemory(const sqlite3*);
|
int sqlite3TempInMemory(const sqlite3*);
|
||||||
|
VTable *sqlite3GetVTable(sqlite3*, Table*);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
10
src/update.c
10
src/update.c
@@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle UPDATE statements.
|
** to handle UPDATE statements.
|
||||||
**
|
**
|
||||||
** $Id: update.c,v 1.204 2009/06/27 11:17:35 drh Exp $
|
** $Id: update.c,v 1.205 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -155,10 +155,10 @@ void sqlite3Update(
|
|||||||
# define isView 0
|
# define isView 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
}
|
}
|
||||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
}
|
}
|
||||||
aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
|
aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
|
||||||
@@ -631,7 +631,7 @@ static void updateVirtualTable(
|
|||||||
int addr; /* Address of top of loop */
|
int addr; /* Address of top of loop */
|
||||||
int iReg; /* First register in set passed to OP_VUpdate */
|
int iReg; /* First register in set passed to OP_VUpdate */
|
||||||
sqlite3 *db = pParse->db; /* Database connection */
|
sqlite3 *db = pParse->db; /* Database connection */
|
||||||
const char *pVtab = (const char*)pTab->pVtab;
|
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
|
||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
|
|
||||||
/* Construct the SELECT statement that will find the new values for
|
/* Construct the SELECT statement that will find the new values for
|
||||||
@@ -676,7 +676,7 @@ static void updateVirtualTable(
|
|||||||
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
|
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
|
||||||
}
|
}
|
||||||
sqlite3VtabMakeWritable(pParse, pTab);
|
sqlite3VtabMakeWritable(pParse, pTab);
|
||||||
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVtab, P4_VTAB);
|
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
|
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
|
||||||
|
28
src/vdbe.c
28
src/vdbe.c
@@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.873 2009/07/22 00:35:24 drh Exp $
|
** $Id: vdbe.c,v 1.874 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
@@ -5017,13 +5017,13 @@ case OP_TableLock: {
|
|||||||
** code will be set to SQLITE_LOCKED.
|
** code will be set to SQLITE_LOCKED.
|
||||||
*/
|
*/
|
||||||
case OP_VBegin: {
|
case OP_VBegin: {
|
||||||
sqlite3_vtab *pVtab;
|
VTable *pVTab;
|
||||||
pVtab = pOp->p4.pVtab;
|
pVTab = pOp->p4.pVtab;
|
||||||
rc = sqlite3VtabBegin(db, pVtab);
|
rc = sqlite3VtabBegin(db, pVTab);
|
||||||
if( pVtab ){
|
if( pVTab ){
|
||||||
sqlite3DbFree(db, p->zErrMsg);
|
sqlite3DbFree(db, p->zErrMsg);
|
||||||
p->zErrMsg = pVtab->zErrMsg;
|
p->zErrMsg = pVTab->pVtab->zErrMsg;
|
||||||
pVtab->zErrMsg = 0;
|
pVTab->pVtab->zErrMsg = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -5070,7 +5070,7 @@ case OP_VOpen: {
|
|||||||
|
|
||||||
pCur = 0;
|
pCur = 0;
|
||||||
pVtabCursor = 0;
|
pVtabCursor = 0;
|
||||||
pVtab = pOp->p4.pVtab;
|
pVtab = pOp->p4.pVtab->pVtab;
|
||||||
pModule = (sqlite3_module *)pVtab->pModule;
|
pModule = (sqlite3_module *)pVtab->pModule;
|
||||||
assert(pVtab && pModule);
|
assert(pVtab && pModule);
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
@@ -5153,14 +5153,12 @@ case OP_VFilter: { /* jump */
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
sqlite3VtabLock(pVtab);
|
|
||||||
p->inVtabMethod = 1;
|
p->inVtabMethod = 1;
|
||||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||||
p->inVtabMethod = 0;
|
p->inVtabMethod = 0;
|
||||||
sqlite3DbFree(db, p->zErrMsg);
|
sqlite3DbFree(db, p->zErrMsg);
|
||||||
p->zErrMsg = pVtab->zErrMsg;
|
p->zErrMsg = pVtab->zErrMsg;
|
||||||
pVtab->zErrMsg = 0;
|
pVtab->zErrMsg = 0;
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
res = pModule->xEof(pVtabCursor);
|
res = pModule->xEof(pVtabCursor);
|
||||||
}
|
}
|
||||||
@@ -5268,14 +5266,12 @@ case OP_VNext: { /* jump */
|
|||||||
** some other method is next invoked on the save virtual table cursor.
|
** some other method is next invoked on the save virtual table cursor.
|
||||||
*/
|
*/
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
sqlite3VtabLock(pVtab);
|
|
||||||
p->inVtabMethod = 1;
|
p->inVtabMethod = 1;
|
||||||
rc = pModule->xNext(pCur->pVtabCursor);
|
rc = pModule->xNext(pCur->pVtabCursor);
|
||||||
p->inVtabMethod = 0;
|
p->inVtabMethod = 0;
|
||||||
sqlite3DbFree(db, p->zErrMsg);
|
sqlite3DbFree(db, p->zErrMsg);
|
||||||
p->zErrMsg = pVtab->zErrMsg;
|
p->zErrMsg = pVtab->zErrMsg;
|
||||||
pVtab->zErrMsg = 0;
|
pVtab->zErrMsg = 0;
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
res = pModule->xEof(pCur->pVtabCursor);
|
res = pModule->xEof(pCur->pVtabCursor);
|
||||||
}
|
}
|
||||||
@@ -5300,18 +5296,16 @@ case OP_VRename: {
|
|||||||
sqlite3_vtab *pVtab;
|
sqlite3_vtab *pVtab;
|
||||||
Mem *pName;
|
Mem *pName;
|
||||||
|
|
||||||
pVtab = pOp->p4.pVtab;
|
pVtab = pOp->p4.pVtab->pVtab;
|
||||||
pName = &p->aMem[pOp->p1];
|
pName = &p->aMem[pOp->p1];
|
||||||
assert( pVtab->pModule->xRename );
|
assert( pVtab->pModule->xRename );
|
||||||
REGISTER_TRACE(pOp->p1, pName);
|
REGISTER_TRACE(pOp->p1, pName);
|
||||||
assert( pName->flags & MEM_Str );
|
assert( pName->flags & MEM_Str );
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
sqlite3VtabLock(pVtab);
|
|
||||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||||
sqlite3DbFree(db, p->zErrMsg);
|
sqlite3DbFree(db, p->zErrMsg);
|
||||||
p->zErrMsg = pVtab->zErrMsg;
|
p->zErrMsg = pVtab->zErrMsg;
|
||||||
pVtab->zErrMsg = 0;
|
pVtab->zErrMsg = 0;
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
|
||||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -5351,7 +5345,7 @@ case OP_VUpdate: {
|
|||||||
Mem **apArg;
|
Mem **apArg;
|
||||||
Mem *pX;
|
Mem *pX;
|
||||||
|
|
||||||
pVtab = pOp->p4.pVtab;
|
pVtab = pOp->p4.pVtab->pVtab;
|
||||||
pModule = (sqlite3_module *)pVtab->pModule;
|
pModule = (sqlite3_module *)pVtab->pModule;
|
||||||
nArg = pOp->p2;
|
nArg = pOp->p2;
|
||||||
assert( pOp->p4type==P4_VTAB );
|
assert( pOp->p4type==P4_VTAB );
|
||||||
@@ -5364,12 +5358,10 @@ case OP_VUpdate: {
|
|||||||
pX++;
|
pX++;
|
||||||
}
|
}
|
||||||
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
|
||||||
sqlite3VtabLock(pVtab);
|
|
||||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||||
sqlite3DbFree(db, p->zErrMsg);
|
sqlite3DbFree(db, p->zErrMsg);
|
||||||
p->zErrMsg = pVtab->zErrMsg;
|
p->zErrMsg = pVtab->zErrMsg;
|
||||||
pVtab->zErrMsg = 0;
|
pVtab->zErrMsg = 0;
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
|
||||||
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
|
||||||
if( rc==SQLITE_OK && pOp->p1 ){
|
if( rc==SQLITE_OK && pOp->p1 ){
|
||||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||||
** simple program to access and modify the underlying database.
|
** simple program to access and modify the underlying database.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.h,v 1.141 2009/04/10 00:56:29 drh Exp $
|
** $Id: vdbe.h,v 1.142 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_VDBE_H_
|
#ifndef _SQLITE_VDBE_H_
|
||||||
#define _SQLITE_VDBE_H_
|
#define _SQLITE_VDBE_H_
|
||||||
@@ -58,7 +58,7 @@ struct VdbeOp {
|
|||||||
VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
|
VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
|
||||||
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
|
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
|
||||||
Mem *pMem; /* Used when p4type is P4_MEM */
|
Mem *pMem; /* Used when p4type is P4_MEM */
|
||||||
sqlite3_vtab *pVtab; /* Used when p4type is P4_VTAB */
|
VTable *pVtab; /* Used when p4type is P4_VTAB */
|
||||||
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
|
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
|
||||||
int *ai; /* Used when p4type is P4_INTARRAY */
|
int *ai; /* Used when p4type is P4_INTARRAY */
|
||||||
} p4;
|
} p4;
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
** to version 2.8.7, all this code was combined into the vdbe.c source file.
|
||||||
** But that file was getting too big so this subroutines were split out.
|
** But that file was getting too big so this subroutines were split out.
|
||||||
**
|
**
|
||||||
** $Id: vdbeaux.c,v 1.477 2009/07/22 00:35:24 drh Exp $
|
** $Id: vdbeaux.c,v 1.478 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
@@ -478,6 +478,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
|||||||
sqlite3ValueFree((sqlite3_value*)p4);
|
sqlite3ValueFree((sqlite3_value*)p4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case P4_VTAB : {
|
||||||
|
sqlite3VtabUnlock((VTable *)p4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,7 +535,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
|||||||
db = p->db;
|
db = p->db;
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p->aOp==0 || db->mallocFailed ){
|
if( p->aOp==0 || db->mallocFailed ){
|
||||||
if (n != P4_KEYINFO) {
|
if ( n!=P4_KEYINFO && n!=P4_VTAB ) {
|
||||||
freeP4(db, n, (void*)*(char**)&zP4);
|
freeP4(db, n, (void*)*(char**)&zP4);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -576,6 +580,11 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
|||||||
}else if( n==P4_KEYINFO_HANDOFF ){
|
}else if( n==P4_KEYINFO_HANDOFF ){
|
||||||
pOp->p4.p = (void*)zP4;
|
pOp->p4.p = (void*)zP4;
|
||||||
pOp->p4type = P4_KEYINFO;
|
pOp->p4type = P4_KEYINFO;
|
||||||
|
}else if( n==P4_VTAB ){
|
||||||
|
pOp->p4.p = (void*)zP4;
|
||||||
|
pOp->p4type = P4_VTAB;
|
||||||
|
sqlite3VtabLock((VTable *)zP4);
|
||||||
|
assert( ((VTable *)zP4)->db==p->db );
|
||||||
}else if( n<0 ){
|
}else if( n<0 ){
|
||||||
pOp->p4.p = (void*)zP4;
|
pOp->p4.p = (void*)zP4;
|
||||||
pOp->p4type = (signed char)n;
|
pOp->p4type = (signed char)n;
|
||||||
@@ -731,7 +740,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
case P4_VTAB: {
|
case P4_VTAB: {
|
||||||
sqlite3_vtab *pVtab = pOp->p4.pVtab;
|
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
|
||||||
sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
|
sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
413
src/vtab.c
413
src/vtab.c
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to help implement virtual tables.
|
** This file contains code used to help implement virtual tables.
|
||||||
**
|
**
|
||||||
** $Id: vtab.c,v 1.92 2009/07/01 18:04:21 danielk1977 Exp $
|
** $Id: vtab.c,v 1.93 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
@@ -27,7 +27,7 @@ static int createModule(
|
|||||||
const sqlite3_module *pModule, /* The definition of the module */
|
const sqlite3_module *pModule, /* The definition of the module */
|
||||||
void *pAux, /* Context pointer for xCreate/xConnect */
|
void *pAux, /* Context pointer for xCreate/xConnect */
|
||||||
void (*xDestroy)(void *) /* Module destructor function */
|
void (*xDestroy)(void *) /* Module destructor function */
|
||||||
) {
|
){
|
||||||
int rc, nName;
|
int rc, nName;
|
||||||
Module *pMod;
|
Module *pMod;
|
||||||
|
|
||||||
@@ -93,33 +93,128 @@ int sqlite3_create_module_v2(
|
|||||||
** If a disconnect is attempted while a virtual table is locked,
|
** If a disconnect is attempted while a virtual table is locked,
|
||||||
** the disconnect is deferred until all locks have been removed.
|
** the disconnect is deferred until all locks have been removed.
|
||||||
*/
|
*/
|
||||||
void sqlite3VtabLock(sqlite3_vtab *pVtab){
|
void sqlite3VtabLock(VTable *pVTab){
|
||||||
pVtab->nRef++;
|
pVTab->nRef++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** pTab is a pointer to a Table structure representing a virtual-table.
|
||||||
|
** 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 *pVtab;
|
||||||
|
assert( IsVirtual(pTab) );
|
||||||
|
for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
|
||||||
|
return pVtab;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Unlock a virtual table. When the last lock is removed,
|
** Decrement the ref-count on a virtual table object. When the ref-count
|
||||||
** disconnect the virtual table.
|
** reaches zero, call the xDisconnect() method to delete the object.
|
||||||
*/
|
*/
|
||||||
void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
|
void sqlite3VtabUnlock(VTable *pVTab){
|
||||||
#ifndef SQLITE_DEBUG
|
sqlite3 *db = pVTab->db;
|
||||||
UNUSED_PARAMETER(db);
|
|
||||||
#endif
|
assert( db );
|
||||||
assert( pVtab->nRef>0 );
|
assert( pVTab->nRef>0 );
|
||||||
pVtab->nRef--;
|
|
||||||
assert(db);
|
|
||||||
assert( sqlite3SafetyCheckOk(db) );
|
assert( sqlite3SafetyCheckOk(db) );
|
||||||
if( pVtab->nRef==0 ){
|
|
||||||
|
pVTab->nRef--;
|
||||||
|
if( pVTab->nRef==0 ){
|
||||||
|
sqlite3_vtab *p = pVTab->pVtab;
|
||||||
|
if( p ){
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
if( db->magic==SQLITE_MAGIC_BUSY ){
|
if( pVTab->db->magic==SQLITE_MAGIC_BUSY ){
|
||||||
(void)sqlite3SafetyOff(db);
|
(void)sqlite3SafetyOff(db);
|
||||||
pVtab->pModule->xDisconnect(pVtab);
|
p->pModule->xDisconnect(p);
|
||||||
(void)sqlite3SafetyOn(db);
|
(void)sqlite3SafetyOn(db);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
pVtab->pModule->xDisconnect(pVtab);
|
p->pModule->xDisconnect(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sqlite3DbFree(db, pVTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Table p is a virtual table. This function moves all elements in the
|
||||||
|
** p->pVTable list to the sqlite3.pDisconnect lists of their associated
|
||||||
|
** database connections to be disconnected at the next opportunity.
|
||||||
|
** Except, if argument db is not NULL, then the entry associated with
|
||||||
|
** connection db is left in the p->pVTable list.
|
||||||
|
*/
|
||||||
|
static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
||||||
|
VTable *pRet = 0;
|
||||||
|
VTable *pVTable = p->pVTable;
|
||||||
|
p->pVTable = 0;
|
||||||
|
|
||||||
|
/* Assert that the mutex (if any) associated with the BtShared database
|
||||||
|
** that contains table p is held by the caller. See header comments
|
||||||
|
** above function sqlite3VtabUnlockList() for an explanation of why
|
||||||
|
** this makes it safe to access the sqlite3.pDisconnect list of any
|
||||||
|
** database connection that may have an entry in the p->pVTable list. */
|
||||||
|
assert( db==0 ||
|
||||||
|
sqlite3BtreeHoldsMutex(db->aDb[sqlite3SchemaToIndex(db, p->pSchema)].pBt)
|
||||||
|
);
|
||||||
|
|
||||||
|
while( pVTable ){
|
||||||
|
sqlite3 *db2 = pVTable->db;
|
||||||
|
VTable *pNext = pVTable->pNext;
|
||||||
|
assert( db2 );
|
||||||
|
if( db2==db ){
|
||||||
|
pRet = pVTable;
|
||||||
|
p->pVTable = pRet;
|
||||||
|
pRet->pNext = 0;
|
||||||
|
}else{
|
||||||
|
pVTable->pNext = db2->pDisconnect;
|
||||||
|
db2->pDisconnect = pVTable;
|
||||||
|
}
|
||||||
|
pVTable = pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( !db || pRet );
|
||||||
|
return pRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
|
||||||
|
**
|
||||||
|
** This function may only be called when the mutexes associated with all
|
||||||
|
** shared b-tree databases opened using connection db are held by the
|
||||||
|
** caller. This is done to protect the sqlite3.pDisconnect list. The
|
||||||
|
** sqlite3.pDisconnect list is accessed only as follows:
|
||||||
|
**
|
||||||
|
** 1) By this function. In this case, all BtShared mutexes and the mutex
|
||||||
|
** associated with the database handle itself must be held.
|
||||||
|
**
|
||||||
|
** 2) By function vtabDisconnectAll(), when it adds a VTable entry to
|
||||||
|
** the sqlite3.pDisconnect list. In this case either the BtShared mutex
|
||||||
|
** associated with the database the virtual table is stored in is held
|
||||||
|
** or, if the virtual table is stored in a non-sharable database, then
|
||||||
|
** the database handle mutex is held.
|
||||||
|
**
|
||||||
|
** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
|
||||||
|
** by multiple threads. It is thread-safe.
|
||||||
|
*/
|
||||||
|
void sqlite3VtabUnlockList(sqlite3 *db){
|
||||||
|
VTable *p = db->pDisconnect;
|
||||||
|
db->pDisconnect = 0;
|
||||||
|
|
||||||
|
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||||
|
assert( sqlite3_mutex_held(db->mutex) );
|
||||||
|
|
||||||
|
if( p ){
|
||||||
|
sqlite3ExpirePreparedStatements(db);
|
||||||
|
do {
|
||||||
|
VTable *pNext = p->pNext;
|
||||||
|
sqlite3VtabUnlock(p);
|
||||||
|
p = pNext;
|
||||||
|
}while( p );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,22 +222,24 @@ void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
|
|||||||
** Clear any and all virtual-table information from the Table record.
|
** Clear any and all virtual-table information from the Table record.
|
||||||
** This routine is called, for example, just before deleting the Table
|
** This routine is called, for example, just before deleting the Table
|
||||||
** record.
|
** record.
|
||||||
|
**
|
||||||
|
** Since it is a virtual-table, the Table structure contains a pointer
|
||||||
|
** to the head of a linked list of VTable structures. Each VTable
|
||||||
|
** structure is associated with a single sqlite3* user of the schema.
|
||||||
|
** The reference count of the VTable structure associated with database
|
||||||
|
** connection db is decremented immediately (which may lead to the
|
||||||
|
** structure being xDisconnected and free). Any other VTable structures
|
||||||
|
** in the list are moved to the sqlite3.pDisconnect list of the associated
|
||||||
|
** database connection.
|
||||||
*/
|
*/
|
||||||
void sqlite3VtabClear(Table *p){
|
void sqlite3VtabClear(Table *p){
|
||||||
sqlite3_vtab *pVtab = p->pVtab;
|
vtabDisconnectAll(0, p);
|
||||||
Schema *pSchema = p->pSchema;
|
|
||||||
sqlite3 *db = pSchema ? pSchema->db : 0;
|
|
||||||
if( pVtab ){
|
|
||||||
assert( p->pMod && p->pMod->pModule );
|
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
|
||||||
p->pVtab = 0;
|
|
||||||
}
|
|
||||||
if( p->azModuleArg ){
|
if( p->azModuleArg ){
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<p->nModuleArg; i++){
|
for(i=0; i<p->nModuleArg; i++){
|
||||||
sqlite3DbFree(db, p->azModuleArg[i]);
|
sqlite3DbFree(p->dbMem, p->azModuleArg[i]);
|
||||||
}
|
}
|
||||||
sqlite3DbFree(db, p->azModuleArg);
|
sqlite3DbFree(p->dbMem, p->azModuleArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,11 +284,6 @@ void sqlite3VtabBeginParse(
|
|||||||
Table *pTable; /* The new virtual table */
|
Table *pTable; /* The new virtual table */
|
||||||
sqlite3 *db; /* Database connection */
|
sqlite3 *db; /* Database connection */
|
||||||
|
|
||||||
if( pParse->db->flags & SQLITE_SharedCache ){
|
|
||||||
sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
|
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
|
||||||
pTable = pParse->pNewTable;
|
pTable = pParse->pNewTable;
|
||||||
if( pTable==0 ) return;
|
if( pTable==0 ) return;
|
||||||
@@ -240,23 +332,13 @@ static void addArgumentToVtab(Parse *pParse){
|
|||||||
** has been completely parsed.
|
** has been completely parsed.
|
||||||
*/
|
*/
|
||||||
void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||||
Table *pTab; /* The table being constructed */
|
Table *pTab = pParse->pNewTable; /* The table being constructed */
|
||||||
sqlite3 *db; /* The database connection */
|
sqlite3 *db = pParse->db; /* The database connection */
|
||||||
char *zModule; /* The module name of the table: USING modulename */
|
|
||||||
Module *pMod = 0;
|
|
||||||
|
|
||||||
|
if( pTab==0 ) return;
|
||||||
addArgumentToVtab(pParse);
|
addArgumentToVtab(pParse);
|
||||||
pParse->sArg.z = 0;
|
pParse->sArg.z = 0;
|
||||||
|
|
||||||
/* Lookup the module name. */
|
|
||||||
pTab = pParse->pNewTable;
|
|
||||||
if( pTab==0 ) return;
|
|
||||||
db = pParse->db;
|
|
||||||
if( pTab->nModuleArg<1 ) return;
|
if( pTab->nModuleArg<1 ) return;
|
||||||
zModule = pTab->azModuleArg[0];
|
|
||||||
pMod = (Module*)sqlite3HashFind(&db->aModule, zModule,
|
|
||||||
sqlite3Strlen30(zModule));
|
|
||||||
pTab->pMod = pMod;
|
|
||||||
|
|
||||||
/* If the CREATE VIRTUAL TABLE statement is being entered for the
|
/* If the CREATE VIRTUAL TABLE statement is being entered for the
|
||||||
** first time (in other words if the virtual table is actually being
|
** first time (in other words if the virtual table is actually being
|
||||||
@@ -307,9 +389,10 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we are rereading the sqlite_master table create the in-memory
|
/* If we are rereading the sqlite_master table create the in-memory
|
||||||
** record of the table. If the module has already been registered,
|
** record of the table. The xConnect() method is not called until
|
||||||
** also call the xConnect method here.
|
** the first time the virtual table is used in an SQL statement. This
|
||||||
*/
|
** allows a schema that contains virtual tables to be loaded before
|
||||||
|
** the required virtual table implementations are registered. */
|
||||||
else {
|
else {
|
||||||
Table *pOld;
|
Table *pOld;
|
||||||
Schema *pSchema = pTab->pSchema;
|
Schema *pSchema = pTab->pSchema;
|
||||||
@@ -363,9 +446,8 @@ static int vtabCallConstructor(
|
|||||||
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
||||||
char **pzErr
|
char **pzErr
|
||||||
){
|
){
|
||||||
|
VTable *pVTable;
|
||||||
int rc;
|
int rc;
|
||||||
int rc2;
|
|
||||||
sqlite3_vtab *pVtab = 0;
|
|
||||||
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
||||||
int nArg = pTab->nModuleArg;
|
int nArg = pTab->nModuleArg;
|
||||||
char *zErr = 0;
|
char *zErr = 0;
|
||||||
@@ -375,22 +457,23 @@ static int vtabCallConstructor(
|
|||||||
return SQLITE_NOMEM;
|
return SQLITE_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
|
||||||
|
if( !pVTable ){
|
||||||
|
sqlite3DbFree(db, zModuleName);
|
||||||
|
return SQLITE_NOMEM;
|
||||||
|
}
|
||||||
|
pVTable->db = db;
|
||||||
|
pVTable->pMod = pMod;
|
||||||
|
|
||||||
assert( !db->pVTab );
|
assert( !db->pVTab );
|
||||||
assert( xConstruct );
|
assert( xConstruct );
|
||||||
|
|
||||||
db->pVTab = pTab;
|
db->pVTab = pTab;
|
||||||
rc = sqlite3SafetyOff(db);
|
|
||||||
assert( rc==SQLITE_OK );
|
/* Invoke the virtual table constructor */
|
||||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVtab, &zErr);
|
(void)sqlite3SafetyOff(db);
|
||||||
rc2 = sqlite3SafetyOn(db);
|
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||||
|
(void)sqlite3SafetyOn(db);
|
||||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||||
/* Justification of ALWAYS(): A correct vtab constructor must allocate
|
|
||||||
** the sqlite3_vtab object if successful. */
|
|
||||||
if( rc==SQLITE_OK && ALWAYS(pVtab) ){
|
|
||||||
pVtab->pModule = pMod->pModule;
|
|
||||||
pVtab->nRef = 1;
|
|
||||||
pTab->pVtab = pVtab;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( SQLITE_OK!=rc ){
|
if( SQLITE_OK!=rc ){
|
||||||
if( zErr==0 ){
|
if( zErr==0 ){
|
||||||
@@ -399,54 +482,61 @@ static int vtabCallConstructor(
|
|||||||
*pzErr = sqlite3MPrintf(db, "%s", zErr);
|
*pzErr = sqlite3MPrintf(db, "%s", zErr);
|
||||||
sqlite3DbFree(db, zErr);
|
sqlite3DbFree(db, zErr);
|
||||||
}
|
}
|
||||||
}else if( db->pVTab ){
|
sqlite3DbFree(db, pVTable);
|
||||||
const char *zFormat = "vtable constructor did not declare schema: %s";
|
}else if( ALWAYS(pVTable->pVtab) ){
|
||||||
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
/* Justification of ALWAYS(): A correct vtab constructor must allocate
|
||||||
rc = SQLITE_ERROR;
|
** the sqlite3_vtab object if successful. */
|
||||||
}
|
pVTable->pVtab->pModule = pMod->pModule;
|
||||||
if( rc==SQLITE_OK ){
|
pVTable->nRef = 1;
|
||||||
rc = rc2;
|
if( db->pVTab ){
|
||||||
}
|
const char *zFormat = "vtable constructor did not declare schema: %s";
|
||||||
db->pVTab = 0;
|
*pzErr = sqlite3MPrintf(db, zFormat, pTab->zName);
|
||||||
sqlite3DbFree(db, zModuleName);
|
sqlite3VtabUnlock(pVTable);
|
||||||
|
rc = SQLITE_ERROR;
|
||||||
|
}else{
|
||||||
|
int iCol;
|
||||||
|
/* If everything went according to plan, link the new VTable structure
|
||||||
|
** into the linked list headed by pTab->pVTable. Then loop through the
|
||||||
|
** columns of the table to see if any of them contain the token "hidden".
|
||||||
|
** If so, set the Column.isHidden flag and remove the token from
|
||||||
|
** the type string. */
|
||||||
|
pVTable->pNext = pTab->pVTable;
|
||||||
|
pTab->pVTable = pVTable;
|
||||||
|
|
||||||
/* If everything went according to plan, loop through the columns
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||||
** of the table to see if any of them contain the token "hidden".
|
char *zType = pTab->aCol[iCol].zType;
|
||||||
** If so, set the Column.isHidden flag and remove the token from
|
int nType;
|
||||||
** the type string.
|
int i = 0;
|
||||||
*/
|
if( !zType ) continue;
|
||||||
if( rc==SQLITE_OK ){
|
nType = sqlite3Strlen30(zType);
|
||||||
int iCol;
|
if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
|
||||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
for(i=0; i<nType; i++){
|
||||||
char *zType = pTab->aCol[iCol].zType;
|
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
|
||||||
int nType;
|
&& (zType[i+7]=='\0' || zType[i+7]==' ')
|
||||||
int i = 0;
|
){
|
||||||
if( !zType ) continue;
|
i++;
|
||||||
nType = sqlite3Strlen30(zType);
|
break;
|
||||||
if( sqlite3StrNICmp("hidden", zType, 6) || (zType[6] && zType[6]!=' ') ){
|
}
|
||||||
for(i=0; i<nType; i++){
|
|
||||||
if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
|
|
||||||
&& (zType[i+7]=='\0' || zType[i+7]==' ')
|
|
||||||
){
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if( i<nType ){
|
||||||
if( i<nType ){
|
int j;
|
||||||
int j;
|
int nDel = 6 + (zType[i+6] ? 1 : 0);
|
||||||
int nDel = 6 + (zType[i+6] ? 1 : 0);
|
for(j=i; (j+nDel)<=nType; j++){
|
||||||
for(j=i; (j+nDel)<=nType; j++){
|
zType[j] = zType[j+nDel];
|
||||||
zType[j] = zType[j+nDel];
|
}
|
||||||
|
if( zType[i]=='\0' && i>0 ){
|
||||||
|
assert(zType[i-1]==' ');
|
||||||
|
zType[i-1] = '\0';
|
||||||
|
}
|
||||||
|
pTab->aCol[iCol].isHidden = 1;
|
||||||
}
|
}
|
||||||
if( zType[i]=='\0' && i>0 ){
|
|
||||||
assert(zType[i-1]==' ');
|
|
||||||
zType[i-1] = '\0';
|
|
||||||
}
|
|
||||||
pTab->aCol[iCol].isHidden = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite3DbFree(db, zModuleName);
|
||||||
|
db->pVTab = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,20 +548,25 @@ static int vtabCallConstructor(
|
|||||||
** This call is a no-op if table pTab is not a virtual table.
|
** This call is a no-op if table pTab is not a virtual table.
|
||||||
*/
|
*/
|
||||||
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
||||||
|
sqlite3 *db = pParse->db;
|
||||||
|
const char *zMod;
|
||||||
Module *pMod;
|
Module *pMod;
|
||||||
int rc = SQLITE_OK;
|
int rc;
|
||||||
|
|
||||||
assert( pTab );
|
assert( pTab );
|
||||||
if( (pTab->tabFlags & TF_Virtual)==0 || pTab->pVtab ){
|
if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
pMod = pTab->pMod;
|
/* Locate the required virtual table module */
|
||||||
|
zMod = pTab->azModuleArg[0];
|
||||||
|
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
|
||||||
|
|
||||||
if( !pMod ){
|
if( !pMod ){
|
||||||
const char *zModule = pTab->azModuleArg[0];
|
const char *zModule = pTab->azModuleArg[0];
|
||||||
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
} else {
|
}else{
|
||||||
char *zErr = 0;
|
char *zErr = 0;
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
|
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
|
||||||
@@ -485,14 +580,14 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add the virtual table pVtab to the array sqlite3.aVTrans[].
|
** Add the virtual table pVTab to the array sqlite3.aVTrans[].
|
||||||
*/
|
*/
|
||||||
static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
|
static int addToVTrans(sqlite3 *db, VTable *pVTab){
|
||||||
const int ARRAY_INCR = 5;
|
const int ARRAY_INCR = 5;
|
||||||
|
|
||||||
/* Grow the sqlite3.aVTrans array if required */
|
/* Grow the sqlite3.aVTrans array if required */
|
||||||
if( (db->nVTrans%ARRAY_INCR)==0 ){
|
if( (db->nVTrans%ARRAY_INCR)==0 ){
|
||||||
sqlite3_vtab **aVTrans;
|
VTable **aVTrans;
|
||||||
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
|
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
|
||||||
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
|
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
|
||||||
if( !aVTrans ){
|
if( !aVTrans ){
|
||||||
@@ -503,8 +598,8 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add pVtab to the end of sqlite3.aVTrans */
|
/* Add pVtab to the end of sqlite3.aVTrans */
|
||||||
db->aVTrans[db->nVTrans++] = pVtab;
|
db->aVTrans[db->nVTrans++] = pVTab;
|
||||||
sqlite3VtabLock(pVtab);
|
sqlite3VtabLock(pVTab);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,19 +615,21 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
|||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
Module *pMod;
|
Module *pMod;
|
||||||
const char *zModule;
|
const char *zMod;
|
||||||
|
|
||||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
||||||
assert(pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVtab);
|
assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
|
||||||
pMod = pTab->pMod;
|
|
||||||
zModule = pTab->azModuleArg[0];
|
/* Locate the required virtual table module */
|
||||||
|
zMod = pTab->azModuleArg[0];
|
||||||
|
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(zMod));
|
||||||
|
|
||||||
/* If the module has been registered and includes a Create method,
|
/* If the module has been registered and includes a Create method,
|
||||||
** invoke it now. If the module has not been registered, return an
|
** invoke it now. If the module has not been registered, return an
|
||||||
** error. Otherwise, do nothing.
|
** error. Otherwise, do nothing.
|
||||||
*/
|
*/
|
||||||
if( !pMod ){
|
if( !pMod ){
|
||||||
*pzErr = sqlite3MPrintf(db, "no such module: %s", zModule);
|
*pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}else{
|
}else{
|
||||||
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
|
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr);
|
||||||
@@ -540,8 +637,8 @@ int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab, char **pzErr){
|
|||||||
|
|
||||||
/* Justification of ALWAYS(): The xConstructor method is required to
|
/* Justification of ALWAYS(): The xConstructor method is required to
|
||||||
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
|
** create a valid sqlite3_vtab if it returns SQLITE_OK. */
|
||||||
if( rc==SQLITE_OK && ALWAYS(pTab->pVtab) ){
|
if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){
|
||||||
rc = addToVTrans(db, pTab->pVtab);
|
rc = addToVTrans(db, sqlite3GetVTable(db, pTab));
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -566,7 +663,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|||||||
sqlite3_mutex_leave(db->mutex);
|
sqlite3_mutex_leave(db->mutex);
|
||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
assert((pTab->tabFlags & TF_Virtual)!=0 && pTab->nCol==0 && pTab->aCol==0);
|
assert( (pTab->tabFlags & TF_Virtual)!=0 );
|
||||||
|
|
||||||
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
|
||||||
if( pParse==0 ){
|
if( pParse==0 ){
|
||||||
@@ -581,10 +678,12 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|||||||
!pParse->pNewTable->pSelect &&
|
!pParse->pNewTable->pSelect &&
|
||||||
(pParse->pNewTable->tabFlags & TF_Virtual)==0
|
(pParse->pNewTable->tabFlags & TF_Virtual)==0
|
||||||
){
|
){
|
||||||
pTab->aCol = pParse->pNewTable->aCol;
|
if( !pTab->aCol ){
|
||||||
pTab->nCol = pParse->pNewTable->nCol;
|
pTab->aCol = pParse->pNewTable->aCol;
|
||||||
pParse->pNewTable->nCol = 0;
|
pTab->nCol = pParse->pNewTable->nCol;
|
||||||
pParse->pNewTable->aCol = 0;
|
pParse->pNewTable->nCol = 0;
|
||||||
|
pParse->pNewTable->aCol = 0;
|
||||||
|
}
|
||||||
db->pVTab = 0;
|
db->pVTab = 0;
|
||||||
} else {
|
} else {
|
||||||
sqlite3Error(db, SQLITE_ERROR, zErr);
|
sqlite3Error(db, SQLITE_ERROR, zErr);
|
||||||
@@ -618,21 +717,20 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
|
|||||||
Table *pTab;
|
Table *pTab;
|
||||||
|
|
||||||
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
|
||||||
if( ALWAYS(pTab!=0 && pTab->pVtab!=0) ){
|
if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
|
||||||
int (*xDestroy)(sqlite3_vtab *pVTab) = pTab->pMod->pModule->xDestroy;
|
VTable *p = vtabDisconnectAll(db, pTab);
|
||||||
|
|
||||||
rc = sqlite3SafetyOff(db);
|
rc = sqlite3SafetyOff(db);
|
||||||
assert( rc==SQLITE_OK );
|
assert( rc==SQLITE_OK );
|
||||||
rc = xDestroy(pTab->pVtab);
|
rc = p->pMod->pModule->xDestroy(p->pVtab);
|
||||||
(void)sqlite3SafetyOn(db);
|
(void)sqlite3SafetyOn(db);
|
||||||
|
|
||||||
|
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
int i;
|
assert( pTab->pVTable==p && p->pNext==0 );
|
||||||
for(i=0; i<db->nVTrans; i++){
|
p->pVtab = 0;
|
||||||
if( db->aVTrans[i]==pTab->pVtab ){
|
pTab->pVTable = 0;
|
||||||
db->aVTrans[i] = db->aVTrans[--db->nVTrans];
|
sqlite3VtabUnlock(p);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pTab->pVtab = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,13 +749,14 @@ static void callFinaliser(sqlite3 *db, int offset){
|
|||||||
int i;
|
int i;
|
||||||
if( db->aVTrans ){
|
if( db->aVTrans ){
|
||||||
for(i=0; i<db->nVTrans; i++){
|
for(i=0; i<db->nVTrans; i++){
|
||||||
sqlite3_vtab *pVtab = db->aVTrans[i];
|
VTable *pVTab = db->aVTrans[i];
|
||||||
int (*x)(sqlite3_vtab *);
|
sqlite3_vtab *p = pVTab->pVtab;
|
||||||
|
if( p ){
|
||||||
assert( pVtab!=0 );
|
int (*x)(sqlite3_vtab *);
|
||||||
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
|
x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset);
|
||||||
if( x ) x(pVtab);
|
if( x ) x(p);
|
||||||
sqlite3VtabUnlock(db, pVtab);
|
}
|
||||||
|
sqlite3VtabUnlock(pVTab);
|
||||||
}
|
}
|
||||||
sqlite3DbFree(db, db->aVTrans);
|
sqlite3DbFree(db, db->aVTrans);
|
||||||
db->nVTrans = 0;
|
db->nVTrans = 0;
|
||||||
@@ -677,16 +776,14 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
|||||||
int i;
|
int i;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
int rcsafety;
|
int rcsafety;
|
||||||
sqlite3_vtab **aVTrans = db->aVTrans;
|
VTable **aVTrans = db->aVTrans;
|
||||||
|
|
||||||
rc = sqlite3SafetyOff(db);
|
rc = sqlite3SafetyOff(db);
|
||||||
db->aVTrans = 0;
|
db->aVTrans = 0;
|
||||||
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
|
||||||
sqlite3_vtab *pVtab = aVTrans[i];
|
|
||||||
int (*x)(sqlite3_vtab *);
|
int (*x)(sqlite3_vtab *);
|
||||||
assert( pVtab!=0 );
|
sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
|
||||||
x = pVtab->pModule->xSync;
|
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
|
||||||
if( x ){
|
|
||||||
rc = x(pVtab);
|
rc = x(pVtab);
|
||||||
sqlite3DbFree(db, *pzErrmsg);
|
sqlite3DbFree(db, *pzErrmsg);
|
||||||
*pzErrmsg = pVtab->zErrMsg;
|
*pzErrmsg = pVtab->zErrMsg;
|
||||||
@@ -728,7 +825,7 @@ int sqlite3VtabCommit(sqlite3 *db){
|
|||||||
** If the xBegin call is successful, place the sqlite3_vtab pointer
|
** If the xBegin call is successful, place the sqlite3_vtab pointer
|
||||||
** in the sqlite3.aVTrans array.
|
** in the sqlite3.aVTrans array.
|
||||||
*/
|
*/
|
||||||
int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
|
int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
const sqlite3_module *pModule;
|
const sqlite3_module *pModule;
|
||||||
|
|
||||||
@@ -740,10 +837,10 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
|
|||||||
if( sqlite3VtabInSync(db) ){
|
if( sqlite3VtabInSync(db) ){
|
||||||
return SQLITE_LOCKED;
|
return SQLITE_LOCKED;
|
||||||
}
|
}
|
||||||
if( !pVtab ){
|
if( !pVTab ){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
pModule = pVtab->pModule;
|
pModule = pVTab->pVtab->pModule;
|
||||||
|
|
||||||
if( pModule->xBegin ){
|
if( pModule->xBegin ){
|
||||||
int i;
|
int i;
|
||||||
@@ -751,15 +848,15 @@ int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){
|
|||||||
|
|
||||||
/* If pVtab is already in the aVTrans array, return early */
|
/* If pVtab is already in the aVTrans array, return early */
|
||||||
for(i=0; i<db->nVTrans; i++){
|
for(i=0; i<db->nVTrans; i++){
|
||||||
if( db->aVTrans[i]==pVtab ){
|
if( db->aVTrans[i]==pVTab ){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke the xBegin method */
|
/* Invoke the xBegin method */
|
||||||
rc = pModule->xBegin(pVtab);
|
rc = pModule->xBegin(pVTab->pVtab);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = addToVTrans(db, pVtab);
|
rc = addToVTrans(db, pVTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
@@ -801,7 +898,7 @@ FuncDef *sqlite3VtabOverloadFunction(
|
|||||||
pTab = pExpr->pTab;
|
pTab = pExpr->pTab;
|
||||||
if( NEVER(pTab==0) ) return pDef;
|
if( NEVER(pTab==0) ) return pDef;
|
||||||
if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
|
if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
|
||||||
pVtab = pTab->pVtab;
|
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
|
||||||
assert( pVtab!=0 );
|
assert( pVtab!=0 );
|
||||||
assert( pVtab->pModule!=0 );
|
assert( pVtab->pModule!=0 );
|
||||||
pMod = (sqlite3_module *)pVtab->pModule;
|
pMod = (sqlite3_module *)pVtab->pModule;
|
||||||
|
12
src/where.c
12
src/where.c
@@ -16,7 +16,7 @@
|
|||||||
** so is applicable. Because this module is responsible for selecting
|
** so is applicable. Because this module is responsible for selecting
|
||||||
** indices, you might also think of this module as the "query optimizer".
|
** indices, you might also think of this module as the "query optimizer".
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.408 2009/06/16 14:15:22 shane Exp $
|
** $Id: where.c,v 1.409 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@@ -1726,7 +1726,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
|||||||
** that this is required.
|
** that this is required.
|
||||||
*/
|
*/
|
||||||
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||||
sqlite3_vtab *pVtab = pTab->pVtab;
|
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1823,7 +1823,7 @@ static void bestVirtualIndex(
|
|||||||
** sqlite3ViewGetColumnNames() would have picked up the error.
|
** sqlite3ViewGetColumnNames() would have picked up the error.
|
||||||
*/
|
*/
|
||||||
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
|
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
|
||||||
assert( pTab->pVtab );
|
assert( sqlite3GetVTable(pParse->db, pTab) );
|
||||||
|
|
||||||
/* Set the aConstraint[].usable fields and initialize all
|
/* Set the aConstraint[].usable fields and initialize all
|
||||||
** output variables to zero.
|
** output variables to zero.
|
||||||
@@ -3404,13 +3404,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||||
pTab = pTabItem->pTab;
|
pTab = pTabItem->pTab;
|
||||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||||
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
|
||||||
|
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
|
||||||
int iCur = pTabItem->iCursor;
|
int iCur = pTabItem->iCursor;
|
||||||
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0,
|
sqlite3VdbeAddOp4(v, OP_VOpen, iCur, 0, 0, pVTab, P4_VTAB);
|
||||||
(const char*)pTab->pVtab, P4_VTAB);
|
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
|
if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
# This file tests interactions between the virtual table and
|
# This file tests interactions between the virtual table and
|
||||||
# shared-schema functionality.
|
# shared-schema functionality.
|
||||||
#
|
#
|
||||||
# $Id: vtab_shared.test,v 1.2 2008/03/19 13:03:34 drh Exp $
|
# $Id: vtab_shared.test,v 1.3 2009/07/24 17:58:53 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -23,39 +23,207 @@ ifcapable !vtab||!shared_cache {
|
|||||||
|
|
||||||
db close
|
db close
|
||||||
sqlite3_enable_shared_cache 1
|
sqlite3_enable_shared_cache 1
|
||||||
sqlite3 db test.db
|
sqlite3 db test.db
|
||||||
|
sqlite3 db2 test.db
|
||||||
do_test vtab_shared-1.0 {
|
|
||||||
register_echo_module [sqlite3_connection_pointer db]
|
|
||||||
catchsql {
|
|
||||||
CREATE TABLE t0(a, b, c);
|
|
||||||
CREATE VIRTUAL TABLE t1 USING echo(t0);
|
|
||||||
}
|
|
||||||
} {1 {Cannot use virtual tables in shared-cache mode}}
|
|
||||||
|
|
||||||
db close
|
|
||||||
sqlite3_enable_shared_cache 0
|
|
||||||
sqlite3 db test.db
|
|
||||||
|
|
||||||
do_test vtab_shared-1.1 {
|
do_test vtab_shared-1.1 {
|
||||||
register_echo_module [sqlite3_connection_pointer db]
|
register_echo_module [sqlite3_connection_pointer db]
|
||||||
catchsql {
|
execsql {
|
||||||
|
CREATE TABLE t0(a, b, c);
|
||||||
|
INSERT INTO t0 VALUES(1, 2, 3);
|
||||||
CREATE VIRTUAL TABLE t1 USING echo(t0);
|
CREATE VIRTUAL TABLE t1 USING echo(t0);
|
||||||
}
|
}
|
||||||
} {0 {}}
|
} {}
|
||||||
|
|
||||||
db close
|
|
||||||
sqlite3_enable_shared_cache 1
|
|
||||||
sqlite3 db test.db
|
|
||||||
|
|
||||||
do_test vtab_shared-1.2 {
|
do_test vtab_shared-1.2 {
|
||||||
register_echo_module [sqlite3_connection_pointer db]
|
execsql { SELECT * FROM t1 } db
|
||||||
catchsql {
|
} {1 2 3}
|
||||||
|
|
||||||
|
# Fails because the 'echo' module has not been registered with connection db2
|
||||||
|
do_test vtab_shared-1.3 {
|
||||||
|
catchsql { SELECT * FROM t1 } db2
|
||||||
|
} {1 {no such module: echo}}
|
||||||
|
|
||||||
|
do_test vtab_shared-1.4 {
|
||||||
|
execsql { SELECT * FROM t0 } db2
|
||||||
|
} {1 2 3}
|
||||||
|
|
||||||
|
do_test vtab_shared-1.5 {
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql { SELECT * FROM t1 } db
|
||||||
|
} {1 2 3}
|
||||||
|
|
||||||
|
# Works after the module is registered with db2
|
||||||
|
do_test vtab_shared-1.6 {
|
||||||
|
execsql { SELECT * FROM t1 } db2
|
||||||
|
} {1 2 3}
|
||||||
|
|
||||||
|
# Set a write-lock on table t0 using connection [db]. Then try to read from
|
||||||
|
# virtual table t1 using [db2]. That this returns an SQLITE_LOCKED error
|
||||||
|
# shows that the correct sqlite3_vtab is being used.
|
||||||
|
#
|
||||||
|
do_test vtab_shared-1.8.1 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(4, 5, 6);
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
}
|
}
|
||||||
} [list 1 \
|
} {1 2 3 4 5 6}
|
||||||
{malformed database schema (t1) - Cannot use virtual tables in shared-cache mode}]
|
do_test vtab_shared-1.8.2 {
|
||||||
|
catchsql { SELECT * FROM t1 } db2
|
||||||
|
} {1 {database table is locked}}
|
||||||
|
do_test vtab_shared-1.8.3 {
|
||||||
|
catchsql { SELECT * FROM t0 } db2
|
||||||
|
} {1 {database table is locked: t0}}
|
||||||
|
do_test vtab_shared-1.8.4 {
|
||||||
|
execsql { SELECT * FROM t0 } db
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
do_test vtab_shared-1.8.5 {
|
||||||
|
execsql { COMMIT } db
|
||||||
|
execsql { SELECT * FROM t1 } db2
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
|
||||||
|
# While a SELECT is active on virtual table t1 via connection [db], close
|
||||||
|
# [db2]. This causes the schema to be reset internally. Verify that this
|
||||||
|
# does not cause a problem.
|
||||||
|
#
|
||||||
|
foreach {iTest dbSelect dbClose} {
|
||||||
|
1 db db2
|
||||||
|
2 db db2
|
||||||
|
3 db2 db
|
||||||
|
} {
|
||||||
|
do_test vtab_shared-1.9.$iTest {
|
||||||
|
set res [list]
|
||||||
|
$dbSelect eval { SELECT * FROM t1 } {
|
||||||
|
if {$a == 1} {$dbClose close}
|
||||||
|
lappend res $a $b $c
|
||||||
|
}
|
||||||
|
sqlite3 $dbClose test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer $dbClose]
|
||||||
|
set res
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure that it is not possible for one connection to DROP a virtual
|
||||||
|
# table while a second connection is reading from the database.
|
||||||
|
#
|
||||||
|
do_test vtab_shared-1.10 {
|
||||||
|
db eval { SELECT * FROM t1 } {
|
||||||
|
set error [catchsql { DROP TABLE t1 } db2]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
set error
|
||||||
|
} {1 {database table is locked: sqlite_master}}
|
||||||
|
|
||||||
|
do_test vtab_shared-1.11 {
|
||||||
|
breakpoint
|
||||||
|
execsql {
|
||||||
|
CREATE VIRTUAL TABLE t2 USING echo(t0);
|
||||||
|
CREATE VIRTUAL TABLE t3 USING echo(t0);
|
||||||
|
}
|
||||||
|
execsql { SELECT * FROM t3 } db2
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
|
||||||
|
do_test vtab_shared-1.12.1 {
|
||||||
|
db close
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM t1 UNION ALL
|
||||||
|
SELECT * FROM t2 UNION ALL
|
||||||
|
SELECT * FROM t3
|
||||||
|
} db2
|
||||||
|
} {1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6}
|
||||||
|
do_test vtab_shared-1.12.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db]
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM t1 UNION ALL
|
||||||
|
SELECT * FROM t2 UNION ALL
|
||||||
|
SELECT * FROM t3
|
||||||
|
} db
|
||||||
|
} {1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6}
|
||||||
|
|
||||||
|
# Try a rename or two.
|
||||||
|
#
|
||||||
|
do_test vtab_shared-1.13.1 {
|
||||||
|
execsql { ALTER TABLE t1 RENAME TO t4 }
|
||||||
|
execsql { SELECT * FROM t4 } db
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
do_test vtab_shared-1.13.2 {
|
||||||
|
execsql { SELECT * FROM t4 } db2
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
do_test vtab_shared-1.13.3 {
|
||||||
|
execsql { ALTER TABLE t2 RENAME TO t5 }
|
||||||
|
execsql { SELECT * FROM t4 } db2
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
|
||||||
|
# Try an UPDATE/INSERT/DELETE on a shared vtab as the first statement after a
|
||||||
|
# schema is loaded.
|
||||||
|
do_test vtab_shared_1.14.1 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql { SELECT * FROM t3 }
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
do_test vtab_shared_1.14.2 {
|
||||||
|
execsql {
|
||||||
|
UPDATE t3 SET c = 'six' WHERE c = 6;
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2
|
||||||
|
} {1 2 3 4 5 six}
|
||||||
|
do_test vtab_shared_1.14.3 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql { SELECT * FROM t3 }
|
||||||
|
} {1 2 3 4 5 six}
|
||||||
|
do_test vtab_shared_1.14.4 {
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t3 WHERE c = 'six';
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2
|
||||||
|
} {1 2 3}
|
||||||
|
do_test vtab_shared_1.14.5 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql { SELECT * FROM t3 }
|
||||||
|
} {1 2 3}
|
||||||
|
do_test vtab_shared_1.14.6 {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t3 VALUES(4, 5, 6);
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
|
||||||
|
do_test vtab_shared_1.15.1 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql {
|
||||||
|
UPDATE t3 SET c = 'six' WHERE c = 6;
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2
|
||||||
|
} {1 2 3 4 5 six}
|
||||||
|
do_test vtab_shared_1.15.2 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql {
|
||||||
|
DELETE FROM t3 WHERE c = 'six';
|
||||||
|
SELECT * FROM t3;
|
||||||
|
} db2
|
||||||
|
} {1 2 3}
|
||||||
|
do_test vtab_shared_1.15.3 {
|
||||||
|
db2 close
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
register_echo_module [sqlite3_connection_pointer db2]
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t3 VALUES(4, 5, 6);
|
||||||
|
SELECT * FROM t3;
|
||||||
|
}
|
||||||
|
} {1 2 3 4 5 6}
|
||||||
|
|
||||||
db close
|
db close
|
||||||
|
db2 close
|
||||||
sqlite3_enable_shared_cache 0
|
sqlite3_enable_shared_cache 0
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user