From: shane Date: Tue, 7 Oct 2008 05:27:11 +0000 (+0000) Subject: Initial support for LIMIT clause on DELETEs and UPDATEs. Changes likely with more... X-Git-Tag: version-3.6.10~403 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4281bd420437102f6fb7fdd72fcf4cca84bd6092;p=thirdparty%2Fsqlite.git Initial support for LIMIT clause on DELETEs and UPDATEs. Changes likely with more testing. The code can be omitted with the define SQLITE_OMIT_UPDATE_DELETE_LIMIT. (CVS 5774) FossilOrigin-Name: 9c8b132e34bc6024bc9898182f8f93127ca52ac9 --- diff --git a/manifest b/manifest index b623ff1b3d..76b936cd36 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Removed\sredundant\sassert().\s(CVS\s5773) -D 2008-10-07T01:18:59 +C Initial\ssupport\sfor\sLIMIT\sclause\son\sDELETEs\sand\sUPDATEs.\s\sChanges\slikely\swith\smore\stesting.\s\sThe\scode\scan\sbe\somitted\swith\sthe\sdefine\sSQLITE_OMIT_UPDATE_DELETE_LIMIT.\s(CVS\s5774) +D 2008-10-07T05:27:11 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in e4ab842f9a64ef61d57093539a8aab76b12810db F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -106,7 +106,7 @@ F src/build.c 8714bd809583bbe07bf22d0e1808a3fc31abe330 F src/callback.c 7a40fd44da3eb89e7f6eff30aa6f940c45d73a97 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c F src/date.c 5c092296c03d658e84884121a694150964d6861d -F src/delete.c 924c43df7533479d0aa93dc0eed32c9b8cf64c9f +F src/delete.c 7c9183a17b93b79dabbbc7cdb2159972d052b5a0 F src/expr.c 30973b017bf95ca767f5eec64918c8afc425488d F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff F src/func.c 8431b40a7843d1024145684d303c55b4ee087bbe @@ -139,7 +139,7 @@ F src/os_unix.c f33b69d8a85372b270fe37ee664a4c2140a5217d F src/os_win.c 04033a86a39f49cb8e348f515eb0116aa9d36678 F src/pager.c 44eba010e81dcc9b772401b90d6a1c61ec24345b F src/pager.h 9c1917be28fff58118e1fe0ddbc7adfb8dd4f44d -F src/parse.y d8edf095cd9f1a0083e6ff6b964396870523dc0d +F src/parse.y 85d57c1dba3098da736a0c2ff8917c3d02a3a5f8 F src/pcache.c f8d7beceba164a34441ac37e88abb3a404f968a7 F src/pcache.h 28d9ce2d66909db1f01652586450b62b64793093 F src/pragma.c 0b1c2d2a241dd79a7361bbeb8ff575a9e9d7cd71 @@ -151,7 +151,7 @@ F src/select.c c1c555ee714c61db92b2688b307a0145d7405122 F src/shell.c d83b578a8ccdd3e0e7fef4388a0887ce9f810967 F src/sqlite.h.in ea235b37a691b32e7941baa70fb0afaf6377dbb4 F src/sqlite3ext.h 1e3887c9bd3ae66cb599e922824b04cd0d0f2c3e -F src/sqliteInt.h 6c08ddc70e1c9b0581778543af6985342c5516f0 +F src/sqliteInt.h 78ec9e3cd535c8a092d6b19808c5ffb5276381f0 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/table.c 22744786199c9195720c15a7a42cb97b2e2728d8 @@ -640,7 +640,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 83a7e446b2d4846a6f92bd831a2adaa265f5a786 -R aa8a31d65cc954485c711dc29b6f394a +P 486b1124f76bcf0505b6be908f2a3e988ad6e05d +R d465119c99c45922a96415b5f4873654 U shane -Z 0e61cf018a940fb3ad2af57c9790cf1b +Z 57d43f78fc0572634b2aa36caa16bd30 diff --git a/manifest.uuid b/manifest.uuid index 36cf0b69e7..88a7b3dac4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -486b1124f76bcf0505b6be908f2a3e988ad6e05d \ No newline at end of file +9c8b132e34bc6024bc9898182f8f93127ca52ac9 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index e125fe6238..9a414d2839 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.177 2008/10/06 16:18:40 danielk1977 Exp $ +** $Id: delete.c,v 1.178 2008/10/07 05:27:11 shane Exp $ */ #include "sqliteInt.h" @@ -116,6 +116,42 @@ void sqlite3MaterializeView( } #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ +#ifndef SQLITE_OMIT_UPDATE_DELETE_LIMIT +/* +** Generate an expression tree to implement the WHERE, ORDER BY, +** and LIMIT/OFFSET portion of DELETE and UPDATE statements. +** +** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1; +** \__________________________/ +** pLimitWhere (pInClause) +*/ +Expr *sqlite3LimitWhere( + Parse *pParse, /* The parser context */ + SrcList *pSrc, /* the FROM clause -- which tables to scan */ + Expr *pWhere, /* The WHERE clause. May be null */ + ExprList *pOrderBy, /* The ORDER BY clause. May be null */ + Expr *pLimit, /* The LIMIT clause. May be null */ + Expr *pOffset /* The OFFSET clause. May be null */ +){ + Expr *pWhereRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0); + Expr *pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0); + Expr *pSelectRowid = sqlite3Expr(pParse->db, TK_ROW, 0, 0, 0); + ExprList *pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid, 0); + SrcList *pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc); + Select *pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,pOrderBy,0,pLimit,pOffset); + if( pSelect ) { + pInClause->pSelect = pSelect; + sqlite3ExprSetHeight(pParse, pInClause); + return pInClause; + } + sqlite3SrcListDelete(pParse->db, pSelectSrc); + sqlite3ExprListDelete(pParse->db, pEList); + sqlite3ExprDelete(pParse->db, pSelectRowid); + sqlite3ExprDelete(pParse->db, pInClause); + sqlite3ExprDelete(pParse->db, pWhereRowid); + return 0; +} +#endif /* !defined(SQLITE_OMIT_UPDATE_DELETE_LIMIT) */ /* ** Generate code for a DELETE FROM statement. diff --git a/src/parse.y b/src/parse.y index 65d968310a..2e955294db 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.254 2008/10/06 16:18:40 danielk1977 Exp $ +** @(#) $Id: parse.y,v 1.255 2008/10/07 05:27:11 shane Exp $ */ // All token codes are small integers with #defines that begin with "TK_" @@ -578,10 +578,28 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). /////////////////////////// The DELETE statement ///////////////////////////// // -cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(Y). { +%ifndef SQLITE_OMIT_UPDATE_DELETE_LIMIT +cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); - sqlite3DeleteFrom(pParse,X,Y); + if( O && !L.pLimit ){ + sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on DELETE"); + pParse->parseError = 1; + } else if (L.pLimit) { + Expr *LW = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset); + if( LW ) { + sqlite3DeleteFrom(pParse,X,LW); + } + } else { + sqlite3DeleteFrom(pParse,X,W); + } } +%endif +%ifdef SQLITE_OMIT_UPDATE_DELETE_LIMIT +cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(W). { + sqlite3SrcListIndexedBy(pParse, X, &I); + sqlite3DeleteFrom(pParse,X,W); +} +%endif %type where_opt {Expr*} %destructor where_opt {sqlite3ExprDelete(pParse->db, $$);} @@ -591,11 +609,30 @@ where_opt(A) ::= WHERE expr(X). {A = X;} ////////////////////////// The UPDATE command //////////////////////////////// // -cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(Z). { +%ifndef SQLITE_OMIT_UPDATE_DELETE_LIMIT +cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); - sqlite3Update(pParse,X,Y,Z,R); + if( O && !L.pLimit ){ + sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE"); + pParse->parseError = 1; + } else if (L.pLimit) { + Expr *LW = sqlite3LimitWhere(pParse, X, W, O, L.pLimit,L.pOffset); + if( LW ) { + sqlite3Update(pParse,X,Y,LW,R); + } + } else { + sqlite3Update(pParse,X,Y,W,R); + } +} +%endif +%ifdef SQLITE_OMIT_UPDATE_DELETE_LIMIT +cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W). { + sqlite3SrcListIndexedBy(pParse, X, &I); + sqlite3ExprListCheckLength(pParse,Y,"set list"); + sqlite3Update(pParse,X,Y,W,R); } +%endif %type setlist {ExprList*} %destructor setlist {sqlite3ExprListDelete(pParse->db, $$);} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ac370c94e0..8141f8e34a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.775 2008/10/06 16:18:40 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.776 2008/10/07 05:27:11 shane Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -2159,6 +2159,9 @@ void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); +#ifndef SQLITE_OMIT_UPDATE_DELETE_LIMIT +Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *); +#endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);