Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfd227aee2 | |||
| d916481b23 | |||
| f414af4578 | |||
| eb4b471f87 | |||
| d7986f29cb | |||
| 74f6123d10 | |||
| 067dbab396 | |||
| 4d1b68f8b2 | |||
| ec04dad11a |
+4
-1
@@ -110,7 +110,10 @@ static int icuOpen(
|
||||
|
||||
*ppCursor = 0;
|
||||
|
||||
if( nInput<0 ){
|
||||
if( zInput==0 ){
|
||||
nInput = 0;
|
||||
zInput = "";
|
||||
}else if( nInput<0 ){
|
||||
nInput = strlen(zInput);
|
||||
}
|
||||
nChar = nInput+1;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\s8-byte\salignment\sproblem\sthat\scauses\sa\sSIGBUS\son\sSparc.
|
||||
D 2011-11-14T02:53:54.950
|
||||
C Cherrypick\s[79ef8e3c77]\s(Apply\sthe\ssame\srestrictions\son\sconstant\srefactoring\sto\sstatements\swithin\sa\strigger\sprogram\sas\stop-level\sstatements).
|
||||
D 2012-12-06T20:27:49.877
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -70,7 +70,7 @@ F ext/fts3/fts3_aux.c 0ebfa7b86cf8ff6a0861605fcc63b83ec1b70691
|
||||
F ext/fts3/fts3_expr.c f5df26bddf46a5916b2a5f80c4027996e92b7b15
|
||||
F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
|
||||
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
|
||||
F ext/fts3/fts3_icu.c 6c8f395cdf9e1e3afa7fadb7e523dbbf381c6dfa
|
||||
F ext/fts3/fts3_icu.c 62ec177c55f6a5c6e994dd3e5fd3194b4045c347
|
||||
F ext/fts3/fts3_porter.c 8d946908f4812c005d3d33fcbe78418b1f4eb70c
|
||||
F ext/fts3/fts3_snippet.c 1f9ee6a8e0e242649645968dcec4deb253d86c2a
|
||||
F ext/fts3/fts3_term.c a5457992723455a58804cb75c8cbd8978db5c2ef
|
||||
@@ -118,9 +118,9 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
|
||||
F src/alter.c ecf329684fcf1af4ae27d3368c30837479dbea71
|
||||
F src/analyze.c 5a1db16a651ce6310c8b046b2cbb736e030e14b9
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/attach.c 48c5736f89a2256237d8eef5da8c28eb0c81edab
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 4368158da74d4711888e03264105c5c527d76caf
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
@@ -128,13 +128,13 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 32199e2d939233ade25340eaba450f818b37c079
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
|
||||
F src/build.c 8915bb6d72ead998f94c2756ea8d143c77709b70
|
||||
F src/build.c f354512133f3c3403df55d00602b9179249858ab
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c ff68e5ef23aee08c0ff528f699a19397ed8bbed8
|
||||
F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8
|
||||
F src/delete.c e3a945da4aecffdb0fc9226da004f7273acecdcb
|
||||
F src/expr.c 96d029a9b7b5c012cc00ce11c38215fb7d13488b
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 657212460bf5cfd3ae607d12ea62092844c227b5
|
||||
F src/func.c 6261ce00aad9c63cd5b4219249b05683979060e9
|
||||
@@ -142,7 +142,7 @@ F src/global.c e230227de13601714b29f9363028514aada5ae2f
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c ca18783512323f74aaf4ee74b46ffd75ec80d031
|
||||
F src/insert.c abe16e63ef0865467e958fc28994eadc2849e169
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 0ee69fca0be54cd93939df98d2aca4ca46f44416
|
||||
@@ -166,9 +166,9 @@ F src/os.c 5d9b02782ed36345348d6fe21d7762ed3a9cfd2a
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
|
||||
F src/os_unix.c ddda0b1c5ae536669634d7bff31b3f8f4d654866
|
||||
F src/os_unix.c 97c346f849b0aeb8f1556141ee1875db5f1f6357
|
||||
F src/os_win.c 49d418916428a59d773f39993db0ecde56ab4c37
|
||||
F src/pager.c ad62daa0c21e27ae332b3ceb4f579a2a97046ddc
|
||||
F src/pager.c db33d4bf1e3e019c34c220971cc6c3aa07c30f54
|
||||
F src/pager.h 9f81b08efb06db4ba8be69446e10b005c351373d
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 49e718c095810c6b3334e3a6d89970aceaddefce
|
||||
@@ -180,11 +180,11 @@ F src/printf.c 03104cbff6959ff45df69dc9060ba6212f60a869
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6
|
||||
F src/select.c 3d4543b9611030df49eca1618bde8bd8468bf3b3
|
||||
F src/shell.c f0ab793261ab045a0b8c47fa2707e8a894d2898f
|
||||
F src/sqlite.h.in ff950aef7b378963c67add42dda5d446a0b7330e
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h c74457cd2c4bd77683bac76e698bf2ec2d3e13f9
|
||||
F src/sqliteInt.h d660a5ad543d775f28a46cf9510b5cb86e8097d2
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@@ -234,25 +234,25 @@ F src/test_vfstrace.c 0b884e06094a746da729119a2cabdc7aa790063d
|
||||
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c c819d9f72168a035d545a5bdafe9b085b20df705
|
||||
F src/trigger.c 1cfb80e2290ef66ea89cb4e821caae65a02c0d56
|
||||
F src/update.c 25e046a8f69d5e557aabde2000487b8545509d8d
|
||||
F src/trigger.c 84f90c64d7118ad2be370063dc3a660001bb02ee
|
||||
F src/update.c d3076782c887c10e882996550345da9c4c9f9dea
|
||||
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
|
||||
F src/util.c df83983bd57057df4951516880066b42b7055269
|
||||
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
|
||||
F src/vdbe.c 326994a64a9a08853122200dc9f62cb96b8f0831
|
||||
F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
|
||||
F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176
|
||||
F src/vdbe.c fed44fdc7c34838d8c6a6a89a7e124944846f66c
|
||||
F src/vdbe.h 18f581cac1f4339ec3299f3e0cc6e11aec654cdb
|
||||
F src/vdbeInt.h 23a9506c9ab31e7823d7257d1828d2d7843443a0
|
||||
F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546
|
||||
F src/vdbeaux.c a950e34449a508d48d90475acc287943a4094f3a
|
||||
F src/vdbeaux.c 15b1ef21b59c308812e49b33b1b42516fdc48817
|
||||
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
|
||||
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
|
||||
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
|
||||
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
|
||||
F src/vtab.c f36d8f8386e59c225f9c458ec45a3c20ff8efe78
|
||||
F src/wal.c 9658df8d404b82e6b2d40fd05944463214e2d935
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 7c85f4c93058e27100d404f0777aaeb0d1b296ae
|
||||
F src/where.c 13e6e3e15bd2b2991e73027cd23e584bf7a629ad
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@@ -472,7 +472,7 @@ F test/fts3corrupt.test 7b0f91780ca36118d73324ec803187208ad33b32
|
||||
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
|
||||
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
|
||||
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
|
||||
F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac
|
||||
F test/fts3defer.test 6c2707be1b05b9790ba8ff91d3391d5fb425269e
|
||||
F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81
|
||||
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
|
||||
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
@@ -735,6 +735,7 @@ F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f
|
||||
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
|
||||
F test/tkt-78e04e52ea.test ab52f0c1e2de6e46c910f4cc16b086bba05952b7
|
||||
F test/tkt-7bbfb7d442.test 8e7658f77d1ccea9d88dc9e255d3ed7fb68f8bdf
|
||||
F test/tkt-80ba201079.test a09684db1a0bd55b8838f606adccee456a51ddbf
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
|
||||
@@ -845,7 +846,7 @@ F test/trace2.test 962175290996d5f06dc4402ca218bbfc7df4cb20
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
|
||||
F test/trigger1.test 38c657eaf9907344c9e0bcb16af94a452c6babde
|
||||
F test/trigger1.test c3e4093e57f6c962ca8e54ca5274d10e7a4e706a
|
||||
F test/trigger2.test 834187beafd1db383af0c659cfa49b0576832816
|
||||
F test/trigger3.test d2c60d8be271c355d61727411e753181e877230a
|
||||
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
|
||||
@@ -856,7 +857,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test e0aaba16d3547193d36bbd82a1b0ed75e9c88d40
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 4d4bdaf0230c206b50d350330107ef9802bc2d4f
|
||||
F test/triggerC.test c9e59c1c8834ef8024045202a2f64816e917c07a
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
@@ -974,10 +975,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
P c7c6050ef060877ebe77b41d959e9df13f8c9b5e
|
||||
R ff6342b74061a33cbd4fa1292ca6bba4
|
||||
T *branch * branch-3.7.9
|
||||
T *sym-branch-3.7.9 *
|
||||
T -sym-trunk *
|
||||
U drh
|
||||
Z d03af58daca88e6314e5ea39548757b9
|
||||
P 0d7b5d455cee06aac4a5b331f26aa5da6963d97f
|
||||
R 1321c1938d7d3f11b7481c95ce141586
|
||||
U dan
|
||||
Z 4d8a6a6b21f3fade47676f63c6713742
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
54cc11981127b52145e39f551d958580b1d45169
|
||||
34aafb743627e469681d9d3be4f831399418cc17
|
||||
+2
-2
@@ -414,7 +414,7 @@ void sqlite3AlterRenameTable(
|
||||
assert( pSrc->nSrc==1 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
||||
|
||||
pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||
if( !pTab ) goto exit_rename_table;
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
@@ -757,7 +757,7 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
assert( pParse->pNewTable==0 );
|
||||
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
||||
if( db->mallocFailed ) goto exit_begin_add_column;
|
||||
pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
||||
if( !pTab ) goto exit_begin_add_column;
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
|
||||
+5
-3
@@ -434,6 +434,7 @@ int sqlite3FixInit(
|
||||
assert( db->nDb>iDb );
|
||||
pFix->pParse = pParse;
|
||||
pFix->zDb = db->aDb[iDb].zName;
|
||||
pFix->pSchema = db->aDb[iDb].pSchema;
|
||||
pFix->zType = zType;
|
||||
pFix->pName = pName;
|
||||
return 1;
|
||||
@@ -464,14 +465,15 @@ int sqlite3FixSrcList(
|
||||
if( NEVER(pList==0) ) return 0;
|
||||
zDb = pFix->zDb;
|
||||
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
||||
if( pItem->zDatabase==0 ){
|
||||
pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
|
||||
}else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
|
||||
if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
|
||||
sqlite3ErrorMsg(pFix->pParse,
|
||||
"%s %T cannot reference objects in database %s",
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
sqlite3_free(pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
||||
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
||||
|
||||
+38
-5
@@ -127,6 +127,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pParse->pToplevel==0 );
|
||||
db = pParse->db;
|
||||
if( db->mallocFailed ) return;
|
||||
if( pParse->nested ) return;
|
||||
@@ -319,6 +320,31 @@ Table *sqlite3LocateTable(
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate the table identified by *p.
|
||||
**
|
||||
** This is a wrapper around sqlite3LocateTable(). The difference between
|
||||
** sqlite3LocateTable() and this function is that this function restricts
|
||||
** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
|
||||
** non-NULL if it is part of a view or trigger program definition. See
|
||||
** sqlite3FixSrcList() for details.
|
||||
*/
|
||||
Table *sqlite3LocateTableItem(
|
||||
Parse *pParse,
|
||||
int isView,
|
||||
struct SrcList_item *p
|
||||
){
|
||||
const char *zDb;
|
||||
assert( p->pSchema==0 || p->zDatabase==0 );
|
||||
if( p->pSchema ){
|
||||
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
|
||||
zDb = pParse->db->aDb[iDb].zName;
|
||||
}else{
|
||||
zDb = p->zDatabase;
|
||||
}
|
||||
return sqlite3LocateTable(pParse, isView, p->zName, zDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** Locate the in-memory structure that describes
|
||||
** a particular index given the name of that index
|
||||
@@ -2090,8 +2116,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
assert( pParse->nErr==0 );
|
||||
assert( pName->nSrc==1 );
|
||||
if( noErr ) db->suppressErr++;
|
||||
pTab = sqlite3LocateTable(pParse, isView,
|
||||
pName->a[0].zName, pName->a[0].zDatabase);
|
||||
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
|
||||
if( noErr ) db->suppressErr--;
|
||||
|
||||
if( pTab==0 ){
|
||||
@@ -2533,8 +2558,7 @@ Index *sqlite3CreateIndex(
|
||||
** sqlite3FixSrcList can never fail. */
|
||||
assert(0);
|
||||
}
|
||||
pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
|
||||
pTblName->a[0].zDatabase);
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
|
||||
if( !pTab || db->mallocFailed ) goto exit_create_index;
|
||||
assert( db->aDb[iDb].pSchema==pTab->pSchema );
|
||||
}else{
|
||||
@@ -2740,7 +2764,7 @@ Index *sqlite3CreateIndex(
|
||||
}else{
|
||||
zColl = pTab->aCol[j].zColl;
|
||||
if( !zColl ){
|
||||
zColl = db->pDfltColl->zName;
|
||||
zColl = "BINARY";
|
||||
}
|
||||
}
|
||||
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
@@ -3549,6 +3573,15 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pToplevel!=pParse ){
|
||||
/* This branch is taken if a trigger is currently being coded. In this
|
||||
** case, set cookieGoto to a non-zero value to show that this function
|
||||
** has been called. This is used by the sqlite3ExprCodeConstants()
|
||||
** function. */
|
||||
pParse->cookieGoto = -1;
|
||||
}
|
||||
#endif
|
||||
if( pToplevel->cookieGoto==0 ){
|
||||
Vdbe *v = sqlite3GetVdbe(pToplevel);
|
||||
if( v==0 ) return; /* This only happens if there was a prior error */
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
struct SrcList_item *pItem = pSrc->a;
|
||||
Table *pTab;
|
||||
assert( pItem && pSrc->nSrc==1 );
|
||||
pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
||||
sqlite3DeleteTable(pParse->db, pItem->pTab);
|
||||
pItem->pTab = pTab;
|
||||
if( pTab ){
|
||||
|
||||
+17
-8
@@ -897,6 +897,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
||||
struct SrcList_item *pNewItem = &pNew->a[i];
|
||||
struct SrcList_item *pOldItem = &p->a[i];
|
||||
Table *pTab;
|
||||
pNewItem->pSchema = pOldItem->pSchema;
|
||||
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
|
||||
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
||||
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
|
||||
@@ -1373,6 +1374,15 @@ static int isCandidateForInOpt(Select *p){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** Code an OP_Once instruction and allocate space for its flag. Return the
|
||||
** address of the new instruction.
|
||||
*/
|
||||
int sqlite3CodeOnce(Parse *pParse){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used by the implementation of the IN (...) operator.
|
||||
** It's job is to find or create a b-tree structure that may be used
|
||||
@@ -1433,6 +1443,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
||||
int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
|
||||
@@ -1443,7 +1454,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
int iCol; /* Index of column <column> */
|
||||
@@ -1468,10 +1478,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
*/
|
||||
assert(v);
|
||||
if( iCol<0 ){
|
||||
int iMem = ++pParse->nMem;
|
||||
int iAddr;
|
||||
|
||||
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
eType = IN_INDEX_ROWID;
|
||||
@@ -1497,12 +1506,11 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
|
||||
&& (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None))
|
||||
){
|
||||
int iMem = ++pParse->nMem;
|
||||
int iAddr;
|
||||
char *pKey;
|
||||
|
||||
pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx);
|
||||
iAddr = sqlite3VdbeAddOp1(v, OP_Once, iMem);
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
|
||||
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
|
||||
pKey,P4_KEYINFO_HANDOFF);
|
||||
@@ -1512,6 +1520,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
if( prNotFound && !pTab->aCol[iCol].notNull ){
|
||||
*prNotFound = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1527,6 +1536,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
eType = IN_INDEX_EPH;
|
||||
if( prNotFound ){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
testcase( pParse->nQueryLoop>(double)1 );
|
||||
pParse->nQueryLoop = (double)1;
|
||||
@@ -1599,9 +1609,8 @@ int sqlite3CodeSubselect(
|
||||
** If all of the above are false, then we can run this code just once
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){
|
||||
int mem = ++pParse->nMem;
|
||||
testAddr = sqlite3VdbeAddOp1(v, OP_Once, mem);
|
||||
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
|
||||
+5
-2
@@ -239,6 +239,7 @@ void sqlite3AutoincrementBegin(Parse *pParse){
|
||||
memId = p->regCtr;
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
|
||||
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9);
|
||||
@@ -1215,8 +1216,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
Expr *pDup = sqlite3ExprDup(pParse->db, pTab->pCheck, 0);
|
||||
pParse->ckBase = regData;
|
||||
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL);
|
||||
sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
|
||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||
if( onError==OE_Ignore ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
@@ -1224,6 +1226,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
|
||||
sqlite3HaltConstraint(pParse, onError, 0, 0);
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pDup);
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
@@ -1687,7 +1690,7 @@ static int xferOptimization(
|
||||
** we have to check the semantics.
|
||||
*/
|
||||
pItem = pSelect->pSrc->a;
|
||||
pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
|
||||
pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
|
||||
if( pSrc==0 ){
|
||||
return 0; /* FROM clause does not contain a real table */
|
||||
}
|
||||
|
||||
+93
-2
@@ -216,6 +216,10 @@ struct unixFile {
|
||||
const char *zPath; /* Name of the file */
|
||||
unixShm *pShm; /* Shared memory segment information */
|
||||
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
|
||||
#ifdef __QNXNTO__
|
||||
int sectorSize; /* Device sector size */
|
||||
int deviceCharacteristics; /* Precomputed device characteristics */
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
#endif
|
||||
@@ -3547,17 +3551,104 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
** a database and its journal file) that the sector size will be the
|
||||
** same for both.
|
||||
*/
|
||||
#ifndef __QNXNTO__
|
||||
static int unixSectorSize(sqlite3_file *NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following version of unixSectorSize() is optimized for QNX.
|
||||
*/
|
||||
#ifdef __QNXNTO__
|
||||
#include <sys/dcmd_blk.h>
|
||||
#include <sys/statvfs.h>
|
||||
static int unixSectorSize(sqlite3_file *id){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
if( pFile->sectorSize == 0 ){
|
||||
struct statvfs fsInfo;
|
||||
|
||||
/* Set defaults for non-supported filesystems */
|
||||
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
pFile->deviceCharacteristics = 0;
|
||||
if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
|
||||
return pFile->sectorSize;
|
||||
}
|
||||
|
||||
if( !strcmp(fsInfo.f_basetype, "tmp") ) {
|
||||
pFile->sectorSize = fsInfo.f_bsize;
|
||||
pFile->deviceCharacteristics =
|
||||
SQLITE_IOCAP_ATOMIC4K | /* All ram filesystem writes are atomic */
|
||||
SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
|
||||
** the write succeeds */
|
||||
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
|
||||
** so it is ordered */
|
||||
0;
|
||||
}else if( strstr(fsInfo.f_basetype, "etfs") ){
|
||||
pFile->sectorSize = fsInfo.f_bsize;
|
||||
pFile->deviceCharacteristics =
|
||||
/* etfs cluster size writes are atomic */
|
||||
(pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) |
|
||||
SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
|
||||
** the write succeeds */
|
||||
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
|
||||
** so it is ordered */
|
||||
0;
|
||||
}else if( !strcmp(fsInfo.f_basetype, "qnx6") ){
|
||||
pFile->sectorSize = fsInfo.f_bsize;
|
||||
pFile->deviceCharacteristics =
|
||||
SQLITE_IOCAP_ATOMIC | /* All filesystem writes are atomic */
|
||||
SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
|
||||
** the write succeeds */
|
||||
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
|
||||
** so it is ordered */
|
||||
0;
|
||||
}else if( !strcmp(fsInfo.f_basetype, "qnx4") ){
|
||||
pFile->sectorSize = fsInfo.f_bsize;
|
||||
pFile->deviceCharacteristics =
|
||||
/* full bitset of atomics from max sector size and smaller */
|
||||
((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
|
||||
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
|
||||
** so it is ordered */
|
||||
0;
|
||||
}else if( strstr(fsInfo.f_basetype, "dos") ){
|
||||
pFile->sectorSize = fsInfo.f_bsize;
|
||||
pFile->deviceCharacteristics =
|
||||
/* full bitset of atomics from max sector size and smaller */
|
||||
((pFile->sectorSize / 512 * SQLITE_IOCAP_ATOMIC512) << 1) - 2 |
|
||||
SQLITE_IOCAP_SEQUENTIAL | /* The ram filesystem has no write behind
|
||||
** so it is ordered */
|
||||
0;
|
||||
}else{
|
||||
pFile->deviceCharacteristics =
|
||||
SQLITE_IOCAP_ATOMIC512 | /* blocks are atomic */
|
||||
SQLITE_IOCAP_SAFE_APPEND | /* growing the file does not occur until
|
||||
** the write succeeds */
|
||||
0;
|
||||
}
|
||||
}
|
||||
/* Last chance verification. If the sector size isn't a multiple of 512
|
||||
** then it isn't valid.*/
|
||||
if( pFile->sectorSize % 512 != 0 ){
|
||||
pFile->deviceCharacteristics = 0;
|
||||
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
return pFile->sectorSize;
|
||||
}
|
||||
#endif /* __QNXNTO__ */
|
||||
|
||||
/*
|
||||
** Return the device characteristics for the file. This is always 0 for unix.
|
||||
*/
|
||||
static int unixDeviceCharacteristics(sqlite3_file *NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
static int unixDeviceCharacteristics(sqlite3_file *id){
|
||||
#ifdef __QNXNTO__
|
||||
unixFile *p = (unixFile*)id;
|
||||
if( p->sectorSize==0 ) unixSectorSize(id);
|
||||
return p->deviceCharacteristics;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
+9
-7
@@ -6660,6 +6660,15 @@ sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
|
||||
return &pPager->pBackup;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_VACUUM
|
||||
/*
|
||||
** Unless this is an in-memory or temporary database, clear the pager cache.
|
||||
*/
|
||||
void sqlite3PagerClearCache(Pager *pPager){
|
||||
if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** This function is called when the user invokes "PRAGMA wal_checkpoint",
|
||||
@@ -6836,13 +6845,6 @@ int sqlite3PagerCloseWal(Pager *pPager){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unless this is an in-memory or temporary database, clear the pager cache.
|
||||
*/
|
||||
void sqlite3PagerClearCache(Pager *pPager){
|
||||
if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/*
|
||||
** This function is called by the wal module when writing page content
|
||||
|
||||
+4
-5
@@ -3239,8 +3239,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}else{
|
||||
/* An ordinary table or view name in the FROM clause */
|
||||
assert( pFrom->pTab==0 );
|
||||
pFrom->pTab = pTab =
|
||||
sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
|
||||
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
pTab->nRef++;
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
|
||||
@@ -3845,12 +3844,11 @@ int sqlite3Select(
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
|
||||
if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
|
||||
if( pItem->isCorrelated==0 ){
|
||||
/* If the subquery is no correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
int regOnce = ++pParse->nMem;
|
||||
onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
|
||||
onceAddr = sqlite3CodeOnce(pParse);
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
@@ -4155,6 +4153,7 @@ int sqlite3Select(
|
||||
VdbeComment((v, "clear abort flag"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
||||
VdbeComment((v, "indicate accumulator empty"));
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
||||
|
||||
/* Begin a loop that will extract all source rows in GROUP BY order.
|
||||
** This might involve two separate loops with an OP_Sort in between, or
|
||||
|
||||
@@ -1861,6 +1861,7 @@ struct SrcList {
|
||||
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
|
||||
i16 nAlloc; /* Number of entries allocated in a[] below */
|
||||
struct SrcList_item {
|
||||
Schema *pSchema; /* Schema to which this item is fixed */
|
||||
char *zDatabase; /* Name of database holding this table */
|
||||
char *zName; /* Name of the table */
|
||||
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
||||
@@ -2218,6 +2219,7 @@ struct Parse {
|
||||
int nTab; /* Number of previously allocated VDBE cursors */
|
||||
int nMem; /* Number of memory cells used so far */
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nOnce; /* Number of OP_Once instructions so far */
|
||||
int ckBase; /* Base register of data during check constraints */
|
||||
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||
@@ -2412,6 +2414,7 @@ struct TriggerStep {
|
||||
typedef struct DbFixer DbFixer;
|
||||
struct DbFixer {
|
||||
Parse *pParse; /* The parsing context. Error messages written here */
|
||||
Schema *pSchema; /* Fix items to this schema */
|
||||
const char *zDb; /* Make sure all objects are contained in this database */
|
||||
const char *zType; /* Type of the container - used for error messages */
|
||||
const Token *pName; /* Name of the container - used for error messages */
|
||||
@@ -2706,6 +2709,7 @@ void sqlite3AddCollateType(Parse*, Token*);
|
||||
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||
int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
||||
sqlite3_vfs**,char**,char **);
|
||||
int sqlite3CodeOnce(Parse *);
|
||||
|
||||
Bitvec *sqlite3BitvecCreate(u32);
|
||||
int sqlite3BitvecTest(Bitvec*, u32);
|
||||
@@ -2790,6 +2794,7 @@ void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
|
||||
Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
|
||||
@@ -729,6 +729,15 @@ static int codeTriggerProgram(
|
||||
*/
|
||||
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
|
||||
|
||||
/* Clear the cookieGoto flag. When coding triggers, the cookieGoto
|
||||
** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
|
||||
** that it is not safe to refactor constants (this happens after the
|
||||
** start of the first loop in the SQL statement is coded - at that
|
||||
** point code may be conditionally executed, so it is no longer safe to
|
||||
** initialize constant register values). */
|
||||
assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
|
||||
pParse->cookieGoto = 0;
|
||||
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
sqlite3Update(pParse,
|
||||
@@ -904,6 +913,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
}
|
||||
pProgram->nMem = pSubParse->nMem;
|
||||
pProgram->nCsr = pSubParse->nTab;
|
||||
pProgram->nOnce = pSubParse->nOnce;
|
||||
pProgram->token = (void *)pTrigger;
|
||||
pPrg->aColmask[0] = pSubParse->oldmask;
|
||||
pPrg->aColmask[1] = pSubParse->newmask;
|
||||
|
||||
+6
-5
@@ -126,8 +126,8 @@ void sqlite3Update(
|
||||
int regRowCount = 0; /* A count of rows changed */
|
||||
int regOldRowid; /* The old rowid */
|
||||
int regNewRowid; /* The new rowid */
|
||||
int regNew;
|
||||
int regOld = 0;
|
||||
int regNew; /* Content of the NEW.* table in triggers */
|
||||
int regOld = 0; /* Content of OLD.* table in triggers */
|
||||
int regRowSet = 0; /* Rowset of rows to be updated */
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
@@ -276,6 +276,7 @@ void sqlite3Update(
|
||||
#endif
|
||||
|
||||
/* Allocate required registers. */
|
||||
regRowSet = ++pParse->nMem;
|
||||
regOldRowid = regNewRowid = ++pParse->nMem;
|
||||
if( pTrigger || hasFK ){
|
||||
regOld = pParse->nMem + 1;
|
||||
@@ -310,7 +311,7 @@ void sqlite3Update(
|
||||
|
||||
/* Begin the database scan
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
||||
pWInfo = sqlite3WhereBegin(
|
||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED
|
||||
);
|
||||
@@ -321,7 +322,6 @@ void sqlite3Update(
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
|
||||
if( !okOnePass ){
|
||||
regRowSet = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
||||
}
|
||||
|
||||
@@ -425,9 +425,10 @@ void sqlite3Update(
|
||||
newmask = sqlite3TriggerColmask(
|
||||
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
|
||||
);
|
||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( i==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
|
||||
/*sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);*/
|
||||
}else{
|
||||
j = aXRef[i];
|
||||
if( j>=0 ){
|
||||
|
||||
+42
-22
@@ -764,7 +764,8 @@ case OP_Goto: { /* jump */
|
||||
** Write the current address onto register P1
|
||||
** and then jump to address P2.
|
||||
*/
|
||||
case OP_Gosub: { /* jump, in1 */
|
||||
case OP_Gosub: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=p->nMem );
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
@@ -961,12 +962,25 @@ case OP_String: { /* out2-prerelease */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Null * P2 * * *
|
||||
/* Opcode: Null * P2 P3 * *
|
||||
**
|
||||
** Write a NULL into register P2.
|
||||
** Write a NULL into registers P2. If P3 greater than P2, then also write
|
||||
** NULL into register P3 and ever register in between P2 and P3. If P3
|
||||
** is less than P2 (typically P3 is zero) then only register P2 is
|
||||
** set to NULL
|
||||
*/
|
||||
case OP_Null: { /* out2-prerelease */
|
||||
int cnt;
|
||||
cnt = pOp->p3-pOp->p2;
|
||||
assert( pOp->p3<=p->nMem );
|
||||
pOut->flags = MEM_Null;
|
||||
while( cnt>0 ){
|
||||
pOut++;
|
||||
memAboutToChange(p, pOut);
|
||||
MemReleaseExt(pOut);
|
||||
pOut->flags = MEM_Null;
|
||||
cnt--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2023,27 +2037,33 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
|
||||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is a not null or zero. If
|
||||
** the value is NULL or zero, fall through and change the P1 register
|
||||
** to an integer 1.
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
**
|
||||
** When P1 is not used otherwise in a program, this opcode falls through
|
||||
** once and jumps on all subsequent invocations. It is the equivalent
|
||||
** of "OP_If P1 P2", followed by "OP_Integer 1 P1".
|
||||
** See also: JumpOnce
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
if( p->aOnceFlag[pOp->p1] ){
|
||||
pc = pOp->p2-1;
|
||||
}else{
|
||||
p->aOnceFlag[pOp->p1] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: If P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is true. The value
|
||||
** is considered true if it is numeric and non-zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
** in P1 is NULL then take the jump if P3 is non-zero.
|
||||
*/
|
||||
/* Opcode: IfNot P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is False. The value
|
||||
** is considered true if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is true.
|
||||
** is considered false if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is zero.
|
||||
*/
|
||||
case OP_Once: /* jump, in1 */
|
||||
case OP_If: /* jump, in1 */
|
||||
case OP_IfNot: { /* jump, in1 */
|
||||
int c;
|
||||
@@ -2060,12 +2080,6 @@ case OP_IfNot: { /* jump, in1 */
|
||||
}
|
||||
if( c ){
|
||||
pc = pOp->p2-1;
|
||||
}else if( pOp->opcode==OP_Once ){
|
||||
assert( (pIn1->flags & (MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))==0 );
|
||||
memAboutToChange(p, pIn1);
|
||||
pIn1->flags = MEM_Int;
|
||||
pIn1->u.i = 1;
|
||||
REGISTER_TRACE(pOp->p1, pIn1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5071,7 +5085,6 @@ case OP_Program: { /* jump */
|
||||
|
||||
pProgram = pOp->p4.pProgram;
|
||||
pRt = &aMem[pOp->p3];
|
||||
assert( memIsValid(pRt) );
|
||||
assert( pProgram->nOp>0 );
|
||||
|
||||
/* If the p5 flag is clear, then recursive invocation of triggers is
|
||||
@@ -5110,7 +5123,8 @@ case OP_Program: { /* jump */
|
||||
nMem = pProgram->nMem + pProgram->nCsr;
|
||||
nByte = ROUND8(sizeof(VdbeFrame))
|
||||
+ nMem * sizeof(Mem)
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *);
|
||||
+ pProgram->nCsr * sizeof(VdbeCursor *)
|
||||
+ pProgram->nOnce * sizeof(u8);
|
||||
pFrame = sqlite3DbMallocZero(db, nByte);
|
||||
if( !pFrame ){
|
||||
goto no_mem;
|
||||
@@ -5130,10 +5144,12 @@ case OP_Program: { /* jump */
|
||||
pFrame->aOp = p->aOp;
|
||||
pFrame->nOp = p->nOp;
|
||||
pFrame->token = pProgram->token;
|
||||
pFrame->aOnceFlag = p->aOnceFlag;
|
||||
pFrame->nOnceFlag = p->nOnceFlag;
|
||||
|
||||
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
|
||||
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
|
||||
pMem->flags = MEM_Null;
|
||||
pMem->flags = MEM_Invalid;
|
||||
pMem->db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -5155,7 +5171,11 @@ case OP_Program: { /* jump */
|
||||
p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
|
||||
p->aOp = aOp = pProgram->aOp;
|
||||
p->nOp = pProgram->nOp;
|
||||
p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
|
||||
p->nOnceFlag = pProgram->nOnce;
|
||||
p->nOp = pProgram->nOp;
|
||||
pc = -1;
|
||||
memset(p->aOnceFlag, 0, p->nOnceFlag);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ struct SubProgram {
|
||||
int nOp; /* Elements in aOp[] */
|
||||
int nMem; /* Number of memory cells required */
|
||||
int nCsr; /* Number of cursors required */
|
||||
int nOnce; /* Number of OP_Once instructions */
|
||||
void *token; /* id that may be used to recursive triggers */
|
||||
SubProgram *pNext; /* Next sub-program already visited */
|
||||
};
|
||||
|
||||
@@ -117,6 +117,8 @@ struct VdbeFrame {
|
||||
int nOp; /* Size of aOp array */
|
||||
Mem *aMem; /* Array of memory cells for parent frame */
|
||||
int nMem; /* Number of entries in aMem */
|
||||
u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
|
||||
int nOnceFlag; /* Number of entries in aOnceFlag */
|
||||
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
|
||||
u16 nCursor; /* Number of entries in apCsr */
|
||||
void *token; /* Copy of SubProgram.token */
|
||||
@@ -326,6 +328,8 @@ struct Vdbe {
|
||||
int nFrame; /* Number of frames in pFrame list */
|
||||
u32 expmask; /* Binding to these vars invalidates VM */
|
||||
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
|
||||
int nOnceFlag; /* Size of array aOnceFlag[] */
|
||||
u8 *aOnceFlag; /* Flags for OP_Once */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+15
-5
@@ -913,13 +913,14 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
}
|
||||
case P4_MEM: {
|
||||
Mem *pMem = pOp->p4.pMem;
|
||||
assert( (pMem->flags & MEM_Null)==0 );
|
||||
if( pMem->flags & MEM_Str ){
|
||||
zP4 = pMem->z;
|
||||
}else if( pMem->flags & MEM_Int ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i);
|
||||
}else if( pMem->flags & MEM_Real ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r);
|
||||
}else if( pMem->flags & MEM_Null ){
|
||||
sqlite3_snprintf(nTemp, zTemp, "NULL");
|
||||
}else{
|
||||
assert( pMem->flags & MEM_Blob );
|
||||
zP4 = "(blob)";
|
||||
@@ -1094,7 +1095,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
p->zMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Null;
|
||||
p->flags = MEM_Invalid;
|
||||
}
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
@@ -1469,6 +1470,7 @@ void sqlite3VdbeMakeReady(
|
||||
int nMem; /* Number of VM memory registers */
|
||||
int nCursor; /* Number of cursors required */
|
||||
int nArg; /* Number of arguments in subprograms */
|
||||
int nOnce; /* Number of OP_Once instructions */
|
||||
int n; /* Loop counter */
|
||||
u8 *zCsr; /* Memory available for allocation */
|
||||
u8 *zEnd; /* First byte past allocated memory */
|
||||
@@ -1484,6 +1486,7 @@ void sqlite3VdbeMakeReady(
|
||||
nMem = pParse->nMem;
|
||||
nCursor = pParse->nTab;
|
||||
nArg = pParse->nMaxArg;
|
||||
nOnce = pParse->nOnce;
|
||||
|
||||
/* For each cursor required, also allocate a memory cell. Memory
|
||||
** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
|
||||
@@ -1530,6 +1533,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->azVar = allocSpace(p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte);
|
||||
p->apCsr = allocSpace(p->apCsr, nCursor*sizeof(VdbeCursor*),
|
||||
&zCsr, zEnd, &nByte);
|
||||
p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte);
|
||||
if( nByte ){
|
||||
p->pFree = sqlite3DbMallocZero(db, nByte);
|
||||
}
|
||||
@@ -1538,6 +1542,7 @@ void sqlite3VdbeMakeReady(
|
||||
}while( nByte && !db->mallocFailed );
|
||||
|
||||
p->nCursor = (u16)nCursor;
|
||||
p->nOnceFlag = nOnce;
|
||||
if( p->aVar ){
|
||||
p->nVar = (ynVar)nVar;
|
||||
for(n=0; n<nVar; n++){
|
||||
@@ -1554,7 +1559,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Null;
|
||||
p->aMem[n].flags = MEM_Invalid;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
@@ -1596,6 +1601,8 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
*/
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
||||
Vdbe *v = pFrame->v;
|
||||
v->aOnceFlag = pFrame->aOnceFlag;
|
||||
v->nOnceFlag = pFrame->nOnceFlag;
|
||||
v->aOp = pFrame->aOp;
|
||||
v->nOp = pFrame->nOp;
|
||||
v->aMem = pFrame->aMem;
|
||||
@@ -1658,8 +1665,10 @@ static void Cleanup(Vdbe *p){
|
||||
/* Execute assert() statements to ensure that the Vdbe.apCsr[] and
|
||||
** Vdbe.aMem[] arrays have already been cleaned up. */
|
||||
int i;
|
||||
for(i=0; i<p->nCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 );
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem==0 || p->aMem[i].flags==MEM_Null );
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
@@ -2127,6 +2136,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
if( p->db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
|
||||
closeAllCursors(p);
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
return SQLITE_OK;
|
||||
|
||||
+8
-1
@@ -236,6 +236,7 @@ void sqlite3VtabClear(sqlite3 *db, Table *p){
|
||||
if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
|
||||
if( p->azModuleArg ){
|
||||
int i;
|
||||
assert( p->nModuleArg<2 || p->azModuleArg[1]==0 );
|
||||
for(i=0; i<p->nModuleArg; i++){
|
||||
sqlite3DbFree(db, p->azModuleArg[i]);
|
||||
}
|
||||
@@ -296,7 +297,7 @@ void sqlite3VtabBeginParse(
|
||||
pTable->tabFlags |= TF_Virtual;
|
||||
pTable->nModuleArg = 0;
|
||||
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
|
||||
addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
|
||||
addModuleArgument(db, pTable, 0);
|
||||
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
|
||||
pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
|
||||
|
||||
@@ -453,6 +454,7 @@ static int vtabCallConstructor(
|
||||
int nArg = pTab->nModuleArg;
|
||||
char *zErr = 0;
|
||||
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
|
||||
int iDb;
|
||||
|
||||
if( !zModuleName ){
|
||||
return SQLITE_NOMEM;
|
||||
@@ -466,6 +468,10 @@ static int vtabCallConstructor(
|
||||
pVTable->db = db;
|
||||
pVTable->pMod = pMod;
|
||||
|
||||
assert( pTab->azModuleArg[1]==0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
pTab->azModuleArg[1] = db->aDb[iDb].zName;
|
||||
|
||||
/* Invoke the virtual table constructor */
|
||||
assert( &db->pVtabCtx );
|
||||
assert( xConstruct );
|
||||
@@ -475,6 +481,7 @@ static int vtabCallConstructor(
|
||||
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
|
||||
db->pVtabCtx = 0;
|
||||
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
|
||||
pTab->azModuleArg[1] = 0;
|
||||
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( zErr==0 ){
|
||||
|
||||
+1
-3
@@ -2005,7 +2005,6 @@ static void constructAutomaticIndex(
|
||||
int nByte; /* Byte of memory needed for pIdx */
|
||||
Index *pIdx; /* Object describing the transient index */
|
||||
Vdbe *v; /* Prepared statement under construction */
|
||||
int regIsInit; /* Register set by initialization */
|
||||
int addrInit; /* Address of the initialization bypass jump */
|
||||
Table *pTable; /* The table being indexed */
|
||||
KeyInfo *pKeyinfo; /* Key information for the index */
|
||||
@@ -2022,8 +2021,7 @@ static void constructAutomaticIndex(
|
||||
** transient index on 2nd and subsequent iterations of the loop. */
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
regIsInit = ++pParse->nMem;
|
||||
addrInit = sqlite3VdbeAddOp1(v, OP_Once, regIsInit);
|
||||
addrInit = sqlite3CodeOnce(pParse);
|
||||
|
||||
/* Count the number of columns that will be added to the index
|
||||
** and used to match WHERE clause constraints */
|
||||
|
||||
@@ -489,5 +489,39 @@ do_execsql_test 4.2 {
|
||||
SELECT * FROM x2 WHERE x2 MATCH 'a b c d e f g h i j k l m n o p q r s';
|
||||
} {{a b c d e f g h i j k l m n o p q r s t u v w x y m}}
|
||||
|
||||
set tokenizers {1 simple}
|
||||
ifcapable icu { lappend tokenizers 2 {icu en_US} }
|
||||
foreach {tn tokenizer} $tokenizers {
|
||||
do_execsql_test 5.$tn.1 "
|
||||
CREATE VIRTUAL TABLE x3 USING FTS4(a, b, TOKENIZE $tokenizer)
|
||||
"
|
||||
do_execsql_test 5.$tn.2 {
|
||||
BEGIN;
|
||||
INSERT INTO x3 VALUES('b b b b b b b b b b b', 'b b b b b b b b b b b b b');
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 SELECT * FROM x3;
|
||||
INSERT INTO x3 VALUES('a b c', NULL);
|
||||
INSERT INTO x3 VALUES('a x c', NULL);
|
||||
COMMIT;
|
||||
|
||||
SELECT * FROM x3 WHERE x3 MATCH 'a b';
|
||||
} {{a b c} {}}
|
||||
|
||||
do_execsql_test 5.$tn.3 { DROP TABLE x3 }
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
# 2011 December 9
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
# This file implements tests to verify that ticket [7bbfb7d442] has been
|
||||
# fixed.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix tkt-7bbfb7d442
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
|
||||
CREATE TABLE t2(c, d);
|
||||
INSERT INTO t2 VALUES('one', 'I');
|
||||
INSERT INTO t2 VALUES('two', 'II');
|
||||
INSERT INTO t2 VALUES('three', 'III');
|
||||
|
||||
CREATE TABLE t3(t3_a PRIMARY KEY, t3_d);
|
||||
CREATE TRIGGER t3t AFTER INSERT ON t3 WHEN new.t3_d IS NULL BEGIN
|
||||
UPDATE t3 SET t3_d = (
|
||||
SELECT d FROM
|
||||
(SELECT * FROM t2 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10),
|
||||
(SELECT * FROM t1 WHERE (new.t3_a%2)=(rowid%2) LIMIT 10)
|
||||
WHERE a = new.t3_a AND b = c
|
||||
) WHERE t3_a = new.t3_a;
|
||||
END;
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
INSERT INTO t3(t3_a) VALUES(1);
|
||||
INSERT INTO t3(t3_a) VALUES(2);
|
||||
INSERT INTO t3(t3_a) VALUES(3);
|
||||
SELECT * FROM t3;
|
||||
} {1 I 2 II 3 III}
|
||||
|
||||
do_execsql_test 1.3 { DELETE FROM t3 }
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
INSERT INTO t3(t3_a) SELECT 1 UNION SELECT 2 UNION SELECT 3;
|
||||
SELECT * FROM t3;
|
||||
} {1 I 2 II 3 III}
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following test case - 2.* - is from the original bug report as
|
||||
# posted to the mailing list.
|
||||
#
|
||||
do_execsql_test 2.1 {
|
||||
CREATE TABLE InventoryControl (
|
||||
InventoryControlId INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
ControlDate DATE NOT NULL,
|
||||
ControlState INTEGER NOT NULL DEFAULT -1,
|
||||
DeliveredQty VARCHAR(30)
|
||||
);
|
||||
|
||||
CREATE TRIGGER TGR_InventoryControl_AfterInsert
|
||||
AFTER INSERT ON InventoryControl
|
||||
FOR EACH ROW WHEN NEW.ControlState=-1 BEGIN
|
||||
|
||||
INSERT OR REPLACE INTO InventoryControl(
|
||||
InventoryControlId,SKU,Variant,ControlDate,ControlState,DeliveredQty
|
||||
) SELECT
|
||||
T1.InventoryControlId AS InventoryControlId,
|
||||
T1.SKU AS SKU,
|
||||
T1.Variant AS Variant,
|
||||
T1.ControlDate AS ControlDate,
|
||||
1 AS ControlState,
|
||||
COALESCE(T2.DeliveredQty,0) AS DeliveredQty
|
||||
FROM (
|
||||
SELECT
|
||||
NEW.InventoryControlId AS InventoryControlId,
|
||||
II.SKU AS SKU,
|
||||
II.Variant AS Variant,
|
||||
COALESCE(LastClosedIC.ControlDate,NEW.ControlDate) AS ControlDate
|
||||
FROM
|
||||
InventoryItem II
|
||||
LEFT JOIN
|
||||
InventoryControl LastClosedIC
|
||||
ON LastClosedIC.InventoryControlId IN ( SELECT 99999 )
|
||||
WHERE
|
||||
II.SKU=NEW.SKU AND
|
||||
II.Variant=NEW.Variant
|
||||
) T1
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
TD.SKU AS SKU,
|
||||
TD.Variant AS Variant,
|
||||
10 AS DeliveredQty
|
||||
FROM
|
||||
TransactionDetail TD
|
||||
WHERE
|
||||
TD.SKU=NEW.SKU AND
|
||||
TD.Variant=NEW.Variant
|
||||
) T2
|
||||
ON T2.SKU=T1.SKU AND
|
||||
T2.Variant=T1.Variant;
|
||||
END;
|
||||
|
||||
CREATE TABLE InventoryItem (
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
DeptCode INTEGER NOT NULL,
|
||||
GroupCode INTEGER NOT NULL,
|
||||
ItemDescription VARCHAR(120) NOT NULL,
|
||||
PRIMARY KEY(SKU, Variant)
|
||||
);
|
||||
|
||||
INSERT INTO InventoryItem VALUES(220,0,1,170,'Scoth Tampon Recurer');
|
||||
INSERT INTO InventoryItem VALUES(31,0,1,110,'Fromage');
|
||||
|
||||
CREATE TABLE TransactionDetail (
|
||||
TransactionId INTEGER NOT NULL,
|
||||
SKU INTEGER NOT NULL,
|
||||
Variant INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(TransactionId, SKU, Variant)
|
||||
);
|
||||
INSERT INTO TransactionDetail(TransactionId, SKU, Variant) VALUES(44, 31, 0);
|
||||
|
||||
|
||||
INSERT INTO InventoryControl(SKU, Variant, ControlDate) SELECT
|
||||
II.SKU AS SKU, II.Variant AS Variant, '2011-08-30' AS ControlDate
|
||||
FROM InventoryItem II;
|
||||
}
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
SELECT SKU, DeliveredQty FROM InventoryControl WHERE SKU=31
|
||||
} {31 10}
|
||||
|
||||
do_execsql_test 2.3 {
|
||||
SELECT CASE WHEN DeliveredQty=10 THEN "TEST PASSED!" ELSE "TEST FAILED!" END
|
||||
FROM InventoryControl WHERE SKU=31;
|
||||
} {{TEST PASSED!}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+3
-3
@@ -210,7 +210,7 @@ do_test trigger1-1.12 {
|
||||
delete from t1 WHERE a=old.a+2;
|
||||
end;
|
||||
}
|
||||
} {1 {cannot create INSTEAD OF trigger on table: main.t1}}
|
||||
} {1 {cannot create INSTEAD OF trigger on table: t1}}
|
||||
|
||||
ifcapable view {
|
||||
# Ensure that we cannot create BEFORE triggers on views
|
||||
@@ -221,7 +221,7 @@ do_test trigger1-1.13 {
|
||||
delete from t1 WHERE a=old.a+2;
|
||||
end;
|
||||
}
|
||||
} {1 {cannot create BEFORE trigger on view: main.v1}}
|
||||
} {1 {cannot create BEFORE trigger on view: v1}}
|
||||
# Ensure that we cannot create AFTER triggers on views
|
||||
do_test trigger1-1.14 {
|
||||
catchsql {
|
||||
@@ -231,7 +231,7 @@ do_test trigger1-1.14 {
|
||||
delete from t1 WHERE a=old.a+2;
|
||||
end;
|
||||
}
|
||||
} {1 {cannot create AFTER trigger on view: main.v1}}
|
||||
} {1 {cannot create AFTER trigger on view: v1}}
|
||||
} ;# ifcapable view
|
||||
|
||||
# Check for memory leaks in the trigger parser
|
||||
|
||||
@@ -949,6 +949,48 @@ do_catchsql_test triggerC-13.2 {
|
||||
UPDATE t12 SET a=a+1, b=b+1;
|
||||
} {1 {too many levels of trigger recursion}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests seek to verify that constant values (i.e. literals)
|
||||
# are not factored out of loops within trigger programs. SQLite does
|
||||
# not factor constants out of loops within trigger programs as it may only
|
||||
# do so in code generated before the first table or index is opened. And
|
||||
# by the time a trigger program is coded, at least one table or index has
|
||||
# always been opened.
|
||||
#
|
||||
# At one point, due to a bug allowing constant factoring within triggers,
|
||||
# the following SQL would produce the wrong result.
|
||||
#
|
||||
set SQL {
|
||||
CREATE TABLE t1(a, b, c);
|
||||
CREATE INDEX i1 ON t1(a, c);
|
||||
CREATE INDEX i2 ON t1(b, c);
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
|
||||
CREATE TABLE t2(e, f);
|
||||
CREATE INDEX i3 ON t2(e);
|
||||
INSERT INTO t2 VALUES(1234567, 3);
|
||||
|
||||
CREATE TABLE empty(x);
|
||||
CREATE TABLE not_empty(x);
|
||||
INSERT INTO not_empty VALUES(2);
|
||||
|
||||
CREATE TABLE t4(x);
|
||||
CREATE TABLE t5(g, h, i);
|
||||
|
||||
CREATE TRIGGER trig BEFORE INSERT ON t4 BEGIN
|
||||
INSERT INTO t5 SELECT * FROM t1 WHERE
|
||||
(a IN (SELECT x FROM empty) OR b IN (SELECT x FROM not_empty))
|
||||
AND c IN (SELECT f FROM t2 WHERE e=1234567);
|
||||
END;
|
||||
|
||||
INSERT INTO t4 VALUES(0);
|
||||
SELECT * FROM t5;
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test triggerC-14.1 $SQL {1 2 3}
|
||||
reset_db
|
||||
optimization_control db factor-constants 0
|
||||
do_execsql_test triggerC-14.2 $SQL {1 2 3}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user