blob: fecb8cc12d558a950bd01fa7bc7376adceb4eee3 [file] [log] [blame]
drhcce7d172000-05-31 15:34:51 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drhcce7d172000-05-31 15:34:51 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drhcce7d172000-05-31 15:34:51 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drhcce7d172000-05-31 15:34:51 +000010**
11*************************************************************************
12** This file contains C code routines that are called by the parser
13** to handle DELETE FROM statements.
14**
drhda93d232003-03-31 02:12:46 +000015** $Id: delete.c,v 1.50 2003/03/31 02:12:47 drh Exp $
drhcce7d172000-05-31 15:34:51 +000016*/
17#include "sqliteInt.h"
18
drha76b5df2002-02-23 02:32:10 +000019/*
drh812d7a22003-03-27 13:50:00 +000020** Look up every table that is named in pSrc. If any table is not found,
21** add an error message to pParse->zErrMsg and return NULL. If all tables
22** are found, return a pointer to the last table.
drha76b5df2002-02-23 02:32:10 +000023*/
drh812d7a22003-03-27 13:50:00 +000024Table *sqliteSrcListLookup(Parse *pParse, SrcList *pSrc){
25 Table *pTab = 0;
26 int i;
27 for(i=0; i<pSrc->nSrc; i++){
28 const char *zTab = pSrc->a[i].zName;
29 const char *zDb = pSrc->a[i].zDatabase;
30 pTab = sqliteFindTable(pParse->db, zTab, zDb);
31 if( pTab==0 ){
drhda93d232003-03-31 02:12:46 +000032 sqliteErrorMsg(pParse, "no such table: %S", pSrc, 0);
drh812d7a22003-03-27 13:50:00 +000033 break;
drhd24cc422003-03-27 12:51:24 +000034 }
drh812d7a22003-03-27 13:50:00 +000035 pSrc->a[i].pTab = pTab;
drha76b5df2002-02-23 02:32:10 +000036 }
37 return pTab;
38}
39
40/*
drh812d7a22003-03-27 13:50:00 +000041** Check to make sure the given table is writable. If it is not
42** writable, generate an error message and return 1. If it is
43** writable return 0;
44*/
45int sqliteIsReadOnly(Parse *pParse, Table *pTab){
46 if( pTab->readOnly || pTab->pSelect ){
drhda93d232003-03-31 02:12:46 +000047 sqliteErrorMsg(pParse, "%s %s may not be modified",
48 pTab->pSelect ? "view" : "table",
49 pTab->zName);
drh812d7a22003-03-27 13:50:00 +000050 return 1;
51 }
52 return 0;
53}
54
55/*
drhcce7d172000-05-31 15:34:51 +000056** Process a DELETE FROM statement.
57*/
58void sqliteDeleteFrom(
59 Parse *pParse, /* The parser context */
drh113088e2003-03-20 01:16:58 +000060 SrcList *pTabList, /* The table from which we should delete things */
drhcce7d172000-05-31 15:34:51 +000061 Expr *pWhere /* The WHERE clause. May be null */
62){
63 Vdbe *v; /* The virtual database engine */
64 Table *pTab; /* The table from which records will be deleted */
drhc977f7f2002-05-21 11:38:11 +000065 char *zTab; /* Name of the table from which we are deleting */
drhd24cc422003-03-27 12:51:24 +000066 char *zDb; /* Name of database containing table zTab */
drhcce7d172000-05-31 15:34:51 +000067 int end, addr; /* A couple addresses of generated code */
68 int i; /* Loop counter */
69 WhereInfo *pWInfo; /* Information about the WHERE clause */
70 Index *pIdx; /* For looping over indices of the table */
drh4794b982000-06-06 13:54:14 +000071 int base; /* Index of the first available table cursor */
drhecdc7532001-09-23 02:35:53 +000072 sqlite *db; /* Main database structure */
drh1bee3d72001-10-15 00:44:35 +000073
danielk1977c3f9bad2002-05-15 08:30:12 +000074 int row_triggers_exist = 0;
75 int oldIdx = -1;
drhcce7d172000-05-31 15:34:51 +000076
drhe5f9c642003-01-13 23:27:31 +000077 if( pParse->nErr || sqlite_malloc_failed ){
drhdaffd0e2001-04-11 14:28:42 +000078 pTabList = 0;
79 goto delete_from_cleanup;
80 }
drhecdc7532001-09-23 02:35:53 +000081 db = pParse->db;
drh113088e2003-03-20 01:16:58 +000082 assert( pTabList->nSrc==1 );
drhdaffd0e2001-04-11 14:28:42 +000083
danielk1977c3f9bad2002-05-15 08:30:12 +000084 /* Check for the special case of a VIEW with one or more ON DELETE triggers
danielk1977f29ce552002-05-19 23:43:12 +000085 ** defined
86 */
drh113088e2003-03-20 01:16:58 +000087 zTab = pTabList->a[0].zName;
drhd24cc422003-03-27 12:51:24 +000088 zDb = pTabList->a[0].zDatabase;
drhc977f7f2002-05-21 11:38:11 +000089 if( zTab != 0 ){
drhd24cc422003-03-27 12:51:24 +000090 pTab = sqliteFindTable(pParse->db, zTab, zDb);
drhc977f7f2002-05-21 11:38:11 +000091 if( pTab ){
92 row_triggers_exist =
93 sqliteTriggersExist(pParse, pTab->pTrigger,
94 TK_DELETE, TK_BEFORE, TK_ROW, 0) ||
95 sqliteTriggersExist(pParse, pTab->pTrigger,
96 TK_DELETE, TK_AFTER, TK_ROW, 0);
97 }
drhc977f7f2002-05-21 11:38:11 +000098 if( row_triggers_exist && pTab->pSelect ){
99 /* Just fire VIEW triggers */
drh113088e2003-03-20 01:16:58 +0000100 sqliteSrcListDelete(pTabList);
drhc977f7f2002-05-21 11:38:11 +0000101 sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0);
102 return;
danielk1977c3f9bad2002-05-15 08:30:12 +0000103 }
104 }
105
drh1ccde152000-06-17 13:12:39 +0000106 /* Locate the table which we want to delete. This table has to be
drhad3cab52002-05-24 02:04:32 +0000107 ** put in an SrcList structure because some of the subroutines we
drhcce7d172000-05-31 15:34:51 +0000108 ** will be calling are designed to work with multiple tables and expect
drhad3cab52002-05-24 02:04:32 +0000109 ** an SrcList* parameter instead of just a Table* parameter.
drhcce7d172000-05-31 15:34:51 +0000110 */
drh812d7a22003-03-27 13:50:00 +0000111 pTab = sqliteSrcListLookup(pParse, pTabList);
112 if( pTab==0 || sqliteIsReadOnly(pParse, pTab) ){
drh113088e2003-03-20 01:16:58 +0000113 goto delete_from_cleanup;
114 }
drh417be792002-03-03 18:59:40 +0000115 assert( pTab->pSelect==0 ); /* This table is not a view */
drhe5f9c642003-01-13 23:27:31 +0000116 if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0) ){
117 goto delete_from_cleanup;
118 }
drhcce7d172000-05-31 15:34:51 +0000119
drhc977f7f2002-05-21 11:38:11 +0000120 /* Allocate a cursor used to store the old.* data for a trigger.
121 */
danielk1977f29ce552002-05-19 23:43:12 +0000122 if( row_triggers_exist ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000123 oldIdx = pParse->nTab++;
danielk1977f29ce552002-05-19 23:43:12 +0000124 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000125
drh967e8b72000-06-21 13:59:10 +0000126 /* Resolve the column names in all the expressions.
drhcce7d172000-05-31 15:34:51 +0000127 */
drh832508b2002-03-02 17:04:07 +0000128 base = pParse->nTab++;
drhcce7d172000-05-31 15:34:51 +0000129 if( pWhere ){
drh832508b2002-03-02 17:04:07 +0000130 if( sqliteExprResolveIds(pParse, base, pTabList, 0, pWhere) ){
drhcce7d172000-05-31 15:34:51 +0000131 goto delete_from_cleanup;
132 }
133 if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
134 goto delete_from_cleanup;
135 }
136 }
137
138 /* Begin generating code.
139 */
drhd8bc7082000-06-07 23:51:50 +0000140 v = sqliteGetVdbe(pParse);
danielk1977f29ce552002-05-19 23:43:12 +0000141 if( v==0 ){
142 goto delete_from_cleanup;
143 }
drhcabb0812002-09-14 13:47:32 +0000144 sqliteBeginWriteOperation(pParse, row_triggers_exist,
drhd24cc422003-03-27 12:51:24 +0000145 !row_triggers_exist && pTab->iDb==1);
drh5e00f6c2001-09-13 13:46:56 +0000146
drh1bee3d72001-10-15 00:44:35 +0000147 /* Initialize the counter of the number of rows deleted, if
148 ** we are counting rows.
149 */
150 if( db->flags & SQLITE_CountRows ){
151 sqliteVdbeAddOp(v, OP_Integer, 0, 0);
152 }
drhcce7d172000-05-31 15:34:51 +0000153
drh0353ced2001-03-20 22:05:00 +0000154 /* Special case: A DELETE without a WHERE clause deletes everything.
drhc977f7f2002-05-21 11:38:11 +0000155 ** It is easier just to erase the whole table. Note, however, that
156 ** this means that the row change count will be incorrect.
drhcce7d172000-05-31 15:34:51 +0000157 */
danielk1977f29ce552002-05-19 23:43:12 +0000158 if( pWhere==0 && !row_triggers_exist ){
drh1bee3d72001-10-15 00:44:35 +0000159 if( db->flags & SQLITE_CountRows ){
160 /* If counting rows deleted, just count the total number of
161 ** entries in the table. */
162 int endOfLoop = sqliteVdbeMakeLabel(v);
163 int addr;
drhd24cc422003-03-27 12:51:24 +0000164 sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
drh001bbcb2003-03-19 03:14:00 +0000165 sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
drh26b3e1b2002-07-19 18:52:40 +0000166 sqliteVdbeAddOp(v, OP_Rewind, base, sqliteVdbeCurrentAddr(v)+2);
drh6b563442001-11-07 16:48:26 +0000167 addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
drh26b3e1b2002-07-19 18:52:40 +0000168 sqliteVdbeAddOp(v, OP_Next, base, addr);
drh1bee3d72001-10-15 00:44:35 +0000169 sqliteVdbeResolveLabel(v, endOfLoop);
drh26b3e1b2002-07-19 18:52:40 +0000170 sqliteVdbeAddOp(v, OP_Close, base, 0);
drh1bee3d72001-10-15 00:44:35 +0000171 }
drhd24cc422003-03-27 12:51:24 +0000172 sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
drh0353ced2001-03-20 22:05:00 +0000173 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
drhd24cc422003-03-27 12:51:24 +0000174 sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
drhcce7d172000-05-31 15:34:51 +0000175 }
176 }
drh0353ced2001-03-20 22:05:00 +0000177
178 /* The usual case: There is a WHERE clause so we have to scan through
179 ** the table an pick which records to delete.
180 */
181 else{
182 /* Begin the database scan
183 */
drhe3184742002-06-19 14:27:05 +0000184 pWInfo = sqliteWhereBegin(pParse, base, pTabList, pWhere, 1, 0);
drh0353ced2001-03-20 22:05:00 +0000185 if( pWInfo==0 ) goto delete_from_cleanup;
186
187 /* Remember the key of every item to be deleted.
188 */
drh99fcd712001-10-13 01:06:47 +0000189 sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
drh1bee3d72001-10-15 00:44:35 +0000190 if( db->flags & SQLITE_CountRows ){
191 sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
192 }
drh0353ced2001-03-20 22:05:00 +0000193
194 /* End the database scan loop.
195 */
196 sqliteWhereEnd(pWInfo);
197
198 /* Delete every item whose key was written to the list during the
199 ** database scan. We have to delete items after the scan is complete
200 ** because deleting an item can change the scan order.
201 */
drh99fcd712001-10-13 01:06:47 +0000202 sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000203 end = sqliteVdbeMakeLabel(v);
204
drhc977f7f2002-05-21 11:38:11 +0000205 /* This is the beginning of the delete loop when there are
206 ** row triggers.
207 */
danielk1977f29ce552002-05-19 23:43:12 +0000208 if( row_triggers_exist ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000209 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
210 sqliteVdbeAddOp(v, OP_Dup, 0, 0);
drhd24cc422003-03-27 12:51:24 +0000211 sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
drh001bbcb2003-03-19 03:14:00 +0000212 sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
danielk1977c3f9bad2002-05-15 08:30:12 +0000213 sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
214 sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
215
216 sqliteVdbeAddOp(v, OP_Integer, 13, 0);
drhc977f7f2002-05-21 11:38:11 +0000217 for(i = 0; i<pTab->nCol; i++){
218 if( i==pTab->iPKey ){
drh9adf9ac2002-05-15 11:44:13 +0000219 sqliteVdbeAddOp(v, OP_Recno, base, 0);
danielk1977f29ce552002-05-19 23:43:12 +0000220 } else {
drhc977f7f2002-05-21 11:38:11 +0000221 sqliteVdbeAddOp(v, OP_Column, base, i);
danielk1977f29ce552002-05-19 23:43:12 +0000222 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000223 }
224 sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
225 sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
226 sqliteVdbeAddOp(v, OP_Close, base, 0);
227 sqliteVdbeAddOp(v, OP_Rewind, oldIdx, 0);
228
229 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1,
danielk19776f349032002-06-11 02:25:40 +0000230 oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
231 addr);
danielk1977c3f9bad2002-05-15 08:30:12 +0000232 }
233
drhc977f7f2002-05-21 11:38:11 +0000234 /* Open cursors for the table we are deleting from and all its
235 ** indices. If there are row triggers, this happens inside the
236 ** OP_ListRead loop because the cursor have to all be closed
237 ** before the trigger fires. If there are no row triggers, the
238 ** cursors are opened only once on the outside the loop.
239 */
danielk1977c3f9bad2002-05-15 08:30:12 +0000240 pParse->nTab = base + 1;
drhd24cc422003-03-27 12:51:24 +0000241 sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
drh001bbcb2003-03-19 03:14:00 +0000242 sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
drh0353ced2001-03-20 22:05:00 +0000243 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
drhd24cc422003-03-27 12:51:24 +0000244 sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
drh001bbcb2003-03-19 03:14:00 +0000245 sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
drh0353ced2001-03-20 22:05:00 +0000246 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000247
drhc977f7f2002-05-21 11:38:11 +0000248 /* This is the beginning of the delete loop when there are no
249 ** row triggers */
danielk1977f29ce552002-05-19 23:43:12 +0000250 if( !row_triggers_exist ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000251 addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
danielk1977f29ce552002-05-19 23:43:12 +0000252 }
danielk1977c3f9bad2002-05-15 08:30:12 +0000253
drhc977f7f2002-05-21 11:38:11 +0000254 /* Delete the row */
drh38640e12002-07-05 21:42:36 +0000255 sqliteGenerateRowDelete(db, v, pTab, base, pParse->trigStack==0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000256
drhc977f7f2002-05-21 11:38:11 +0000257 /* If there are row triggers, close all cursors then invoke
258 ** the AFTER triggers
259 */
danielk1977f29ce552002-05-19 23:43:12 +0000260 if( row_triggers_exist ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000261 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
drh9adf9ac2002-05-15 11:44:13 +0000262 sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum);
danielk1977c3f9bad2002-05-15 08:30:12 +0000263 }
264 sqliteVdbeAddOp(v, OP_Close, base, 0);
265 sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1,
danielk19776f349032002-06-11 02:25:40 +0000266 oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
267 addr);
danielk1977c3f9bad2002-05-15 08:30:12 +0000268 }
269
drhc977f7f2002-05-21 11:38:11 +0000270 /* End of the delete loop */
drh99fcd712001-10-13 01:06:47 +0000271 sqliteVdbeAddOp(v, OP_Goto, 0, addr);
272 sqliteVdbeResolveLabel(v, end);
drha8b38d22001-11-01 14:41:34 +0000273 sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
danielk1977c3f9bad2002-05-15 08:30:12 +0000274
drhc977f7f2002-05-21 11:38:11 +0000275 /* Close the cursors after the loop if there are no row triggers */
danielk1977f29ce552002-05-19 23:43:12 +0000276 if( !row_triggers_exist ){
danielk1977c3f9bad2002-05-15 08:30:12 +0000277 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
drh9adf9ac2002-05-15 11:44:13 +0000278 sqliteVdbeAddOp(v, OP_Close, base + i, pIdx->tnum);
danielk1977c3f9bad2002-05-15 08:30:12 +0000279 }
280 sqliteVdbeAddOp(v, OP_Close, base, 0);
281 pParse->nTab = base;
282 }
drh0353ced2001-03-20 22:05:00 +0000283 }
drh1c928532002-01-31 15:54:21 +0000284 sqliteEndWriteOperation(pParse);
drh5e00f6c2001-09-13 13:46:56 +0000285
drh1bee3d72001-10-15 00:44:35 +0000286 /*
287 ** Return the number of rows that were deleted.
288 */
289 if( db->flags & SQLITE_CountRows ){
drh1bee3d72001-10-15 00:44:35 +0000290 sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
291 sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
292 sqliteVdbeAddOp(v, OP_Callback, 1, 0);
293 }
drhcce7d172000-05-31 15:34:51 +0000294
295delete_from_cleanup:
drhad3cab52002-05-24 02:04:32 +0000296 sqliteSrcListDelete(pTabList);
drhcce7d172000-05-31 15:34:51 +0000297 sqliteExprDelete(pWhere);
298 return;
299}
drh9cfcf5d2002-01-29 18:41:24 +0000300
301/*
302** This routine generates VDBE code that causes a single row of a
303** single table to be deleted.
304**
305** The VDBE must be in a particular state when this routine is called.
306** These are the requirements:
307**
308** 1. A read/write cursor pointing to pTab, the table containing the row
309** to be deleted, must be opened as cursor number "base".
310**
311** 2. Read/write cursors for all indices of pTab must be open as
312** cursor number base+i for the i-th index.
313**
314** 3. The record number of the row to be deleted must be on the top
315** of the stack.
316**
317** This routine pops the top of the stack to remove the record number
318** and then generates code to remove both the table record and all index
319** entries that point to that record.
320*/
321void sqliteGenerateRowDelete(
drh38640e12002-07-05 21:42:36 +0000322 sqlite *db, /* The database containing the index */
drh9cfcf5d2002-01-29 18:41:24 +0000323 Vdbe *v, /* Generate code into this VDBE */
324 Table *pTab, /* Table containing the row to be deleted */
drhc8d30ac2002-04-12 10:08:59 +0000325 int base, /* Cursor number for the table */
326 int count /* Increment the row change counter */
drh9cfcf5d2002-01-29 18:41:24 +0000327){
drh07d6e3a2002-05-23 12:50:18 +0000328 int addr;
329 addr = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
drh38640e12002-07-05 21:42:36 +0000330 sqliteGenerateRowIndexDelete(db, v, pTab, base, 0);
drhc8d30ac2002-04-12 10:08:59 +0000331 sqliteVdbeAddOp(v, OP_Delete, base, count);
drh07d6e3a2002-05-23 12:50:18 +0000332 sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
drh0ca3e242002-01-29 23:07:02 +0000333}
334
335/*
336** This routine generates VDBE code that causes the deletion of all
337** index entries associated with a single row of a single table.
338**
339** The VDBE must be in a particular state when this routine is called.
340** These are the requirements:
341**
342** 1. A read/write cursor pointing to pTab, the table containing the row
343** to be deleted, must be opened as cursor number "base".
344**
345** 2. Read/write cursors for all indices of pTab must be open as
346** cursor number base+i for the i-th index.
347**
348** 3. The "base" cursor must be pointing to the row that is to be
349** deleted.
350*/
351void sqliteGenerateRowIndexDelete(
drh38640e12002-07-05 21:42:36 +0000352 sqlite *db, /* The database containing the index */
drh0ca3e242002-01-29 23:07:02 +0000353 Vdbe *v, /* Generate code into this VDBE */
354 Table *pTab, /* Table containing the row to be deleted */
355 int base, /* Cursor number for the table */
356 char *aIdxUsed /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
357){
drh9cfcf5d2002-01-29 18:41:24 +0000358 int i;
359 Index *pIdx;
360
drh0ca3e242002-01-29 23:07:02 +0000361 for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
362 int j;
363 if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
364 sqliteVdbeAddOp(v, OP_Recno, base, 0);
365 for(j=0; j<pIdx->nColumn; j++){
366 int idx = pIdx->aiColumn[j];
367 if( idx==pTab->iPKey ){
368 sqliteVdbeAddOp(v, OP_Dup, j, 0);
369 }else{
370 sqliteVdbeAddOp(v, OP_Column, base, idx);
drh9cfcf5d2002-01-29 18:41:24 +0000371 }
drh9cfcf5d2002-01-29 18:41:24 +0000372 }
drh0ca3e242002-01-29 23:07:02 +0000373 sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
drh491791a2002-07-18 00:34:09 +0000374 if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
drh0ca3e242002-01-29 23:07:02 +0000375 sqliteVdbeAddOp(v, OP_IdxDelete, base+i, 0);
drh9cfcf5d2002-01-29 18:41:24 +0000376 }
drh9cfcf5d2002-01-29 18:41:24 +0000377}