wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Diagnostics;
3 using System.Text;
4  
5 using u8 = System.Byte;
6 using u32 = System.UInt32;
7  
8 namespace Community.CsharpSqlite
9 {
10 public partial class Sqlite3
11 {
12 /*
13 ** 2001 September 15
14 **
15 ** The author disclaims copyright to this source code. In place of
16 ** a legal notice, here is a blessing:
17 **
18 ** May you do good and not evil.
19 ** May you find forgiveness for yourself and forgive others.
20 ** May you share freely, never taking more than you give.
21 **
22 *************************************************************************
23 ** This file contains C code routines that are called by the parser
24 ** in order to generate code for DELETE FROM statements.
25 *************************************************************************
26 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
27 ** C#-SQLite is an independent reimplementation of the SQLite software library
28 **
29 ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
30 **
31 *************************************************************************
32 */
33 //#include "sqliteInt.h"
34  
35 /*
36 ** While a SrcList can in general represent multiple tables and subqueries
37 ** (as in the FROM clause of a SELECT statement) in this case it contains
38 ** the name of a single table, as one might find in an INSERT, DELETE,
39 ** or UPDATE statement. Look up that table in the symbol table and
40 ** return a pointer. Set an error message and return NULL if the table
41 ** name is not found or if any other error occurs.
42 **
43 ** The following fields are initialized appropriate in pSrc:
44 **
45 ** pSrc->a[0].pTab Pointer to the Table object
46 ** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one
47 **
48 */
49 static Table sqlite3SrcListLookup( Parse pParse, SrcList pSrc )
50 {
51 SrcList_item pItem = pSrc.a[0];
52 Table pTab;
53 Debug.Assert( pItem != null && pSrc.nSrc == 1 );
54 pTab = sqlite3LocateTable( pParse, 0, pItem.zName, pItem.zDatabase );
55 sqlite3DeleteTable( pParse.db, ref pItem.pTab );
56 pItem.pTab = pTab;
57 if ( pTab != null )
58 {
59 pTab.nRef++;
60 }
61 if ( sqlite3IndexedByLookup( pParse, pItem ) != 0 )
62 {
63 pTab = null;
64 }
65 return pTab;
66 }
67  
68 /*
69 ** Check to make sure the given table is writable. If it is not
70 ** writable, generate an error message and return 1. If it is
71 ** writable return 0;
72 */
73 static bool sqlite3IsReadOnly( Parse pParse, Table pTab, int viewOk )
74 {
75 /* A table is not writable under the following circumstances:
76 **
77 ** 1) It is a virtual table and no implementation of the xUpdate method
78 ** has been provided, or
79 ** 2) It is a system table (i.e. sqlite_master), this call is not
80 ** part of a nested parse and writable_schema pragma has not
81 ** been specified.
82 **
83 ** In either case leave an error message in pParse and return non-zero.
84 */
85 if (
86 ( IsVirtual( pTab )
87 && sqlite3GetVTable( pParse.db, pTab ).pMod.pModule.xUpdate == null )
88 || ( ( pTab.tabFlags & TF_Readonly ) != 0
89 && ( pParse.db.flags & SQLITE_WriteSchema ) == 0
90 && pParse.nested == 0 )
91 )
92 {
93 sqlite3ErrorMsg( pParse, "table %s may not be modified", pTab.zName );
94 return true;
95 }
96  
97 #if !SQLITE_OMIT_VIEW
98 if ( viewOk == 0 && pTab.pSelect != null )
99 {
100 sqlite3ErrorMsg( pParse, "cannot modify %s because it is a view", pTab.zName );
101 return true;
102 }
103 #endif
104 return false;
105 }
106  
107  
108 #if !SQLITE_OMIT_VIEW && !SQLITE_OMIT_TRIGGER
109 /*
110 ** Evaluate a view and store its result in an ephemeral table. The
111 ** pWhere argument is an optional WHERE clause that restricts the
112 ** set of rows in the view that are to be added to the ephemeral table.
113 */
114 static void sqlite3MaterializeView(
115 Parse pParse, /* Parsing context */
116 Table pView, /* View definition */
117 Expr pWhere, /* Optional WHERE clause to be added */
118 int iCur /* VdbeCursor number for ephemerial table */
119 )
120 {
121 SelectDest dest = new SelectDest();
122 Select pDup;
123 sqlite3 db = pParse.db;
124  
125 pDup = sqlite3SelectDup( db, pView.pSelect, 0 );
126 if ( pWhere != null )
127 {
128 SrcList pFrom;
129  
130 pWhere = sqlite3ExprDup( db, pWhere, 0 );
131 pFrom = sqlite3SrcListAppend( db, null, null, null );
132 //if ( pFrom != null )
133 //{
134 Debug.Assert( pFrom.nSrc == 1 );
135 pFrom.a[0].zAlias = pView.zName;// sqlite3DbStrDup( db, pView.zName );
136 pFrom.a[0].pSelect = pDup;
137 Debug.Assert( pFrom.a[0].pOn == null );
138 Debug.Assert( pFrom.a[0].pUsing == null );
139 //}
140 //else
141 //{
142 // sqlite3SelectDelete( db, ref pDup );
143 //}
144 pDup = sqlite3SelectNew( pParse, null, pFrom, pWhere, null, null, null, 0, null, null );
145 }
146 sqlite3SelectDestInit( dest, SRT_EphemTab, iCur );
147 sqlite3Select( pParse, pDup, ref dest );
148 sqlite3SelectDelete( db, ref pDup );
149 }
150 #endif //* !SQLITE_OMIT_VIEW) && !SQLITE_OMIT_TRIGGER) */
151  
152 #if (SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !(SQLITE_OMIT_SUBQUERY)
153 /*
154 ** Generate an expression tree to implement the WHERE, ORDER BY,
155 ** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
156 **
157 ** DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
158 ** \__________________________/
159 ** pLimitWhere (pInClause)
160 */
161 Expr sqlite3LimitWhere(
162 Parse pParse, /* The parser context */
163 SrcList pSrc, /* the FROM clause -- which tables to scan */
164 Expr pWhere, /* The WHERE clause. May be null */
165 ExprList pOrderBy, /* The ORDER BY clause. May be null */
166 Expr pLimit, /* The LIMIT clause. May be null */
167 Expr pOffset, /* The OFFSET clause. May be null */
168 char zStmtType /* Either DELETE or UPDATE. For error messages. */
169 ){
170 Expr pWhereRowid = null; /* WHERE rowid .. */
171 Expr pInClause = null; /* WHERE rowid IN ( select ) */
172 Expr pSelectRowid = null; /* SELECT rowid ... */
173 ExprList pEList = null; /* Expression list contaning only pSelectRowid */
174 SrcList pSelectSrc = null; /* SELECT rowid FROM x ... (dup of pSrc) */
175 Select pSelect = null; /* Complete SELECT tree */
176  
177 /* Check that there isn't an ORDER BY without a LIMIT clause.
178 */
179 if( pOrderBy!=null && (pLimit == null) ) {
180 sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
181 pParse.parseError = 1;
182 goto limit_where_cleanup_2;
183 }
184  
185 /* We only need to generate a select expression if there
186 ** is a limit/offset term to enforce.
187 */
188 if ( pLimit == null )
189 {
190 /* if pLimit is null, pOffset will always be null as well. */
191 Debug.Assert( pOffset == null );
192 return pWhere;
193 }
194  
195 /* Generate a select expression tree to enforce the limit/offset
196 ** term for the DELETE or UPDATE statement. For example:
197 ** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
198 ** becomes:
199 ** DELETE FROM table_a WHERE rowid IN (
200 ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
201 ** );
202 */
203  
204 pSelectRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
205 if( pSelectRowid == null ) goto limit_where_cleanup_2;
206 pEList = sqlite3ExprListAppend( pParse, null, pSelectRowid);
207 if( pEList == null ) goto limit_where_cleanup_2;
208  
209 /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
210 ** and the SELECT subtree. */
211 pSelectSrc = sqlite3SrcListDup(pParse.db, pSrc,0);
212 if( pSelectSrc == null ) {
213 sqlite3ExprListDelete(pParse.db, pEList);
214 goto limit_where_cleanup_2;
215 }
216  
217 /* generate the SELECT expression tree. */
218 pSelect = sqlite3SelectNew( pParse, pEList, pSelectSrc, pWhere, null, null,
219 pOrderBy, 0, pLimit, pOffset );
220 if( pSelect == null ) return null;
221  
222 /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
223 pWhereRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
224 if( pWhereRowid == null ) goto limit_where_cleanup_1;
225 pInClause = sqlite3PExpr( pParse, TK_IN, pWhereRowid, null, null );
226 if( pInClause == null ) goto limit_where_cleanup_1;
227  
228 pInClause->x.pSelect = pSelect;
229 pInClause->flags |= EP_xIsSelect;
230 sqlite3ExprSetHeight(pParse, pInClause);
231 return pInClause;
232  
233 /* something went wrong. clean up anything allocated. */
234 limit_where_cleanup_1:
235 sqlite3SelectDelete(pParse.db, pSelect);
236 return null;
237  
238 limit_where_cleanup_2:
239 sqlite3ExprDelete(pParse.db, ref pWhere);
240 sqlite3ExprListDelete(pParse.db, pOrderBy);
241 sqlite3ExprDelete(pParse.db, ref pLimit);
242 sqlite3ExprDelete(pParse.db, ref pOffset);
243 return null;
244 }
245 #endif //* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
246  
247 /*
248 ** Generate code for a DELETE FROM statement.
249 **
250 ** DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
251 ** \________/ \________________/
252 ** pTabList pWhere
253 */
254 static void sqlite3DeleteFrom(
255 Parse pParse, /* The parser context */
256 SrcList pTabList, /* The table from which we should delete things */
257 Expr pWhere /* The WHERE clause. May be null */
258 )
259 {
260 Vdbe v; /* The virtual database engine */
261 Table pTab; /* The table from which records will be deleted */
262 int end, addr = 0; /* A couple addresses of generated code */
263 int i; /* Loop counter */
264 WhereInfo pWInfo; /* Information about the WHERE clause */
265 Index pIdx; /* For looping over indices of the table */
266 int iCur; /* VDBE VdbeCursor number for pTab */
267 sqlite3 db; /* Main database structure */
268 NameContext sNC; /* Name context to resolve expressions in */
269 int iDb; /* Database number */
270 int memCnt = -1; /* Memory cell used for change counting */
271 int rcauth; /* Value returned by authorization callback */
272  
273 #if !SQLITE_OMIT_TRIGGER
274 bool isView; /* True if attempting to delete from a view */
275 Trigger pTrigger; /* List of table triggers, if required */
276 #endif
277 #if !SQLITE_OMIT_AUTHORIZATION
278 AuthContext sContext = new AuthContext();//memset(&sContext, 0, sizeof(sContext));
279 #endif
280  
281 db = pParse.db;
282 if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
283 {
284 goto delete_from_cleanup;
285 }
286 Debug.Assert( pTabList.nSrc == 1 );
287  
288 /* Locate the table which we want to delete. This table has to be
289 ** put in an SrcList structure because some of the subroutines we
290 ** will be calling are designed to work with multiple tables and expect
291 ** an SrcList* parameter instead of just a Table* parameter.
292 */
293 pTab = sqlite3SrcListLookup( pParse, pTabList );
294 if ( pTab == null )
295 goto delete_from_cleanup;
296  
297 /* Figure out if we have any triggers and if the table being
298 ** deleted from is a view
299 */
300 #if !SQLITE_OMIT_TRIGGER
301 int iDummy;
302 pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, out iDummy );
303 isView = pTab.pSelect != null;
304 #else
305 const Trigger pTrigger = null;
306 bool isView = false;
307 #endif
308 #if SQLITE_OMIT_VIEW
309 //# undef isView
310 isView = false;
311 #endif
312  
313 /* If pTab is really a view, make sure it has been initialized.
314 */
315 if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 )
316 {
317 goto delete_from_cleanup;
318 }
319  
320 if ( sqlite3IsReadOnly( pParse, pTab, ( pTrigger != null ? 1 : 0 ) ) )
321 {
322 goto delete_from_cleanup;
323 }
324 iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
325 Debug.Assert( iDb < db.nDb );
326 #if !SQLITE_OMIT_AUTHORIZATION
327 string zDb = db.aDb[iDb].zName;
328 rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
329 #else
330 rcauth = SQLITE_OK;
331 #endif
332 Debug.Assert( rcauth == SQLITE_OK || rcauth == SQLITE_DENY || rcauth == SQLITE_IGNORE );
333 if ( rcauth == SQLITE_DENY )
334 {
335 goto delete_from_cleanup;
336 }
337 Debug.Assert( !isView || pTrigger != null );
338  
339 /* Assign cursor number to the table and all its indices.
340 */
341 Debug.Assert( pTabList.nSrc == 1 );
342 iCur = pTabList.a[0].iCursor = pParse.nTab++;
343 for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
344 {
345 pParse.nTab++;
346 }
347  
348 #if !SQLITE_OMIT_AUTHORIZATION
349 /* Start the view context
350 */
351 if( isView ){
352 sqlite3AuthContextPush(pParse, sContext, pTab.zName);
353 }
354 #endif
355 /* Begin generating code.
356 */
357 v = sqlite3GetVdbe( pParse );
358 if ( v == null )
359 {
360 goto delete_from_cleanup;
361 }
362 if ( pParse.nested == 0 )
363 sqlite3VdbeCountChanges( v );
364 sqlite3BeginWriteOperation( pParse, 1, iDb );
365  
366 /* If we are trying to delete from a view, realize that view into
367 ** a ephemeral table.
368 */
369 #if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
370 if ( isView )
371 {
372 sqlite3MaterializeView( pParse, pTab, pWhere, iCur );
373 }
374 #endif
375 /* Resolve the column names in the WHERE clause.
376 */
377 sNC = new NameContext();// memset( &sNC, 0, sizeof( sNC ) );
378 sNC.pParse = pParse;
379 sNC.pSrcList = pTabList;
380 if ( sqlite3ResolveExprNames( sNC, ref pWhere ) != 0 )
381 {
382 goto delete_from_cleanup;
383 }
384  
385  
386 /* Initialize the counter of the number of rows deleted, if
387 ** we are counting rows.
388 */
389 if ( ( db.flags & SQLITE_CountRows ) != 0 )
390 {
391 memCnt = ++pParse.nMem;
392 sqlite3VdbeAddOp2( v, OP_Integer, 0, memCnt );
393 }
394  
395 #if !SQLITE_OMIT_TRUNCATE_OPTIMIZATION
396 /* Special case: A DELETE without a WHERE clause deletes everything.
397 ** It is easier just to erase the whole table. Prior to version 3.6.5,
398 ** this optimization caused the row change count (the value returned by
399 ** API function sqlite3_count_changes) to be set incorrectly. */
400 if ( rcauth == SQLITE_OK && pWhere == null && null == pTrigger && !IsVirtual( pTab )
401 && 0 == sqlite3FkRequired( pParse, pTab, null, 0 )
402 )
403 {
404 Debug.Assert( !isView );
405 sqlite3VdbeAddOp4( v, OP_Clear, pTab.tnum, iDb, memCnt,
406 pTab.zName, P4_STATIC );
407 for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
408 {
409 Debug.Assert( pIdx.pSchema == pTab.pSchema );
410 sqlite3VdbeAddOp2( v, OP_Clear, pIdx.tnum, iDb );
411 }
412 }
413 else
414 #endif //* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
415 /* The usual case: There is a WHERE clause so we have to scan through
416 ** the table and pick which records to delete.
417 */
418 {
419 int iRowSet = ++pParse.nMem; /* Register for rowset of rows to delete */
420 int iRowid = ++pParse.nMem; /* Used for storing rowid values. */
421 int regRowid; /* Actual register containing rowids */
422  
423 /* Collect rowids of every row to be deleted.
424 */
425 sqlite3VdbeAddOp2( v, OP_Null, 0, iRowSet );
426 ExprList elDummy = null;
427 pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref elDummy, WHERE_DUPLICATES_OK );
428 if ( pWInfo == null )
429 goto delete_from_cleanup;
430 regRowid = sqlite3ExprCodeGetColumn( pParse, pTab, -1, iCur, iRowid );
431 sqlite3VdbeAddOp2( v, OP_RowSetAdd, iRowSet, regRowid );
432 if ( ( db.flags & SQLITE_CountRows ) != 0 )
433 {
434 sqlite3VdbeAddOp2( v, OP_AddImm, memCnt, 1 );
435 }
436  
437 sqlite3WhereEnd( pWInfo );
438  
439 /* Delete every item whose key was written to the list during the
440 ** database scan. We have to delete items after the scan is complete
441 ** because deleting an item can change the scan order. */
442 end = sqlite3VdbeMakeLabel( v );
443  
444 /* Unless this is a view, open cursors for the table we are
445 ** deleting from and all its indices. If this is a view, then the
446 ** only effect this statement has is to fire the INSTEAD OF
447 ** triggers. */
448 if ( !isView )
449 {
450 sqlite3OpenTableAndIndices( pParse, pTab, iCur, OP_OpenWrite );
451 }
452  
453 addr = sqlite3VdbeAddOp3( v, OP_RowSetRead, iRowSet, end, iRowid );
454  
455 /* Delete the row */
456 #if !SQLITE_OMIT_VIRTUALTABLE
457 if ( IsVirtual( pTab ) )
458 {
459 VTable pVTab = sqlite3GetVTable( db, pTab );
460 sqlite3VtabMakeWritable( pParse, pTab );
461 sqlite3VdbeAddOp4( v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB );
462 sqlite3VdbeChangeP5( v, OE_Abort );
463 sqlite3MayAbort( pParse );
464 }
465 else
466 #endif
467 {
468 int count = ( pParse.nested == 0 ) ? 1 : 0; /* True to count changes */
469 sqlite3GenerateRowDelete( pParse, pTab, iCur, iRowid, count, pTrigger, OE_Default );
470 }
471  
472 /* End of the delete loop */
473 sqlite3VdbeAddOp2( v, OP_Goto, 0, addr );
474 sqlite3VdbeResolveLabel( v, end );
475  
476 /* Close the cursors open on the table and its indexes. */
477 if ( !isView && !IsVirtual( pTab ) )
478 {
479 for ( i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext )
480 {
481 sqlite3VdbeAddOp2( v, OP_Close, iCur + i, pIdx.tnum );
482 }
483 sqlite3VdbeAddOp1( v, OP_Close, iCur );
484 }
485 }
486  
487 /* Update the sqlite_sequence table by storing the content of the
488 ** maximum rowid counter values recorded while inserting into
489 ** autoincrement tables.
490 */
491 if ( pParse.nested == 0 && pParse.pTriggerTab == null )
492 {
493 sqlite3AutoincrementEnd( pParse );
494 }
495  
496 /* Return the number of rows that were deleted. If this routine is
497 ** generating code because of a call to sqlite3NestedParse(), do not
498 ** invoke the callback function.
499 */
500  
501 if ( ( db.flags & SQLITE_CountRows ) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab )
502 {
503 sqlite3VdbeAddOp2( v, OP_ResultRow, memCnt, 1 );
504 sqlite3VdbeSetNumCols( v, 1 );
505 sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC );
506 }
507  
508 delete_from_cleanup:
509 #if !SQLITE_OMIT_AUTHORIZATION
510 sqlite3AuthContextPop(sContext);
511 #endif
512 sqlite3SrcListDelete( db, ref pTabList );
513 sqlite3ExprDelete( db, ref pWhere );
514 return;
515 }
516  
517 /* Make sure "isView" and other macros defined above are undefined. Otherwise
518 ** thely may interfere with compilation of other functions in this file
519 ** (or in another file, if this file becomes part of the amalgamation). */
520 //#if isView
521 // #undef isView
522 //#endif
523 //#if pTrigger
524 // #undef pTrigger
525 //#endif
526  
527 /*
528 ** This routine generates VDBE code that causes a single row of a
529 ** single table to be deleted.
530 **
531 ** The VDBE must be in a particular state when this routine is called.
532 ** These are the requirements:
533 **
534 ** 1. A read/write cursor pointing to pTab, the table containing the row
535 ** to be deleted, must be opened as cursor number $iCur.
536 **
537 ** 2. Read/write cursors for all indices of pTab must be open as
538 ** cursor number base+i for the i-th index.
539 **
540 ** 3. The record number of the row to be deleted must be stored in
541 ** memory cell iRowid.
542 **
543 ** This routine generates code to remove both the table record and all
544 ** index entries that point to that record.
545 */
546 static void sqlite3GenerateRowDelete(
547 Parse pParse, /* Parsing context */
548 Table pTab, /* Table containing the row to be deleted */
549 int iCur, /* VdbeCursor number for the table */
550 int iRowid, /* Memory cell that contains the rowid to delete */
551 int count, /* If non-zero, increment the row change counter */
552 Trigger pTrigger, /* List of triggers to (potentially) fire */
553 int onconf /* Default ON CONFLICT policy for triggers */
554 )
555 {
556 Vdbe v = pParse.pVdbe; /* Vdbe */
557 int iOld = 0; /* First register in OLD.* array */
558 int iLabel; /* Label resolved to end of generated code */
559  
560 /* Vdbe is guaranteed to have been allocated by this stage. */
561 Debug.Assert( v != null );
562  
563 /* Seek cursor iCur to the row to delete. If this row no longer exists
564 ** (this can happen if a trigger program has already deleted it), do
565 ** not attempt to delete it or fire any DELETE triggers. */
566 iLabel = sqlite3VdbeMakeLabel( v );
567 sqlite3VdbeAddOp3( v, OP_NotExists, iCur, iLabel, iRowid );
568  
569 /* If there are any triggers to fire, allocate a range of registers to
570 ** use for the old.* references in the triggers. */
571 if ( sqlite3FkRequired( pParse, pTab, null, 0 ) != 0 || pTrigger != null )
572 {
573 u32 mask; /* Mask of OLD.* columns in use */
574 int iCol; /* Iterator used while populating OLD.* */
575  
576 /* TODO: Could use temporary registers here. Also could attempt to
577 ** avoid copying the contents of the rowid register. */
578 mask = sqlite3TriggerColmask(
579 pParse, pTrigger, null, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onconf
580 );
581 mask |= sqlite3FkOldmask( pParse, pTab );
582 iOld = pParse.nMem + 1;
583 pParse.nMem += ( 1 + pTab.nCol );
584  
585 /* Populate the OLD.* pseudo-table register array. These values will be
586 ** used by any BEFORE and AFTER triggers that exist. */
587 sqlite3VdbeAddOp2( v, OP_Copy, iRowid, iOld );
588 for ( iCol = 0; iCol < pTab.nCol; iCol++ )
589 {
590 if ( mask == 0xffffffff || ( mask & ( 1 << iCol ) ) != 0 )
591 {
592 sqlite3ExprCodeGetColumnOfTable( v, pTab, iCur, iCol, iOld + iCol + 1 );
593 }
594 }
595  
596 /* Invoke BEFORE DELETE trigger programs. */
597 sqlite3CodeRowTrigger( pParse, pTrigger,
598 TK_DELETE, null, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
599 );
600  
601 /* Seek the cursor to the row to be deleted again. It may be that
602 ** the BEFORE triggers coded above have already removed the row
603 ** being deleted. Do not attempt to delete the row a second time, and
604 ** do not fire AFTER triggers. */
605 sqlite3VdbeAddOp3( v, OP_NotExists, iCur, iLabel, iRowid );
606  
607 /* Do FK processing. This call checks that any FK constraints that
608 ** refer to this table (i.e. constraints attached to other tables)
609 ** are not violated by deleting this row. */
610 sqlite3FkCheck( pParse, pTab, iOld, 0 );
611 }
612  
613 /* Delete the index and table entries. Skip this step if pTab is really
614 ** a view (in which case the only effect of the DELETE statement is to
615 ** fire the INSTEAD OF triggers). */
616 if ( pTab.pSelect == null )
617 {
618 sqlite3GenerateRowIndexDelete( pParse, pTab, iCur, 0 );
619 sqlite3VdbeAddOp2( v, OP_Delete, iCur, ( count != 0 ? (int)OPFLAG_NCHANGE : 0 ) );
620 if ( count != 0 )
621 {
622 sqlite3VdbeChangeP4( v, -1, pTab.zName, P4_TRANSIENT );
623 }
624 }
625  
626 /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
627 ** handle rows (possibly in other tables) that refer via a foreign key
628 ** to the row just deleted. */
629 sqlite3FkActions( pParse, pTab, null, iOld );
630  
631 /* Invoke AFTER DELETE trigger programs. */
632 sqlite3CodeRowTrigger( pParse, pTrigger,
633 TK_DELETE, null, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
634 );
635  
636 /* Jump here if the row had already been deleted before any BEFORE
637 ** trigger programs were invoked. Or if a trigger program throws a
638 ** RAISE(IGNORE) exception. */
639 sqlite3VdbeResolveLabel( v, iLabel );
640 }
641  
642  
643 /*
644 ** This routine generates VDBE code that causes the deletion of all
645 ** index entries associated with a single row of a single table.
646 **
647 ** The VDBE must be in a particular state when this routine is called.
648 ** These are the requirements:
649 **
650 ** 1. A read/write cursor pointing to pTab, the table containing the row
651 ** to be deleted, must be opened as cursor number "iCur".
652 **
653 ** 2. Read/write cursors for all indices of pTab must be open as
654 ** cursor number iCur+i for the i-th index.
655 **
656 ** 3. The "iCur" cursor must be pointing to the row that is to be
657 ** deleted.
658 */
659 static void sqlite3GenerateRowIndexDelete(
660 Parse pParse, /* Parsing and code generating context */
661 Table pTab, /* Table containing the row to be deleted */
662 int iCur, /* VdbeCursor number for the table */
663 int nothing /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
664 )
665 {
666 int[] aRegIdx = null;
667 sqlite3GenerateRowIndexDelete( pParse, pTab, iCur, aRegIdx );
668 }
669 static void sqlite3GenerateRowIndexDelete(
670 Parse pParse, /* Parsing and code generating context */
671 Table pTab, /* Table containing the row to be deleted */
672 int iCur, /* VdbeCursor number for the table */
673 int[] aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
674 )
675 {
676 int i;
677 Index pIdx;
678 int r1;
679  
680 for ( i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext )
681 {
682 if ( aRegIdx != null && aRegIdx[i - 1] == 0 )
683 continue;
684 r1 = sqlite3GenerateIndexKey( pParse, pIdx, iCur, 0, false );
685 sqlite3VdbeAddOp3( pParse.pVdbe, OP_IdxDelete, iCur + i, r1, pIdx.nColumn + 1 );
686 }
687 }
688  
689 /*
690 ** Generate code that will assemble an index key and put it in register
691 ** regOut. The key with be for index pIdx which is an index on pTab.
692 ** iCur is the index of a cursor open on the pTab table and pointing to
693 ** the entry that needs indexing.
694 **
695 ** Return a register number which is the first in a block of
696 ** registers that holds the elements of the index key. The
697 ** block of registers has already been deallocated by the time
698 ** this routine returns.
699 */
700 static int sqlite3GenerateIndexKey(
701 Parse pParse, /* Parsing context */
702 Index pIdx, /* The index for which to generate a key */
703 int iCur, /* VdbeCursor number for the pIdx.pTable table */
704 int regOut, /* Write the new index key to this register */
705 bool doMakeRec /* Run the OP_MakeRecord instruction if true */
706 )
707 {
708 Vdbe v = pParse.pVdbe;
709 int j;
710 Table pTab = pIdx.pTable;
711 int regBase;
712 int nCol;
713  
714 nCol = pIdx.nColumn;
715 regBase = sqlite3GetTempRange( pParse, nCol + 1 );
716 sqlite3VdbeAddOp2( v, OP_Rowid, iCur, regBase + nCol );
717 for ( j = 0; j < nCol; j++ )
718 {
719 int idx = pIdx.aiColumn[j];
720 if ( idx == pTab.iPKey )
721 {
722 sqlite3VdbeAddOp2( v, OP_SCopy, regBase + nCol, regBase + j );
723 }
724 else
725 {
726 sqlite3VdbeAddOp3( v, OP_Column, iCur, idx, regBase + j );
727 sqlite3ColumnDefault( v, pTab, idx, -1 );
728 }
729 }
730 if ( doMakeRec )
731 {
732 string zAff;
733 if ( pTab.pSelect != null|| ( pParse.db.flags & SQLITE_IdxRealAsInt ) != 0 )
734 {
735 zAff = string.Empty;
736 }
737 else
738 {
739 zAff = sqlite3IndexAffinityStr( v, pIdx );
740 }
741 sqlite3VdbeAddOp3( v, OP_MakeRecord, regBase, nCol + 1, regOut );
742 sqlite3VdbeChangeP4( v, -1, zAff, P4_TRANSIENT );
743 }
744 sqlite3ReleaseTempRange( pParse, regBase, nCol + 1 );
745 return regBase;
746 }
747 }
748 }