blob: 06e7d82bd029f8887eab49422260c755478998d7 [file] [log] [blame]
drhcce7d172000-05-31 15:34:51 +00001/*
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** drh@hwaci.com
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**
drh5e00f6c2001-09-13 13:46:56 +000027** $Id: delete.c,v 1.10 2001/09/13 13:46:56 drh Exp $
drhcce7d172000-05-31 15:34:51 +000028*/
29#include "sqliteInt.h"
30
31/*
32** Process a DELETE FROM statement.
33*/
34void 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 */
drh4794b982000-06-06 13:54:14 +000046 int base; /* Index of the first available table cursor */
drhcce7d172000-05-31 15:34:51 +000047
drhdaffd0e2001-04-11 14:28:42 +000048 if( pParse->nErr || sqlite_malloc_failed ){
49 pTabList = 0;
50 goto delete_from_cleanup;
51 }
52
drh1ccde152000-06-17 13:12:39 +000053 /* Locate the table which we want to delete. This table has to be
54 ** put in an IdList structure because some of the subroutines we
drhcce7d172000-05-31 15:34:51 +000055 ** will be calling are designed to work with multiple tables and expect
56 ** an IdList* parameter instead of just a Table* parameger.
57 */
58 pTabList = sqliteIdListAppend(0, pTableName);
drhdaffd0e2001-04-11 14:28:42 +000059 if( pTabList==0 ) goto delete_from_cleanup;
drhcce7d172000-05-31 15:34:51 +000060 for(i=0; i<pTabList->nId; i++){
61 pTabList->a[i].pTab = sqliteFindTable(pParse->db, pTabList->a[i].zName);
62 if( pTabList->a[i].pTab==0 ){
63 sqliteSetString(&pParse->zErrMsg, "no such table: ",
64 pTabList->a[i].zName, 0);
65 pParse->nErr++;
66 goto delete_from_cleanup;
67 }
68 if( pTabList->a[i].pTab->readOnly ){
69 sqliteSetString(&pParse->zErrMsg, "table ", pTabList->a[i].zName,
70 " may not be modified", 0);
71 pParse->nErr++;
72 goto delete_from_cleanup;
73 }
74 }
75 pTab = pTabList->a[0].pTab;
76
drh967e8b72000-06-21 13:59:10 +000077 /* Resolve the column names in all the expressions.
drhcce7d172000-05-31 15:34:51 +000078 */
79 if( pWhere ){
drh4794b982000-06-06 13:54:14 +000080 sqliteExprResolveInSelect(pParse, pWhere);
drhcce7d172000-05-31 15:34:51 +000081 if( sqliteExprResolveIds(pParse, pTabList, pWhere) ){
82 goto delete_from_cleanup;
83 }
84 if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
85 goto delete_from_cleanup;
86 }
87 }
88
89 /* Begin generating code.
90 */
drhd8bc7082000-06-07 23:51:50 +000091 v = sqliteGetVdbe(pParse);
drhcce7d172000-05-31 15:34:51 +000092 if( v==0 ) goto delete_from_cleanup;
drh5e00f6c2001-09-13 13:46:56 +000093 if( (pParse->db->flags & SQLITE_InTrans)==0 ){
94 sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
95 }
96
drhcce7d172000-05-31 15:34:51 +000097
drh0353ced2001-03-20 22:05:00 +000098 /* Special case: A DELETE without a WHERE clause deletes everything.
99 ** It is easier just to deleted the database files directly.
drhcce7d172000-05-31 15:34:51 +0000100 */
drh0353ced2001-03-20 22:05:00 +0000101 if( pWhere==0 ){
drh5e00f6c2001-09-13 13:46:56 +0000102 sqliteVdbeAddOp(v, OP_Destroy, pTab->tnum, 0, 0, 0);
drh0353ced2001-03-20 22:05:00 +0000103 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
drh5e00f6c2001-09-13 13:46:56 +0000104 sqliteVdbeAddOp(v, OP_Destroy, pIdx->tnum, 0, 0, 0);
drhcce7d172000-05-31 15:34:51 +0000105 }
106 }
drh0353ced2001-03-20 22:05:00 +0000107
108 /* The usual case: There is a WHERE clause so we have to scan through
109 ** the table an pick which records to delete.
110 */
111 else{
112 /* Begin the database scan
113 */
114 sqliteVdbeAddOp(v, OP_ListOpen, 0, 0, 0, 0);
115 pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1);
116 if( pWInfo==0 ) goto delete_from_cleanup;
117
118 /* Remember the key of every item to be deleted.
119 */
120 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0, 0, 0);
121
122 /* End the database scan loop.
123 */
124 sqliteWhereEnd(pWInfo);
125
126 /* Delete every item whose key was written to the list during the
127 ** database scan. We have to delete items after the scan is complete
128 ** because deleting an item can change the scan order.
129 */
130 base = pParse->nTab;
131 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0, 0, 0);
drh5e00f6c2001-09-13 13:46:56 +0000132 sqliteVdbeAddOp(v, OP_Open, base, pTab->tnum, 0, 0);
drh0353ced2001-03-20 22:05:00 +0000133 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
drh5e00f6c2001-09-13 13:46:56 +0000134 sqliteVdbeAddOp(v, OP_Open, base+i, pIdx->tnum, 0, 0);
drh0353ced2001-03-20 22:05:00 +0000135 }
136 end = sqliteVdbeMakeLabel(v);
137 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end, 0, 0);
138 if( pTab->pIndex ){
139 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
140 sqliteVdbeAddOp(v, OP_Fetch, base, 0, 0, 0);
141 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
142 int j;
143 sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
144 for(j=0; j<pIdx->nColumn; j++){
145 sqliteVdbeAddOp(v, OP_Field, base, pIdx->aiColumn[j], 0, 0);
146 }
drh5e00f6c2001-09-13 13:46:56 +0000147 sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0, 0, 0);
drh0353ced2001-03-20 22:05:00 +0000148 sqliteVdbeAddOp(v, OP_DeleteIdx, base+i, 0, 0, 0);
149 }
150 }
151 sqliteVdbeAddOp(v, OP_Delete, base, 0, 0, 0);
152 sqliteVdbeAddOp(v, OP_Goto, 0, addr, 0, 0);
153 sqliteVdbeAddOp(v, OP_ListClose, 0, 0, 0, end);
154 }
drh5e00f6c2001-09-13 13:46:56 +0000155 if( (pParse->db->flags & SQLITE_InTrans)==0 ){
156 sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
157 }
158
drhcce7d172000-05-31 15:34:51 +0000159
160delete_from_cleanup:
161 sqliteIdListDelete(pTabList);
162 sqliteExprDelete(pWhere);
163 return;
164}