xref: /sqlite-3.40.0/src/delete.c (revision 7c68d60b)
1 /*
2 ** Copyright (c) 1999, 2000 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2 of the License, or (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ** General Public License for more details.
13 **
14 ** You should have received a copy of the GNU General Public
15 ** License along with this library; if not, write to the
16 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 ** Boston, MA  02111-1307, USA.
18 **
19 ** Author contact information:
20 **   [email protected]
21 **   http://www.hwaci.com/drh/
22 **
23 *************************************************************************
24 ** This file contains C code routines that are called by the parser
25 ** to handle DELETE FROM statements.
26 **
27 ** $Id: delete.c,v 1.6 2000/06/21 13:59:11 drh Exp $
28 */
29 #include "sqliteInt.h"
30 
31 /*
32 ** Process a DELETE FROM statement.
33 */
34 void sqliteDeleteFrom(
35   Parse *pParse,         /* The parser context */
36   Token *pTableName,     /* The table from which we should delete things */
37   Expr *pWhere           /* The WHERE clause.  May be null */
38 ){
39   Vdbe *v;               /* The virtual database engine */
40   Table *pTab;           /* The table from which records will be deleted */
41   IdList *pTabList;      /* An ID list holding pTab and nothing else */
42   int end, addr;         /* A couple addresses of generated code */
43   int i;                 /* Loop counter */
44   WhereInfo *pWInfo;     /* Information about the WHERE clause */
45   Index *pIdx;           /* For looping over indices of the table */
46   int base;              /* Index of the first available table cursor */
47 
48   /* Locate the table which we want to delete.  This table has to be
49   ** put in an IdList structure because some of the subroutines we
50   ** will be calling are designed to work with multiple tables and expect
51   ** an IdList* parameter instead of just a Table* parameger.
52   */
53   pTabList = sqliteIdListAppend(0, pTableName);
54   for(i=0; i<pTabList->nId; i++){
55     pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
56     if( pTabList->a[i].pTab==0 ){
57       sqliteSetString(&pParse->zErrMsg, "no such table: ",
58          pTabList->a[i].zName, 0);
59       pParse->nErr++;
60       goto delete_from_cleanup;
61     }
62     if( pTabList->a[i].pTab->readOnly ){
63       sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
64         " may not be modified", 0);
65       pParse->nErr++;
66       goto delete_from_cleanup;
67     }
68   }
69   pTab = pTabList->a[0].pTab;
70 
71   /* Resolve the column names in all the expressions.
72   */
73   if( pWhere ){
74     sqliteExprResolveInSelect(pParse, pWhere);
75     if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
76       goto delete_from_cleanup;
77     }
78     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
79       goto delete_from_cleanup;
80     }
81   }
82 
83   /* Begin generating code.
84   */
85   v = sqliteGetVdbe(pParse);
86   if( v==0 ) goto delete_from_cleanup;
87 
88   /* Begin the database scan
89   */
90   sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
91   pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
92   if( pWInfo==0 ) goto delete_from_cleanup;
93 
94   /* Remember the key of every item to be deleted.
95   */
96   sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
97 
98   /* End the database scan loop.
99   */
100   sqliteWhereEnd(pWInfo);
101 
102   /* Delete every item whose key was written to the list during the
103   ** database scan.  We have to delete items after the scan is complete
104   ** because deleting an item can change the scan order.
105   */
106   base = pParse->nTab;
107   sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
108   sqliteVdbeAddOp(v, OP_Open, base, 1, pTab->zName, 0);
109   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
110     sqliteVdbeAddOp(v, OP_Open, base+i, 1, pIdx->zName, 0);
111   }
112   end = sqliteVdbeMakeLabel(v);
113   addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
114   if( pTab->pIndex ){
115     sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
116     sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
117     for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
118       int j;
119       sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
120       for(j=0; j<pIdx->nColumn; j++){
121         sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
122       }
123       sqliteVdbeAddOp(v, OP_MakeKey, pIdx->nColumn, 0, 0, 0);
124       sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
125     }
126   }
127   sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0);
128   sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
129   sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
130 
131 delete_from_cleanup:
132   sqliteIdListDelete(pTabList);
133   sqliteExprDelete(pWhere);
134   return;
135 }
136