wasCSharpSQLite – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Diagnostics; |
||
3 | |||
4 | using u8 = System.Byte; |
||
5 | using u32 = System.UInt32; |
||
6 | |||
7 | namespace Community.CsharpSqlite |
||
8 | { |
||
9 | using sqlite3_value = Sqlite3.Mem; |
||
10 | |||
11 | public partial class Sqlite3 |
||
12 | { |
||
13 | /* |
||
14 | ** 2001 September 15 |
||
15 | ** |
||
16 | ** The author disclaims copyright to this source code. In place of |
||
17 | ** a legal notice, here is a blessing: |
||
18 | ** |
||
19 | ** May you do good and not evil. |
||
20 | ** May you find forgiveness for yourself and forgive others. |
||
21 | ** May you share freely, never taking more than you give. |
||
22 | ** |
||
23 | ************************************************************************* |
||
24 | ** This file contains C code routines that are called by the parser |
||
25 | ** to handle UPDATE statements. |
||
26 | ************************************************************************* |
||
27 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
28 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
29 | ** |
||
30 | ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2 |
||
31 | ** |
||
32 | ************************************************************************* |
||
33 | */ |
||
34 | //#include "sqliteInt.h" |
||
35 | |||
36 | #if !SQLITE_OMIT_VIRTUALTABLE |
||
37 | /* Forward declaration */ |
||
38 | //static void updateVirtualTable( |
||
39 | //Parse pParse, /* The parsing context */ |
||
40 | //SrcList pSrc, /* The virtual table to be modified */ |
||
41 | //Table pTab, /* The virtual table */ |
||
42 | //ExprList pChanges, /* The columns to change in the UPDATE statement */ |
||
43 | //Expr pRowidExpr, /* Expression used to recompute the rowid */ |
||
44 | //int aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
||
45 | //Expr *pWhere, /* WHERE clause of the UPDATE statement */ |
||
46 | //int onError /* ON CONFLICT strategy */ |
||
47 | //); |
||
48 | #endif // * SQLITE_OMIT_VIRTUALTABLE */ |
||
49 | |||
50 | /* |
||
51 | ** The most recently coded instruction was an OP_Column to retrieve the |
||
52 | ** i-th column of table pTab. This routine sets the P4 parameter of the |
||
53 | ** OP_Column to the default value, if any. |
||
54 | ** |
||
55 | ** The default value of a column is specified by a DEFAULT clause in the |
||
56 | ** column definition. This was either supplied by the user when the table |
||
57 | ** was created, or added later to the table definition by an ALTER TABLE |
||
58 | ** command. If the latter, then the row-records in the table btree on disk |
||
59 | ** may not contain a value for the column and the default value, taken |
||
60 | ** from the P4 parameter of the OP_Column instruction, is returned instead. |
||
61 | ** If the former, then all row-records are guaranteed to include a value |
||
62 | ** for the column and the P4 value is not required. |
||
63 | ** |
||
64 | ** Column definitions created by an ALTER TABLE command may only have |
||
65 | ** literal default values specified: a number, null or a string. (If a more |
||
66 | ** complicated default expression value was provided, it is evaluated |
||
67 | ** when the ALTER TABLE is executed and one of the literal values written |
||
68 | ** into the sqlite_master table.) |
||
69 | ** |
||
70 | ** Therefore, the P4 parameter is only required if the default value for |
||
71 | ** the column is a literal number, string or null. The sqlite3ValueFromExpr() |
||
72 | ** function is capable of transforming these types of expressions into |
||
73 | ** sqlite3_value objects. |
||
74 | ** |
||
75 | ** If parameter iReg is not negative, code an OP_RealAffinity instruction |
||
76 | ** on register iReg. This is used when an equivalent integer value is |
||
77 | ** stored in place of an 8-byte floating point value in order to save |
||
78 | ** space. |
||
79 | */ |
||
80 | static void sqlite3ColumnDefault( Vdbe v, Table pTab, int i, int iReg ) |
||
81 | { |
||
82 | Debug.Assert( pTab != null ); |
||
83 | if ( null == pTab.pSelect ) |
||
84 | { |
||
85 | sqlite3_value pValue = new sqlite3_value(); |
||
86 | int enc = ENC( sqlite3VdbeDb( v ) ); |
||
87 | Column pCol = pTab.aCol[i]; |
||
88 | #if SQLITE_DEBUG |
||
89 | VdbeComment( v, "%s.%s", pTab.zName, pCol.zName ); |
||
90 | #endif |
||
91 | Debug.Assert( i < pTab.nCol ); |
||
92 | sqlite3ValueFromExpr( sqlite3VdbeDb( v ), pCol.pDflt, enc, |
||
93 | pCol.affinity, ref pValue ); |
||
94 | if ( pValue != null ) |
||
95 | { |
||
96 | sqlite3VdbeChangeP4( v, -1, pValue, P4_MEM ); |
||
97 | } |
||
98 | #if !SQLITE_OMIT_FLOATING_POINT |
||
99 | if ( iReg >= 0 && pTab.aCol[i].affinity == SQLITE_AFF_REAL ) |
||
100 | { |
||
101 | sqlite3VdbeAddOp1( v, OP_RealAffinity, iReg ); |
||
102 | } |
||
103 | #endif |
||
104 | } |
||
105 | } |
||
106 | |||
107 | /* |
||
108 | ** Process an UPDATE statement. |
||
109 | ** |
||
110 | ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; |
||
111 | ** \_______/ \________/ \______/ \________________/ |
||
112 | * onError pTabList pChanges pWhere |
||
113 | */ |
||
114 | static void sqlite3Update( |
||
115 | Parse pParse, /* The parser context */ |
||
116 | SrcList pTabList, /* The table in which we should change things */ |
||
117 | ExprList pChanges, /* Things to be changed */ |
||
118 | Expr pWhere, /* The WHERE clause. May be null */ |
||
119 | int onError /* How to handle constraint errors */ |
||
120 | ) |
||
121 | { |
||
122 | int i, j; /* Loop counters */ |
||
123 | Table pTab; /* The table to be updated */ |
||
124 | int addr = 0; /* VDBE instruction address of the start of the loop */ |
||
125 | WhereInfo pWInfo; /* Information about the WHERE clause */ |
||
126 | Vdbe v; /* The virtual database engine */ |
||
127 | Index pIdx; /* For looping over indices */ |
||
128 | int nIdx; /* Number of indices that need updating */ |
||
129 | int iCur; /* VDBE Cursor number of pTab */ |
||
130 | sqlite3 db; /* The database structure */ |
||
131 | int[] aRegIdx = null; /* One register assigned to each index to be updated */ |
||
132 | int[] aXRef = null; /* aXRef[i] is the index in pChanges.a[] of the |
||
133 | ** an expression for the i-th column of the table. |
||
134 | ** aXRef[i]==-1 if the i-th column is not changed. */ |
||
135 | bool chngRowid; /* True if the record number is being changed */ |
||
136 | Expr pRowidExpr = null; /* Expression defining the new record number */ |
||
137 | bool openAll = false; /* True if all indices need to be opened */ |
||
138 | AuthContext sContext; /* The authorization context */ |
||
139 | NameContext sNC; /* The name-context to resolve expressions in */ |
||
140 | int iDb; /* Database containing the table being updated */ |
||
141 | bool okOnePass; /* True for one-pass algorithm without the FIFO */ |
||
142 | bool hasFK; /* True if foreign key processing is required */ |
||
143 | |||
144 | #if !SQLITE_OMIT_TRIGGER |
||
145 | bool isView; /* True when updating a view (INSTEAD OF trigger) */ |
||
146 | Trigger pTrigger; /* List of triggers on pTab, if required */ |
||
147 | int tmask = 0; /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */ |
||
148 | #endif |
||
149 | int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */ |
||
150 | |||
151 | /* Register Allocations */ |
||
152 | int regRowCount = 0; /* A count of rows changed */ |
||
153 | int regOldRowid; /* The old rowid */ |
||
154 | int regNewRowid; /* The new rowid */ |
||
155 | int regNew; |
||
156 | int regOld = 0; |
||
157 | int regRowSet = 0; /* Rowset of rows to be updated */ |
||
158 | |||
159 | sContext = new AuthContext(); //memset( &sContext, 0, sizeof( sContext ) ); |
||
160 | db = pParse.db; |
||
161 | if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ ) |
||
162 | { |
||
163 | goto update_cleanup; |
||
164 | } |
||
165 | Debug.Assert( pTabList.nSrc == 1 ); |
||
166 | |||
167 | /* Locate the table which we want to update. |
||
168 | */ |
||
169 | pTab = sqlite3SrcListLookup( pParse, pTabList ); |
||
170 | if ( pTab == null ) |
||
171 | goto update_cleanup; |
||
172 | iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema ); |
||
173 | |||
174 | /* Figure out if we have any triggers and if the table being |
||
175 | ** updated is a view. |
||
176 | */ |
||
177 | #if !SQLITE_OMIT_TRIGGER |
||
178 | pTrigger = sqlite3TriggersExist( pParse, pTab, TK_UPDATE, pChanges, out tmask ); |
||
179 | isView = pTab.pSelect != null; |
||
180 | Debug.Assert( pTrigger != null || tmask == 0 ); |
||
181 | #else |
||
182 | const Trigger pTrigger = null;//# define pTrigger 0 |
||
183 | const int tmask = 0; //# define tmask 0 |
||
184 | #endif |
||
185 | #if SQLITE_OMIT_TRIGGER || SQLITE_OMIT_VIEW |
||
186 | // # undef isView |
||
187 | const bool isView = false; //# define isView 0 |
||
188 | #endif |
||
189 | |||
190 | if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 ) |
||
191 | { |
||
192 | goto update_cleanup; |
||
193 | } |
||
194 | if ( sqlite3IsReadOnly( pParse, pTab, tmask ) ) |
||
195 | { |
||
196 | goto update_cleanup; |
||
197 | } |
||
198 | aXRef = new int[pTab.nCol];// sqlite3DbMallocRaw(db, sizeof(int) * pTab.nCol); |
||
199 | //if ( aXRef == null ) goto update_cleanup; |
||
200 | for ( i = 0; i < pTab.nCol; i++ ) |
||
201 | aXRef[i] = -1; |
||
202 | |||
203 | /* Allocate a cursors for the main database table and for all indices. |
||
204 | ** The index cursors might not be used, but if they are used they |
||
205 | ** need to occur right after the database cursor. So go ahead and |
||
206 | ** allocate enough space, just in case. |
||
207 | */ |
||
208 | pTabList.a[0].iCursor = iCur = pParse.nTab++; |
||
209 | for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext ) |
||
210 | { |
||
211 | pParse.nTab++; |
||
212 | } |
||
213 | |||
214 | /* Initialize the name-context */ |
||
215 | sNC = new NameContext();// memset(&sNC, 0, sNC).Length; |
||
216 | sNC.pParse = pParse; |
||
217 | sNC.pSrcList = pTabList; |
||
218 | |||
219 | /* Resolve the column names in all the expressions of the |
||
220 | ** of the UPDATE statement. Also find the column index |
||
221 | ** for each column to be updated in the pChanges array. For each |
||
222 | ** column to be updated, make sure we have authorization to change |
||
223 | ** that column. |
||
224 | */ |
||
225 | chngRowid = false; |
||
226 | for ( i = 0; i < pChanges.nExpr; i++ ) |
||
227 | { |
||
228 | if ( sqlite3ResolveExprNames( sNC, ref pChanges.a[i].pExpr ) != 0 ) |
||
229 | { |
||
230 | goto update_cleanup; |
||
231 | } |
||
232 | for ( j = 0; j < pTab.nCol; j++ ) |
||
233 | { |
||
234 | if ( pTab.aCol[j].zName.Equals( pChanges.a[i].zName, StringComparison.OrdinalIgnoreCase ) ) |
||
235 | { |
||
236 | if ( j == pTab.iPKey ) |
||
237 | { |
||
238 | chngRowid = true; |
||
239 | pRowidExpr = pChanges.a[i].pExpr; |
||
240 | } |
||
241 | aXRef[j] = i; |
||
242 | break; |
||
243 | } |
||
244 | } |
||
245 | if ( j >= pTab.nCol ) |
||
246 | { |
||
247 | if ( sqlite3IsRowid( pChanges.a[i].zName ) ) |
||
248 | { |
||
249 | chngRowid = true; |
||
250 | pRowidExpr = pChanges.a[i].pExpr; |
||
251 | } |
||
252 | else |
||
253 | { |
||
254 | sqlite3ErrorMsg( pParse, "no such column: %s", pChanges.a[i].zName ); |
||
255 | pParse.checkSchema = 1; |
||
256 | goto update_cleanup; |
||
257 | } |
||
258 | } |
||
259 | #if !SQLITE_OMIT_AUTHORIZATION |
||
260 | { |
||
261 | int rc; |
||
262 | rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab.zName, |
||
263 | pTab.aCol[j].zName, db.aDb[iDb].zName); |
||
264 | if( rc==SQLITE_DENY ){ |
||
265 | goto update_cleanup; |
||
266 | }else if( rc==SQLITE_IGNORE ){ |
||
267 | aXRef[j] = -1; |
||
268 | } |
||
269 | } |
||
270 | #endif |
||
271 | } |
||
272 | |||
273 | hasFK = sqlite3FkRequired( pParse, pTab, aXRef, chngRowid ? 1 : 0 ) != 0; |
||
274 | |||
275 | /* Allocate memory for the array aRegIdx[]. There is one entry in the |
||
276 | ** array for each index associated with table being updated. Fill in |
||
277 | ** the value with a register number for indices that are to be used |
||
278 | ** and with zero for unused indices. |
||
279 | */ |
||
280 | for ( nIdx = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, nIdx++ ) |
||
281 | { |
||
282 | } |
||
283 | if ( nIdx > 0 ) |
||
284 | { |
||
285 | aRegIdx = new int[nIdx]; // sqlite3DbMallocRaw(db, Index*.Length * nIdx); |
||
286 | if ( aRegIdx == null ) |
||
287 | goto update_cleanup; |
||
288 | } |
||
289 | for ( j = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, j++ ) |
||
290 | { |
||
291 | int reg; |
||
292 | if ( hasFK || chngRowid ) |
||
293 | { |
||
294 | reg = ++pParse.nMem; |
||
295 | } |
||
296 | else |
||
297 | { |
||
298 | reg = 0; |
||
299 | for ( i = 0; i < pIdx.nColumn; i++ ) |
||
300 | { |
||
301 | if ( aXRef[pIdx.aiColumn[i]] >= 0 ) |
||
302 | { |
||
303 | reg = ++pParse.nMem; |
||
304 | break; |
||
305 | } |
||
306 | } |
||
307 | } |
||
308 | aRegIdx[j] = reg; |
||
309 | } |
||
310 | |||
311 | /* Begin generating code. */ |
||
312 | v = sqlite3GetVdbe( pParse ); |
||
313 | if ( v == null ) |
||
314 | goto update_cleanup; |
||
315 | if ( pParse.nested == 0 ) |
||
316 | sqlite3VdbeCountChanges( v ); |
||
317 | sqlite3BeginWriteOperation( pParse, 1, iDb ); |
||
318 | |||
319 | #if !SQLITE_OMIT_VIRTUALTABLE |
||
320 | /* Virtual tables must be handled separately */ |
||
321 | if ( IsVirtual( pTab ) ) |
||
322 | { |
||
323 | updateVirtualTable( pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, |
||
324 | pWhere, onError ); |
||
325 | pWhere = null; |
||
326 | pTabList = null; |
||
327 | goto update_cleanup; |
||
328 | } |
||
329 | #endif |
||
330 | |||
331 | /* Allocate required registers. */ |
||
332 | regOldRowid = regNewRowid = ++pParse.nMem; |
||
333 | if ( pTrigger != null || hasFK ) |
||
334 | { |
||
335 | regOld = pParse.nMem + 1; |
||
336 | pParse.nMem += pTab.nCol; |
||
337 | } |
||
338 | if ( chngRowid || pTrigger != null || hasFK ) |
||
339 | { |
||
340 | regNewRowid = ++pParse.nMem; |
||
341 | } |
||
342 | regNew = pParse.nMem + 1; |
||
343 | pParse.nMem += pTab.nCol; |
||
344 | |||
345 | /* Start the view context. */ |
||
346 | if ( isView ) |
||
347 | { |
||
348 | sqlite3AuthContextPush( pParse, sContext, pTab.zName ); |
||
349 | } |
||
350 | |||
351 | /* If we are trying to update a view, realize that view into |
||
352 | ** a ephemeral table. |
||
353 | */ |
||
354 | #if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER) |
||
355 | if ( isView ) |
||
356 | { |
||
357 | sqlite3MaterializeView( pParse, pTab, pWhere, iCur ); |
||
358 | } |
||
359 | #endif |
||
360 | |||
361 | /* Resolve the column names in all the expressions in the |
||
362 | ** WHERE clause. |
||
363 | */ |
||
364 | if ( sqlite3ResolveExprNames( sNC, ref pWhere ) != 0 ) |
||
365 | { |
||
366 | goto update_cleanup; |
||
367 | } |
||
368 | |||
369 | /* Begin the database scan |
||
370 | */ |
||
371 | sqlite3VdbeAddOp2( v, OP_Null, 0, regOldRowid ); |
||
372 | ExprList NullOrderby = null; |
||
373 | pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref NullOrderby, WHERE_ONEPASS_DESIRED ); |
||
374 | if ( pWInfo == null ) |
||
375 | goto update_cleanup; |
||
376 | okOnePass = pWInfo.okOnePass != 0; |
||
377 | |||
378 | /* Remember the rowid of every item to be updated. |
||
379 | */ |
||
380 | sqlite3VdbeAddOp2( v, OP_Rowid, iCur, regOldRowid ); |
||
381 | if ( !okOnePass ) |
||
382 | { |
||
383 | regRowSet = ++pParse.nMem; |
||
384 | sqlite3VdbeAddOp2( v, OP_RowSetAdd, regRowSet, regOldRowid ); |
||
385 | } |
||
386 | |||
387 | /* End the database scan loop. |
||
388 | */ |
||
389 | sqlite3WhereEnd( pWInfo ); |
||
390 | |||
391 | /* Initialize the count of updated rows |
||
392 | */ |
||
393 | if ( ( db.flags & SQLITE_CountRows ) != 0 && null == pParse.pTriggerTab ) |
||
394 | { |
||
395 | regRowCount = ++pParse.nMem; |
||
396 | sqlite3VdbeAddOp2( v, OP_Integer, 0, regRowCount ); |
||
397 | } |
||
398 | |||
399 | if ( !isView ) |
||
400 | { |
||
401 | /* |
||
402 | ** Open every index that needs updating. Note that if any |
||
403 | ** index could potentially invoke a REPLACE conflict resolution |
||
404 | ** action, then we need to open all indices because we might need |
||
405 | ** to be deleting some records. |
||
406 | */ |
||
407 | if ( !okOnePass ) |
||
408 | sqlite3OpenTable( pParse, iCur, iDb, pTab, OP_OpenWrite ); |
||
409 | if ( onError == OE_Replace ) |
||
410 | { |
||
411 | openAll = true; |
||
412 | } |
||
413 | else |
||
414 | { |
||
415 | openAll = false; |
||
416 | for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext ) |
||
417 | { |
||
418 | if ( pIdx.onError == OE_Replace ) |
||
419 | { |
||
420 | openAll = true; |
||
421 | break; |
||
422 | } |
||
423 | } |
||
424 | } |
||
425 | for ( i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++ ) |
||
426 | { |
||
427 | if ( openAll || aRegIdx[i] > 0 ) |
||
428 | { |
||
429 | KeyInfo pKey = sqlite3IndexKeyinfo( pParse, pIdx ); |
||
430 | sqlite3VdbeAddOp4( v, OP_OpenWrite, iCur + i + 1, pIdx.tnum, iDb, |
||
431 | pKey, P4_KEYINFO_HANDOFF ); |
||
432 | Debug.Assert( pParse.nTab > iCur + i + 1 ); |
||
433 | } |
||
434 | } |
||
435 | } |
||
436 | |||
437 | /* Top of the update loop */ |
||
438 | if ( okOnePass ) |
||
439 | { |
||
440 | int a1 = sqlite3VdbeAddOp1( v, OP_NotNull, regOldRowid ); |
||
441 | addr = sqlite3VdbeAddOp0( v, OP_Goto ); |
||
442 | sqlite3VdbeJumpHere( v, a1 ); |
||
443 | } |
||
444 | else |
||
445 | { |
||
446 | addr = sqlite3VdbeAddOp3( v, OP_RowSetRead, regRowSet, 0, regOldRowid ); |
||
447 | } |
||
448 | |||
449 | /* Make cursor iCur point to the record that is being updated. If |
||
450 | ** this record does not exist for some reason (deleted by a trigger, |
||
451 | ** for example, then jump to the next iteration of the RowSet loop. */ |
||
452 | sqlite3VdbeAddOp3( v, OP_NotExists, iCur, addr, regOldRowid ); |
||
453 | |||
454 | /* If the record number will change, set register regNewRowid to |
||
455 | ** contain the new value. If the record number is not being modified, |
||
456 | ** then regNewRowid is the same register as regOldRowid, which is |
||
457 | ** already populated. */ |
||
458 | Debug.Assert( chngRowid || pTrigger != null || hasFK || regOldRowid == regNewRowid ); |
||
459 | if ( chngRowid ) |
||
460 | { |
||
461 | sqlite3ExprCode( pParse, pRowidExpr, regNewRowid ); |
||
462 | sqlite3VdbeAddOp1( v, OP_MustBeInt, regNewRowid ); |
||
463 | } |
||
464 | |||
465 | /* If there are triggers on this table, populate an array of registers |
||
466 | ** with the required old.* column data. */ |
||
467 | if ( hasFK || pTrigger != null ) |
||
468 | { |
||
469 | u32 oldmask = ( hasFK ? sqlite3FkOldmask( pParse, pTab ) : 0 ); |
||
470 | oldmask |= sqlite3TriggerColmask( pParse, |
||
471 | pTrigger, pChanges, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onError |
||
472 | ); |
||
473 | for ( i = 0; i < pTab.nCol; i++ ) |
||
474 | { |
||
475 | if ( aXRef[i] < 0 || oldmask == 0xffffffff || ( i < 32 && 0 != ( oldmask & ( 1 << i ) ) ) ) |
||
476 | { |
||
477 | sqlite3ExprCodeGetColumnOfTable( v, pTab, iCur, i, regOld + i ); |
||
478 | } |
||
479 | else |
||
480 | { |
||
481 | sqlite3VdbeAddOp2( v, OP_Null, 0, regOld + i ); |
||
482 | } |
||
483 | } |
||
484 | if ( chngRowid == false ) |
||
485 | { |
||
486 | sqlite3VdbeAddOp2( v, OP_Copy, regOldRowid, regNewRowid ); |
||
487 | } |
||
488 | } |
||
489 | |||
490 | /* Populate the array of registers beginning at regNew with the new |
||
491 | ** row data. This array is used to check constaints, create the new |
||
492 | ** table and index records, and as the values for any new.* references |
||
493 | ** made by triggers. |
||
494 | ** |
||
495 | ** If there are one or more BEFORE triggers, then do not populate the |
||
496 | ** registers associated with columns that are (a) not modified by |
||
497 | ** this UPDATE statement and (b) not accessed by new.* references. The |
||
498 | ** values for registers not modified by the UPDATE must be reloaded from |
||
499 | ** the database after the BEFORE triggers are fired anyway (as the trigger |
||
500 | ** may have modified them). So not loading those that are not going to |
||
501 | ** be used eliminates some redundant opcodes. |
||
502 | */ |
||
503 | newmask = (int)sqlite3TriggerColmask( |
||
504 | pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError |
||
505 | ); |
||
506 | for ( i = 0; i < pTab.nCol; i++ ) |
||
507 | { |
||
508 | if ( i == pTab.iPKey ) |
||
509 | { |
||
510 | sqlite3VdbeAddOp2( v, OP_Null, 0, regNew + i ); |
||
511 | } |
||
512 | else |
||
513 | { |
||
514 | j = aXRef[i]; |
||
515 | if ( j >= 0 ) |
||
516 | { |
||
517 | sqlite3ExprCode( pParse, pChanges.a[j].pExpr, regNew + i ); |
||
518 | } |
||
519 | else if ( 0 == ( tmask & TRIGGER_BEFORE ) || i > 31 || ( newmask & ( 1 << i ) ) != 0 ) |
||
520 | { |
||
521 | /* This branch loads the value of a column that will not be changed |
||
522 | ** into a register. This is done if there are no BEFORE triggers, or |
||
523 | ** if there are one or more BEFORE triggers that use this value via |
||
524 | ** a new.* reference in a trigger program. |
||
525 | */ |
||
526 | testcase( i == 31 ); |
||
527 | testcase( i == 32 ); |
||
528 | sqlite3VdbeAddOp3( v, OP_Column, iCur, i, regNew + i ); |
||
529 | sqlite3ColumnDefault( v, pTab, i, regNew + i ); |
||
530 | } |
||
531 | } |
||
532 | } |
||
533 | |||
534 | /* Fire any BEFORE UPDATE triggers. This happens before constraints are |
||
535 | ** verified. One could argue that this is wrong. |
||
536 | */ |
||
537 | if ( ( tmask & TRIGGER_BEFORE ) != 0 ) |
||
538 | { |
||
539 | sqlite3VdbeAddOp2( v, OP_Affinity, regNew, pTab.nCol ); |
||
540 | sqlite3TableAffinityStr( v, pTab ); |
||
541 | sqlite3CodeRowTrigger( pParse, pTrigger, TK_UPDATE, pChanges, |
||
542 | TRIGGER_BEFORE, pTab, regOldRowid, onError, addr ); |
||
543 | |||
544 | /* The row-trigger may have deleted the row being updated. In this |
||
545 | ** case, jump to the next row. No updates or AFTER triggers are |
||
546 | ** required. This behaviour - what happens when the row being updated |
||
547 | ** is deleted or renamed by a BEFORE trigger - is left undefined in the |
||
548 | ** documentation. |
||
549 | */ |
||
550 | sqlite3VdbeAddOp3( v, OP_NotExists, iCur, addr, regOldRowid ); |
||
551 | |||
552 | /* If it did not delete it, the row-trigger may still have modified |
||
553 | ** some of the columns of the row being updated. Load the values for |
||
554 | ** all columns not modified by the update statement into their |
||
555 | ** registers in case this has happened. |
||
556 | */ |
||
557 | for ( i = 0; i < pTab.nCol; i++ ) |
||
558 | { |
||
559 | if ( aXRef[i] < 0 && i != pTab.iPKey ) |
||
560 | { |
||
561 | sqlite3VdbeAddOp3( v, OP_Column, iCur, i, regNew + i ); |
||
562 | sqlite3ColumnDefault( v, pTab, i, regNew + i ); |
||
563 | } |
||
564 | } |
||
565 | } |
||
566 | |||
567 | if ( !isView ) |
||
568 | { |
||
569 | int j1; /* Address of jump instruction */ |
||
570 | |||
571 | /* Do constraint checks. */ |
||
572 | int iDummy; |
||
573 | sqlite3GenerateConstraintChecks( pParse, pTab, iCur, regNewRowid, |
||
574 | aRegIdx, ( chngRowid ? regOldRowid : 0 ), true, onError, addr, out iDummy ); |
||
575 | |||
576 | /* Do FK constraint checks. */ |
||
577 | if ( hasFK ) |
||
578 | { |
||
579 | sqlite3FkCheck( pParse, pTab, regOldRowid, 0 ); |
||
580 | } |
||
581 | |||
582 | /* Delete the index entries associated with the current record. */ |
||
583 | j1 = sqlite3VdbeAddOp3( v, OP_NotExists, iCur, 0, regOldRowid ); |
||
584 | sqlite3GenerateRowIndexDelete( pParse, pTab, iCur, aRegIdx ); |
||
585 | |||
586 | /* If changing the record number, delete the old record. */ |
||
587 | if ( hasFK || chngRowid ) |
||
588 | { |
||
589 | sqlite3VdbeAddOp2( v, OP_Delete, iCur, 0 ); |
||
590 | } |
||
591 | sqlite3VdbeJumpHere( v, j1 ); |
||
592 | |||
593 | if ( hasFK ) |
||
594 | { |
||
595 | sqlite3FkCheck( pParse, pTab, 0, regNewRowid ); |
||
596 | } |
||
597 | |||
598 | /* Insert the new index entries and the new record. */ |
||
599 | sqlite3CompleteInsertion( pParse, pTab, iCur, regNewRowid, aRegIdx, true, false, false ); |
||
600 | |||
601 | /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to |
||
602 | ** handle rows (possibly in other tables) that refer via a foreign key |
||
603 | ** to the row just updated. */ |
||
604 | if ( hasFK ) |
||
605 | { |
||
606 | sqlite3FkActions( pParse, pTab, pChanges, regOldRowid ); |
||
607 | } |
||
608 | } |
||
609 | |||
610 | /* Increment the row counter |
||
611 | */ |
||
612 | if ( ( db.flags & SQLITE_CountRows ) != 0 && null == pParse.pTriggerTab ) |
||
613 | { |
||
614 | sqlite3VdbeAddOp2( v, OP_AddImm, regRowCount, 1 ); |
||
615 | } |
||
616 | |||
617 | sqlite3CodeRowTrigger( pParse, pTrigger, TK_UPDATE, pChanges, |
||
618 | TRIGGER_AFTER, pTab, regOldRowid, onError, addr ); |
||
619 | |||
620 | /* Repeat the above with the next record to be updated, until |
||
621 | ** all record selected by the WHERE clause have been updated. |
||
622 | */ |
||
623 | sqlite3VdbeAddOp2( v, OP_Goto, 0, addr ); |
||
624 | sqlite3VdbeJumpHere( v, addr ); |
||
625 | |||
626 | /* Close all tables */ |
||
627 | for ( i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++ ) |
||
628 | { |
||
629 | if ( openAll || aRegIdx[i] > 0 ) |
||
630 | { |
||
631 | sqlite3VdbeAddOp2( v, OP_Close, iCur + i + 1, 0 ); |
||
632 | } |
||
633 | } |
||
634 | sqlite3VdbeAddOp2( v, OP_Close, iCur, 0 ); |
||
635 | |||
636 | /* Update the sqlite_sequence table by storing the content of the |
||
637 | ** maximum rowid counter values recorded while inserting into |
||
638 | ** autoincrement tables. |
||
639 | */ |
||
640 | if ( pParse.nested == 0 && pParse.pTriggerTab == null ) |
||
641 | { |
||
642 | sqlite3AutoincrementEnd( pParse ); |
||
643 | } |
||
644 | |||
645 | /* |
||
646 | ** Return the number of rows that were changed. If this routine is |
||
647 | ** generating code because of a call to sqlite3NestedParse(), do not |
||
648 | ** invoke the callback function. |
||
649 | */ |
||
650 | if ( ( db.flags & SQLITE_CountRows ) != 0 && null == pParse.pTriggerTab && 0 == pParse.nested ) |
||
651 | { |
||
652 | sqlite3VdbeAddOp2( v, OP_ResultRow, regRowCount, 1 ); |
||
653 | sqlite3VdbeSetNumCols( v, 1 ); |
||
654 | sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC ); |
||
655 | } |
||
656 | |||
657 | update_cleanup: |
||
658 | #if !SQLITE_OMIT_AUTHORIZATION |
||
659 | sqlite3AuthContextPop(sContext); |
||
660 | #endif |
||
661 | sqlite3DbFree( db, ref aRegIdx ); |
||
662 | sqlite3DbFree( db, ref aXRef ); |
||
663 | sqlite3SrcListDelete( db, ref pTabList ); |
||
664 | sqlite3ExprListDelete( db, ref pChanges ); |
||
665 | sqlite3ExprDelete( db, ref pWhere ); |
||
666 | return; |
||
667 | } |
||
668 | /* Make sure "isView" and other macros defined above are undefined. Otherwise |
||
669 | ** thely may interfere with compilation of other functions in this file |
||
670 | ** (or in another file, if this file becomes part of the amalgamation). */ |
||
671 | //#if isView |
||
672 | // #undef isView |
||
673 | //#endif |
||
674 | //#if pTrigger |
||
675 | // #undef pTrigger |
||
676 | //#endif |
||
677 | |||
678 | #if !SQLITE_OMIT_VIRTUALTABLE |
||
679 | /* |
||
680 | ** Generate code for an UPDATE of a virtual table. |
||
681 | ** |
||
682 | ** The strategy is that we create an ephemerial table that contains |
||
683 | ** for each row to be changed: |
||
684 | ** |
||
685 | ** (A) The original rowid of that row. |
||
686 | ** (B) The revised rowid for the row. (note1) |
||
687 | ** (C) The content of every column in the row. |
||
688 | ** |
||
689 | ** Then we loop over this ephemeral table and for each row in |
||
690 | ** the ephermeral table call VUpdate. |
||
691 | ** |
||
692 | ** When finished, drop the ephemeral table. |
||
693 | ** |
||
694 | ** (note1) Actually, if we know in advance that (A) is always the same |
||
695 | ** as (B) we only store (A), then duplicate (A) when pulling |
||
696 | ** it out of the ephemeral table before calling VUpdate. |
||
697 | */ |
||
698 | static void updateVirtualTable( |
||
699 | Parse pParse, /* The parsing context */ |
||
700 | SrcList pSrc, /* The virtual table to be modified */ |
||
701 | Table pTab, /* The virtual table */ |
||
702 | ExprList pChanges, /* The columns to change in the UPDATE statement */ |
||
703 | Expr pRowid, /* Expression used to recompute the rowid */ |
||
704 | int[] aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
||
705 | Expr pWhere, /* WHERE clause of the UPDATE statement */ |
||
706 | int onError /* ON CONFLICT strategy */ |
||
707 | ) |
||
708 | { |
||
709 | Vdbe v = pParse.pVdbe; /* Virtual machine under construction */ |
||
710 | ExprList pEList = null; /* The result set of the SELECT statement */ |
||
711 | Select pSelect = null; /* The SELECT statement */ |
||
712 | Expr pExpr; /* Temporary expression */ |
||
713 | int ephemTab; /* Table holding the result of the SELECT */ |
||
714 | int i; /* Loop counter */ |
||
715 | int addr; /* Address of top of loop */ |
||
716 | int iReg; /* First register in set passed to OP_VUpdate */ |
||
717 | sqlite3 db = pParse.db; /* Database connection */ |
||
718 | VTable pVTab = sqlite3GetVTable( db, pTab ); |
||
719 | SelectDest dest = new SelectDest(); |
||
720 | |||
721 | /* Construct the SELECT statement that will find the new values for |
||
722 | ** all updated rows. |
||
723 | */ |
||
724 | pEList = sqlite3ExprListAppend( pParse, 0, sqlite3Expr( db, TK_ID, "_rowid_" ) ); |
||
725 | if ( pRowid != null) |
||
726 | { |
||
727 | pEList = sqlite3ExprListAppend( pParse, pEList, |
||
728 | sqlite3ExprDup( db, pRowid, 0 ) ); |
||
729 | } |
||
730 | Debug.Assert( pTab.iPKey < 0 ); |
||
731 | for ( i = 0; i < pTab.nCol; i++ ) |
||
732 | { |
||
733 | if ( aXRef[i] >= 0 ) |
||
734 | { |
||
735 | pExpr = sqlite3ExprDup( db, pChanges.a[aXRef[i]].pExpr, 0 ); |
||
736 | } |
||
737 | else |
||
738 | { |
||
739 | pExpr = sqlite3Expr( db, TK_ID, pTab.aCol[i].zName ); |
||
740 | } |
||
741 | pEList = sqlite3ExprListAppend( pParse, pEList, pExpr ); |
||
742 | } |
||
743 | pSelect = sqlite3SelectNew( pParse, pEList, pSrc, pWhere, null, null, null, 0, null, null ); |
||
744 | |||
745 | /* Create the ephemeral table into which the update results will |
||
746 | ** be stored. |
||
747 | */ |
||
748 | Debug.Assert( v != null); |
||
749 | ephemTab = pParse.nTab++; |
||
750 | sqlite3VdbeAddOp2( v, OP_OpenEphemeral, ephemTab, pTab.nCol + 1 + ( ( pRowid != null ) ? 1 : 0 ) ); |
||
751 | sqlite3VdbeChangeP5( v, BTREE_UNORDERED ); |
||
752 | |||
753 | /* fill the ephemeral table |
||
754 | */ |
||
755 | sqlite3SelectDestInit( dest, SRT_Table, ephemTab ); |
||
756 | sqlite3Select( pParse, pSelect, ref dest ); |
||
757 | |||
758 | /* Generate code to scan the ephemeral table and call VUpdate. */ |
||
759 | iReg = ++pParse.nMem; |
||
760 | pParse.nMem += pTab.nCol + 1; |
||
761 | addr = sqlite3VdbeAddOp2( v, OP_Rewind, ephemTab, 0 ); |
||
762 | sqlite3VdbeAddOp3( v, OP_Column, ephemTab, 0, iReg ); |
||
763 | sqlite3VdbeAddOp3( v, OP_Column, ephemTab, ( pRowid != null ? 1 : 0 ), iReg + 1 ); |
||
764 | for ( i = 0; i < pTab.nCol; i++ ) |
||
765 | { |
||
766 | sqlite3VdbeAddOp3( v, OP_Column, ephemTab, i + 1 + ( ( pRowid != null ) ? 1 : 0 ), iReg + 2 + i ); |
||
767 | } |
||
768 | sqlite3VtabMakeWritable( pParse, pTab ); |
||
769 | sqlite3VdbeAddOp4( v, OP_VUpdate, 0, pTab.nCol + 2, iReg, pVTab, P4_VTAB ); |
||
770 | sqlite3VdbeChangeP5( v, (byte)( onError == OE_Default ? OE_Abort : onError ) ); |
||
771 | sqlite3MayAbort( pParse ); |
||
772 | sqlite3VdbeAddOp2( v, OP_Next, ephemTab, addr + 1 ); |
||
773 | sqlite3VdbeJumpHere( v, addr ); |
||
774 | sqlite3VdbeAddOp2( v, OP_Close, ephemTab, 0 ); |
||
775 | |||
776 | /* Cleanup */ |
||
777 | sqlite3SelectDelete( db, ref pSelect ); |
||
778 | } |
||
779 | #endif // * SQLITE_OMIT_VIRTUALTABLE */ |
||
780 | } |
||
781 | } |