mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Add SQLITE_ENABLE_UPDATE_DELETE_LIMIT for views and WITHOUT ROWID tables.
FossilOrigin-Name: 584b88aaf89ab30cb51185396b7b50c6ecba286add023a26ab41d865b9c605ce
This commit is contained in:
26
manifest
26
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Disallow\sORDER\sBY\sand\sLIMIT\son\sUPDATE\sand\sDELETE\sof\sviews\sand\sWITHOUT\sROWID\ntables.\s\sThis\sis\sa\stemporary\sfix\sfor\sticket\s[d4beea1633f1b88f]\suntil\sa\sbetter\nsolution\scan\sbe\sfound.
|
C Add\sSQLITE_ENABLE_UPDATE_DELETE_LIMIT\sfor\sviews\sand\sWITHOUT\sROWID\stables.
|
||||||
D 2017-11-09T03:55:09.531
|
D 2017-11-09T19:53:06.815
|
||||||
F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2
|
F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b
|
F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b
|
||||||
@@ -422,7 +422,7 @@ F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
|
|||||||
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
|
||||||
F src/dbpage.c 432f46fb47c99ae1f0e2863fe595038a6f9d3b59f4a3dabe5f86ec2a88758fde
|
F src/dbpage.c 432f46fb47c99ae1f0e2863fe595038a6f9d3b59f4a3dabe5f86ec2a88758fde
|
||||||
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
|
||||||
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
|
F src/delete.c 001653cc4065ad83d47f4307c29572437f778f1fe249d482894e100275d27efd
|
||||||
F src/expr.c 0016b95aed1df47ebc0eb7415bd621841d72dbffd3bfb62210e50e71d83b4691
|
F src/expr.c 0016b95aed1df47ebc0eb7415bd621841d72dbffd3bfb62210e50e71d83b4691
|
||||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||||
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
|
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
|
||||||
@@ -459,7 +459,7 @@ F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
|
|||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
|
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
|
||||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||||
F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
|
F src/parse.y 5fbc16a4adf5da8ee22a1ef271e001fd6b766eebc3195b52ba2c30cecbbaf2d0
|
||||||
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
|
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
|
||||||
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
|
||||||
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
|
||||||
@@ -475,7 +475,7 @@ F src/shell.c.in 08cbffc31900359fea85896342a46147e9772c370d8a5079b7be26e3a1f50e8
|
|||||||
F src/sqlite.h.in 6d96f09aac30a030c7674a47659d8156263d2ccad1aa5dae23a723f7166a0c37
|
F src/sqlite.h.in 6d96f09aac30a030c7674a47659d8156263d2ccad1aa5dae23a723f7166a0c37
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
|
||||||
F src/sqliteInt.h f5377febf86654c975e1d4e4353a5ad2fbaa5bc86b584ba3761ed33e24ce2c0e
|
F src/sqliteInt.h 821479be791acfdb63177b21a491e604526191c1630d1d65d7a4a7c65d203c83
|
||||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||||
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@@ -535,7 +535,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
|||||||
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
|
||||||
F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afef
|
F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afef
|
||||||
F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
|
F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
|
||||||
F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
|
F src/update.c 5123fcb4aa98a705ced2acb172c1761a570d142d77901b4f4ce38acb191ef8ed
|
||||||
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
|
||||||
F src/util.c d01fa6f45bfad3b65fb2490513aa2e0676412c61b4b094340b513cf72c3704a4
|
F src/util.c d01fa6f45bfad3b65fb2490513aa2e0676412c61b4b094340b513cf72c3704a4
|
||||||
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
|
||||||
@@ -1557,7 +1557,8 @@ F test/whereI.test eab5b226bbc344ac70d7dc09b963a064860ae6d7
|
|||||||
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
|
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
|
||||||
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||||
F test/wherelimit.test baa8e5e30b2eddc395cbb3edb313deea14ca6938ea8a96c02a03c34d0ab84b5b
|
F test/wherelimit.test 1dee70c9cc147330156d75e23de88f771e624998b03ae316cb64e1d249f129d8
|
||||||
|
F test/wherelimit2.test 501e470c9cf62e96359e3386ae520874792b83322060168ee9c708b2e953b985
|
||||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||||
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
|
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
|
||||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||||
@@ -1673,7 +1674,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 1bc2d04645c5239ba9a30a13f6fb3c8cc46461c864e7927012bc0ad305eb705e
|
P 62fe56b59270d9d7372b1bb8a53788a40d20d0f111fe38c61dd6269848592c70
|
||||||
R a028f3be0864f739aeb3787daf46fc8e
|
R 46792a4c59e5e3fb96fc57893e581fbe
|
||||||
U drh
|
T *branch * update-delete-limit-fix
|
||||||
Z 97937a65b1ac3d4b961579eac7d25cbd
|
T *sym-update-delete-limit-fix *
|
||||||
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
|
Z c86d100b98964de2c810aa6a7710c91c
|
||||||
|
@@ -1 +1 @@
|
|||||||
62fe56b59270d9d7372b1bb8a53788a40d20d0f111fe38c61dd6269848592c70
|
584b88aaf89ab30cb51185396b7b50c6ecba286add023a26ab41d865b9c605ce
|
95
src/delete.c
95
src/delete.c
@@ -90,6 +90,9 @@ void sqlite3MaterializeView(
|
|||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
Table *pView, /* View definition */
|
Table *pView, /* View definition */
|
||||||
Expr *pWhere, /* Optional WHERE clause to be added */
|
Expr *pWhere, /* Optional WHERE clause to be added */
|
||||||
|
ExprList *pOrderBy, /* Optional ORDER BY clause */
|
||||||
|
Expr *pLimit, /* Optional LIMIT clause */
|
||||||
|
Expr *pOffset, /* Optional OFFSET clause */
|
||||||
int iCur /* Cursor number for ephemeral table */
|
int iCur /* Cursor number for ephemeral table */
|
||||||
){
|
){
|
||||||
SelectDest dest;
|
SelectDest dest;
|
||||||
@@ -106,8 +109,8 @@ void sqlite3MaterializeView(
|
|||||||
assert( pFrom->a[0].pOn==0 );
|
assert( pFrom->a[0].pOn==0 );
|
||||||
assert( pFrom->a[0].pUsing==0 );
|
assert( pFrom->a[0].pUsing==0 );
|
||||||
}
|
}
|
||||||
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0,
|
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
|
||||||
SF_IncludeHidden, 0, 0);
|
SF_IncludeHidden, pLimit, pOffset);
|
||||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
||||||
sqlite3Select(pParse, pSel, &dest);
|
sqlite3Select(pParse, pSel, &dest);
|
||||||
sqlite3SelectDelete(db, pSel);
|
sqlite3SelectDelete(db, pSel);
|
||||||
@@ -132,18 +135,23 @@ Expr *sqlite3LimitWhere(
|
|||||||
Expr *pOffset, /* The OFFSET clause. May be null */
|
Expr *pOffset, /* The OFFSET clause. May be null */
|
||||||
char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
|
char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
|
||||||
){
|
){
|
||||||
Expr *pWhereRowid = NULL; /* WHERE rowid .. */
|
sqlite3 *db = pParse->db;
|
||||||
|
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
|
||||||
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
|
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
|
||||||
Expr *pSelectRowid = NULL; /* SELECT rowid ... */
|
|
||||||
ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
|
ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
|
||||||
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
|
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
|
||||||
Select *pSelect = NULL; /* Complete SELECT tree */
|
Select *pSelect = NULL; /* Complete SELECT tree */
|
||||||
|
Table *pTab;
|
||||||
|
|
||||||
/* Check that there isn't an ORDER BY without a LIMIT clause.
|
/* Check that there isn't an ORDER BY without a LIMIT clause.
|
||||||
*/
|
*/
|
||||||
if( pOrderBy && (pLimit == 0) ) {
|
if( pOrderBy && pLimit==0 ) {
|
||||||
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
|
||||||
goto limit_where_cleanup;
|
sqlite3ExprDelete(pParse->db, pWhere);
|
||||||
|
sqlite3ExprListDelete(pParse->db, pOrderBy);
|
||||||
|
sqlite3ExprDelete(pParse->db, pLimit);
|
||||||
|
sqlite3ExprDelete(pParse->db, pOffset);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We only need to generate a select expression if there
|
/* We only need to generate a select expression if there
|
||||||
@@ -164,36 +172,44 @@ Expr *sqlite3LimitWhere(
|
|||||||
** );
|
** );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
pTab = pSrc->a[0].pTab;
|
||||||
if( pSelectRowid == 0 ) goto limit_where_cleanup;
|
if( HasRowid(pTab) ){
|
||||||
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
|
pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
||||||
if( pEList == 0 ) goto limit_where_cleanup;
|
pEList = sqlite3ExprListAppend(
|
||||||
|
pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||||
|
if( pPk->nKeyCol==1 ){
|
||||||
|
pLhs = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[0]].zName);
|
||||||
|
}else{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<pPk->nKeyCol; i++){
|
||||||
|
Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
|
||||||
|
pEList = sqlite3ExprListAppend(pParse, pEList, p);
|
||||||
|
}
|
||||||
|
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
|
||||||
|
if( pLhs ){
|
||||||
|
pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
||||||
** and the SELECT subtree. */
|
** and the SELECT subtree. */
|
||||||
|
pSrc->a[0].pTab = 0;
|
||||||
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
||||||
if( pSelectSrc == 0 ) {
|
pSrc->a[0].pTab = pTab;
|
||||||
sqlite3ExprListDelete(pParse->db, pEList);
|
|
||||||
goto limit_where_cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generate the SELECT expression tree. */
|
/* generate the SELECT expression tree. */
|
||||||
pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
|
pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
|
||||||
pOrderBy,0,pLimit,pOffset);
|
pOrderBy,0,pLimit,pOffset
|
||||||
if( pSelect == 0 ) return 0;
|
);
|
||||||
|
|
||||||
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
|
||||||
pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
|
||||||
pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0;
|
|
||||||
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
|
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
|
||||||
return pInClause;
|
return pInClause;
|
||||||
|
|
||||||
limit_where_cleanup:
|
|
||||||
sqlite3ExprDelete(pParse->db, pWhere);
|
|
||||||
sqlite3ExprListDelete(pParse->db, pOrderBy);
|
|
||||||
sqlite3ExprDelete(pParse->db, pLimit);
|
|
||||||
sqlite3ExprDelete(pParse->db, pOffset);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
|
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
|
||||||
/* && !defined(SQLITE_OMIT_SUBQUERY) */
|
/* && !defined(SQLITE_OMIT_SUBQUERY) */
|
||||||
@@ -205,10 +221,13 @@ limit_where_cleanup:
|
|||||||
** \________/ \________________/
|
** \________/ \________________/
|
||||||
** pTabList pWhere
|
** pTabList pWhere
|
||||||
*/
|
*/
|
||||||
void sqlite3DeleteFrom(
|
void sqlite3DeleteFromLimit(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
SrcList *pTabList, /* The table from which we should delete things */
|
SrcList *pTabList, /* The table from which we should delete things */
|
||||||
Expr *pWhere /* The WHERE clause. May be null */
|
Expr *pWhere, /* The WHERE clause. May be null */
|
||||||
|
ExprList *pOrderBy,
|
||||||
|
Expr *pLimit,
|
||||||
|
Expr *pOffset
|
||||||
){
|
){
|
||||||
Vdbe *v; /* The virtual database engine */
|
Vdbe *v; /* The virtual database engine */
|
||||||
Table *pTab; /* The table from which records will be deleted */
|
Table *pTab; /* The table from which records will be deleted */
|
||||||
@@ -253,6 +272,7 @@ void sqlite3DeleteFrom(
|
|||||||
}
|
}
|
||||||
assert( pTabList->nSrc==1 );
|
assert( pTabList->nSrc==1 );
|
||||||
|
|
||||||
|
|
||||||
/* Locate the table which we want to delete. This table has to be
|
/* Locate the table which we want to delete. This table has to be
|
||||||
** put in an SrcList structure because some of the subroutines we
|
** put in an SrcList structure because some of the subroutines we
|
||||||
** will be calling are designed to work with multiple tables and expect
|
** will be calling are designed to work with multiple tables and expect
|
||||||
@@ -277,6 +297,16 @@ void sqlite3DeleteFrom(
|
|||||||
# define isView 0
|
# define isView 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||||
|
if( !isView ){
|
||||||
|
pWhere = sqlite3LimitWhere(
|
||||||
|
pParse, pTabList, pWhere, pOrderBy, pLimit, pOffset, "DELETE"
|
||||||
|
);
|
||||||
|
pOrderBy = 0;
|
||||||
|
pLimit = pOffset = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If pTab is really a view, make sure it has been initialized.
|
/* If pTab is really a view, make sure it has been initialized.
|
||||||
*/
|
*/
|
||||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||||
@@ -324,8 +354,12 @@ void sqlite3DeleteFrom(
|
|||||||
*/
|
*/
|
||||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||||
if( isView ){
|
if( isView ){
|
||||||
sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
|
sqlite3MaterializeView(pParse, pTab,
|
||||||
|
pWhere, pOrderBy, pLimit, pOffset, iTabCur
|
||||||
|
);
|
||||||
iDataCur = iIdxCur = iTabCur;
|
iDataCur = iIdxCur = iTabCur;
|
||||||
|
pOrderBy = 0;
|
||||||
|
pLimit = pOffset = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -569,6 +603,9 @@ delete_from_cleanup:
|
|||||||
sqlite3AuthContextPop(&sContext);
|
sqlite3AuthContextPop(&sContext);
|
||||||
sqlite3SrcListDelete(db, pTabList);
|
sqlite3SrcListDelete(db, pTabList);
|
||||||
sqlite3ExprDelete(db, pWhere);
|
sqlite3ExprDelete(db, pWhere);
|
||||||
|
sqlite3ExprListDelete(db, pOrderBy);
|
||||||
|
sqlite3ExprDelete(db, pLimit);
|
||||||
|
sqlite3ExprDelete(db, pOffset);
|
||||||
sqlite3DbFree(db, aToOpen);
|
sqlite3DbFree(db, aToOpen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -753,8 +753,7 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W)
|
|||||||
orderby_opt(O) limit_opt(L). {
|
orderby_opt(O) limit_opt(L). {
|
||||||
sqlite3WithPush(pParse, C, 1);
|
sqlite3WithPush(pParse, C, 1);
|
||||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||||
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE");
|
sqlite3DeleteFromLimit(pParse,X,W,O,L.pLimit,L.pOffset);
|
||||||
sqlite3DeleteFrom(pParse,X,W);
|
|
||||||
}
|
}
|
||||||
%endif
|
%endif
|
||||||
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||||
@@ -779,8 +778,10 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
|
|||||||
sqlite3WithPush(pParse, C, 1);
|
sqlite3WithPush(pParse, C, 1);
|
||||||
sqlite3SrcListIndexedBy(pParse, X, &I);
|
sqlite3SrcListIndexedBy(pParse, X, &I);
|
||||||
sqlite3ExprListCheckLength(pParse,Y,"set list");
|
sqlite3ExprListCheckLength(pParse,Y,"set list");
|
||||||
|
#if 0
|
||||||
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
|
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
|
||||||
sqlite3Update(pParse,X,Y,W,R);
|
#endif
|
||||||
|
sqlite3UpdateLimit(pParse,X,Y,W,R,O,L.pLimit,L.pOffset);
|
||||||
}
|
}
|
||||||
%endif
|
%endif
|
||||||
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||||
|
@@ -3764,8 +3764,11 @@ void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
|||||||
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
||||||
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
|
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
|
||||||
#endif
|
#endif
|
||||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
void sqlite3DeleteFromLimit(Parse*, SrcList*, Expr*, ExprList*, Expr*, Expr*);
|
||||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
#define sqlite3DeleteFrom(x,y,z) sqlite3DeleteFromLimit(x,y,z,0,0,0)
|
||||||
|
void sqlite3UpdateLimit(Parse*, SrcList*, ExprList*, Expr*, int,
|
||||||
|
ExprList*,Expr*,Expr*);
|
||||||
|
#define sqlite3Update(v,w,x,y,z) sqlite3UpdateLimit(v,w,x,y,z,0,0,0)
|
||||||
WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
|
WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
|
||||||
void sqlite3WhereEnd(WhereInfo*);
|
void sqlite3WhereEnd(WhereInfo*);
|
||||||
LogEst sqlite3WhereOutputRowCount(WhereInfo*);
|
LogEst sqlite3WhereOutputRowCount(WhereInfo*);
|
||||||
@@ -3889,7 +3892,7 @@ int sqlite3SafetyCheckSickOrOk(sqlite3*);
|
|||||||
void sqlite3ChangeCookie(Parse*, int);
|
void sqlite3ChangeCookie(Parse*, int);
|
||||||
|
|
||||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||||
void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
|
void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,Expr*,int);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
|
26
src/update.c
26
src/update.c
@@ -86,12 +86,15 @@ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
|
|||||||
** \_______/ \________/ \______/ \________________/
|
** \_______/ \________/ \______/ \________________/
|
||||||
* onError pTabList pChanges pWhere
|
* onError pTabList pChanges pWhere
|
||||||
*/
|
*/
|
||||||
void sqlite3Update(
|
void sqlite3UpdateLimit(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
SrcList *pTabList, /* The table in which we should change things */
|
SrcList *pTabList, /* The table in which we should change things */
|
||||||
ExprList *pChanges, /* Things to be changed */
|
ExprList *pChanges, /* Things to be changed */
|
||||||
Expr *pWhere, /* The WHERE clause. May be null */
|
Expr *pWhere, /* The WHERE clause. May be null */
|
||||||
int onError /* How to handle constraint errors */
|
int onError, /* How to handle constraint errors */
|
||||||
|
ExprList *pOrderBy,
|
||||||
|
Expr *pLimit,
|
||||||
|
Expr *pOffset
|
||||||
){
|
){
|
||||||
int i, j; /* Loop counters */
|
int i, j; /* Loop counters */
|
||||||
Table *pTab; /* The table to be updated */
|
Table *pTab; /* The table to be updated */
|
||||||
@@ -176,6 +179,16 @@ void sqlite3Update(
|
|||||||
# define isView 0
|
# define isView 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||||
|
if( !isView ){
|
||||||
|
pWhere = sqlite3LimitWhere(
|
||||||
|
pParse, pTabList, pWhere, pOrderBy, pLimit, pOffset, "UPDATE"
|
||||||
|
);
|
||||||
|
pOrderBy = 0;
|
||||||
|
pLimit = pOffset = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
|
||||||
goto update_cleanup;
|
goto update_cleanup;
|
||||||
}
|
}
|
||||||
@@ -344,7 +357,11 @@ void sqlite3Update(
|
|||||||
*/
|
*/
|
||||||
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
||||||
if( isView ){
|
if( isView ){
|
||||||
sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
|
sqlite3MaterializeView(pParse, pTab,
|
||||||
|
pWhere, pOrderBy, pLimit, pOffset, iDataCur
|
||||||
|
);
|
||||||
|
pOrderBy = 0;
|
||||||
|
pLimit = pOffset = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -728,6 +745,9 @@ update_cleanup:
|
|||||||
sqlite3SrcListDelete(db, pTabList);
|
sqlite3SrcListDelete(db, pTabList);
|
||||||
sqlite3ExprListDelete(db, pChanges);
|
sqlite3ExprListDelete(db, pChanges);
|
||||||
sqlite3ExprDelete(db, pWhere);
|
sqlite3ExprDelete(db, pWhere);
|
||||||
|
sqlite3ExprListDelete(db, pOrderBy);
|
||||||
|
sqlite3ExprDelete(db, pLimit);
|
||||||
|
sqlite3ExprDelete(db, pOffset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
||||||
|
@@ -38,6 +38,8 @@ proc create_test_data {size} {
|
|||||||
|
|
||||||
ifcapable {update_delete_limit} {
|
ifcapable {update_delete_limit} {
|
||||||
|
|
||||||
|
execsql { CREATE TABLE t1(x, y) }
|
||||||
|
|
||||||
# check syntax error support
|
# check syntax error support
|
||||||
do_test wherelimit-0.1 {
|
do_test wherelimit-0.1 {
|
||||||
catchsql {DELETE FROM t1 ORDER BY x}
|
catchsql {DELETE FROM t1 ORDER BY x}
|
||||||
@@ -49,6 +51,8 @@ ifcapable {update_delete_limit} {
|
|||||||
catchsql {UPDATE t1 SET y=1 WHERE x=1 ORDER BY x}
|
catchsql {UPDATE t1 SET y=1 WHERE x=1 ORDER BY x}
|
||||||
} {1 {ORDER BY without LIMIT on UPDATE}}
|
} {1 {ORDER BY without LIMIT on UPDATE}}
|
||||||
|
|
||||||
|
execsql { DROP TABLE t1 }
|
||||||
|
|
||||||
# no AS on table sources
|
# no AS on table sources
|
||||||
do_test wherelimit-0.4 {
|
do_test wherelimit-0.4 {
|
||||||
catchsql {DELETE FROM t1 AS a WHERE x=1}
|
catchsql {DELETE FROM t1 AS a WHERE x=1}
|
||||||
@@ -301,20 +305,20 @@ ifcapable {update_delete_limit} {
|
|||||||
} {}
|
} {}
|
||||||
do_catchsql_test wherelimit-4.2 {
|
do_catchsql_test wherelimit-4.2 {
|
||||||
DELETE FROM tv WHERE 1 LIMIT 2;
|
DELETE FROM tv WHERE 1 LIMIT 2;
|
||||||
} {1 {ORDER BY and LIMIT not support for table tv}}
|
} {0 {}}
|
||||||
do_catchsql_test wherelimit-4.3 {
|
do_catchsql_test wherelimit-4.3 {
|
||||||
DELETE FROM tv WHERE 1 ORDER BY a LIMIT 2;
|
DELETE FROM tv WHERE 1 ORDER BY a LIMIT 2;
|
||||||
} {1 {ORDER BY and LIMIT not support for table tv}}
|
} {0 {}}
|
||||||
do_execsql_test wherelimit-4.10 {
|
do_execsql_test wherelimit-4.10 {
|
||||||
CREATE TABLE t3(a,b,c,d TEXT, PRIMARY KEY(a,b)) WITHOUT ROWID;
|
CREATE TABLE t3(a,b,c,d TEXT, PRIMARY KEY(a,b)) WITHOUT ROWID;
|
||||||
INSERT INTO t3(a,b,c,d) VALUES(1,2,3,4),(5,6,7,8),(9,10,11,12);
|
INSERT INTO t3(a,b,c,d) VALUES(1,2,3,4),(5,6,7,8),(9,10,11,12);
|
||||||
} {}
|
} {}
|
||||||
do_catchsql_test wherelimit-4.11 {
|
do_catchsql_test wherelimit-4.11 {
|
||||||
DELETE FROM t3 WHERE a=5 LIMIT 2;
|
DELETE FROM t3 WHERE a=5 LIMIT 2;
|
||||||
} {1 {ORDER BY and LIMIT not support for table t3}}
|
} {0 {}}
|
||||||
do_execsql_test wherelimit-4.12 {
|
do_execsql_test wherelimit-4.12 {
|
||||||
SELECT a,b,c,d FROM t3 ORDER BY 1;
|
SELECT a,b,c,d FROM t3 ORDER BY 1;
|
||||||
} {1 2 3 4 5 6 7 8 9 10 11 12}
|
} {1 2 3 4 9 10 11 12}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
109
test/wherelimit2.test
Normal file
109
test/wherelimit2.test
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# 2008 October 6
|
||||||
|
#
|
||||||
|
# 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. The
|
||||||
|
# focus of this file is testing the LIMIT ... OFFSET ... clause
|
||||||
|
# of UPDATE and DELETE statements.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix wherelimit2
|
||||||
|
|
||||||
|
ifcapable !update_delete_limit {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE TABLE t1(a, b);
|
||||||
|
INSERT INTO t1 VALUES(1, 'f');
|
||||||
|
INSERT INTO t1 VALUES(2, 'e');
|
||||||
|
INSERT INTO t1 VALUES(3, 'd');
|
||||||
|
INSERT INTO t1 VALUES(4, 'c');
|
||||||
|
INSERT INTO t1 VALUES(5, 'b');
|
||||||
|
INSERT INTO t1 VALUES(6, 'a');
|
||||||
|
|
||||||
|
CREATE VIEW v1 AS SELECT a,b FROM t1;
|
||||||
|
CREATE TABLE log(op, a);
|
||||||
|
|
||||||
|
CREATE TRIGGER v1del INSTEAD OF DELETE ON v1 BEGIN
|
||||||
|
INSERT INTO log VALUES('delete', old.a);
|
||||||
|
END;
|
||||||
|
|
||||||
|
CREATE TRIGGER v1upd INSTEAD OF UPDATE ON v1 BEGIN
|
||||||
|
INSERT INTO log VALUES('update', old.a);
|
||||||
|
END;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
DELETE FROM v1 ORDER BY a LIMIT 3;
|
||||||
|
SELECT * FROM log; DELETE FROM log;
|
||||||
|
} {
|
||||||
|
delete 1 delete 2 delete 3
|
||||||
|
}
|
||||||
|
do_execsql_test 1.2 {
|
||||||
|
DELETE FROM v1 ORDER BY b LIMIT 3;
|
||||||
|
SELECT * FROM log; DELETE FROM log;
|
||||||
|
} {
|
||||||
|
delete 6 delete 5 delete 4
|
||||||
|
}
|
||||||
|
do_execsql_test 1.3 {
|
||||||
|
UPDATE v1 SET b = 555 ORDER BY a LIMIT 3;
|
||||||
|
SELECT * FROM log; DELETE FROM log;
|
||||||
|
} {
|
||||||
|
update 1 update 2 update 3
|
||||||
|
}
|
||||||
|
do_execsql_test 1.4 {
|
||||||
|
UPDATE v1 SET b = 555 ORDER BY b LIMIT 3;
|
||||||
|
SELECT * FROM log; DELETE FROM log;
|
||||||
|
} {
|
||||||
|
update 6 update 5 update 4
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.0 {
|
||||||
|
CREATE TABLE t2(a, b, c, PRIMARY KEY(a, b)) WITHOUT ROWID;
|
||||||
|
INSERT INTO t2 VALUES(1, 1, 'h');
|
||||||
|
INSERT INTO t2 VALUES(1, 2, 'g');
|
||||||
|
INSERT INTO t2 VALUES(2, 1, 'f');
|
||||||
|
INSERT INTO t2 VALUES(2, 2, 'e');
|
||||||
|
INSERT INTO t2 VALUES(3, 1, 'd');
|
||||||
|
INSERT INTO t2 VALUES(3, 2, 'c');
|
||||||
|
INSERT INTO t2 VALUES(4, 1, 'b');
|
||||||
|
INSERT INTO t2 VALUES(4, 2, 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1 {
|
||||||
|
BEGIN;
|
||||||
|
DELETE FROM t2 WHERE b=1 ORDER BY c LIMIT 2;
|
||||||
|
SELECT c FROM t2 ORDER BY 1;
|
||||||
|
ROLLBACK;
|
||||||
|
} {a c e f g h}
|
||||||
|
|
||||||
|
do_execsql_test 2.2 {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE t2 SET c=NULL ORDER BY a, b DESC LIMIT 3 OFFSET 1;
|
||||||
|
SELECT a, b, c FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
} {
|
||||||
|
1 1 {}
|
||||||
|
1 2 g
|
||||||
|
2 1 {}
|
||||||
|
2 2 {}
|
||||||
|
3 1 d
|
||||||
|
3 2 c
|
||||||
|
4 1 b
|
||||||
|
4 2 a
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
Reference in New Issue
Block a user