/ Check-in [9c8b132e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment: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)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:9c8b132e34bc6024bc9898182f8f93127ca52ac9
User & Date: shane 2008-10-07 05:27:11
Context
2008-10-07
11:51
Fix a problem with hot-journal rollback. SQLITE_CANTOPEN was being returned if the hot-journal file contained a pointer to a master journal file that did not exist. (CVS 5775) check-in: 22d1feb9 user: danielk1977 tags: trunk
05:27
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) check-in: 9c8b132e user: shane tags: trunk
01:18
Removed redundant assert(). (CVS 5773) check-in: 486b1124 user: shane tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/delete.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
112
113
114
115
116
117
118




































119
120
121
122
123
124
125
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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 $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.
................................................................................
  }
  sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
  sqlite3Select(pParse, pDup, &dest);
  sqlite3SelectDelete(db, pDup);
}
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */






































/*
** Generate code for a DELETE FROM statement.
**
**     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
**                 \________/       \________________/
**                  pTabList              pWhere







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** 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.178 2008/10/07 05:27:11 shane Exp $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.
................................................................................
  }
  sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
  sqlite3Select(pParse, pDup, &dest);
  sqlite3SelectDelete(db, pDup);
}
#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.
**
**     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
**                 \________/       \________________/
**                  pTabList              pWhere

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
574
575
576
577
578
579
580

















581
582
583
584

585
586
587
588
589
590
591
592
593


















594
595
596
597
598

599
600
601
602
603
604
605
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** 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 $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). 
                                       {A.pLimit = X; A.pOffset = Y;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). 
                                       {A.pOffset = X; A.pLimit = Y;}

/////////////////////////// The DELETE statement /////////////////////////////
//

















cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(Y). {
  sqlite3SrcListIndexedBy(pParse, X, &I);
  sqlite3DeleteFrom(pParse,X,Y);
}


%type where_opt {Expr*}
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}

where_opt(A) ::= .                    {A = 0;}
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).  {
  sqlite3SrcListIndexedBy(pParse, X, &I);
  sqlite3ExprListCheckLength(pParse,Y,"set list"); 
  sqlite3Update(pParse,X,Y,Z,R);
}


%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}

setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
    {A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
setlist(A) ::= nm(X) EQ expr(Y).







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

|

>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|


|

>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $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_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). 
                                       {A.pLimit = X; A.pOffset = Y;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). 
                                       {A.pOffset = X; A.pLimit = Y;}

/////////////////////////// The DELETE statement /////////////////////////////
//
%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);
  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, $$);}

where_opt(A) ::= .                    {A = 0;}
where_opt(A) ::= WHERE expr(X).       {A = X;}

////////////////////////// The UPDATE command ////////////////////////////////
//
%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"); 
  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, $$);}

setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y).
    {A = sqlite3ExprListAppend(pParse,Z,Y,&X);}
setlist(A) ::= nm(X) EQ expr(Y).

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2155
2156
2157
2158
2159
2160
2161



2162
2163
2164
2165
2166
2167
2168
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.775 2008/10/06 16:18:40 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                         Expr*,ExprList*,int,Expr*,Expr*);
void sqlite3SelectDelete(sqlite3*, Select*);
Table *sqlite3SrcListLookup(Parse*, SrcList*);
int sqlite3IsReadOnly(Parse*, Table*, int);
void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);



void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**, u8);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCodeCopy(Parse*, int, int, int);







|







 







>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.776 2008/10/07 05:27:11 shane Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
int sqlite3Select(Parse*, Select*, SelectDest*);
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
                         Expr*,ExprList*,int,Expr*,Expr*);
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);
void sqlite3WhereEnd(WhereInfo*);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int);
void sqlite3ExprCodeCopy(Parse*, int, int, int);