Annotation of embedaddon/php/ext/sqlite/libsqlite/src/update.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: ** 2001 September 15
                      3: **
                      4: ** The author disclaims copyright to this source code.  In place of
                      5: ** a legal notice, here is a blessing:
                      6: **
                      7: **    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.
                     10: **
                     11: *************************************************************************
                     12: ** This file contains C code routines that are called by the parser
                     13: ** to handle UPDATE statements.
                     14: **
                     15: ** $Id: update.c 195361 2005-09-07 15:11:33Z iliaa $
                     16: */
                     17: #include "sqliteInt.h"
                     18: 
                     19: /*
                     20: ** Process an UPDATE statement.
                     21: **
                     22: **   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
                     23: **          \_______/ \________/     \______/       \________________/
                     24: *            onError   pTabList      pChanges             pWhere
                     25: */
                     26: void sqliteUpdate(
                     27:   Parse *pParse,         /* The parser context */
                     28:   SrcList *pTabList,     /* The table in which we should change things */
                     29:   ExprList *pChanges,    /* Things to be changed */
                     30:   Expr *pWhere,          /* The WHERE clause.  May be null */
                     31:   int onError            /* How to handle constraint errors */
                     32: ){
                     33:   int i, j;              /* Loop counters */
                     34:   Table *pTab;           /* The table to be updated */
                     35:   int loopStart;         /* VDBE instruction address of the start of the loop */
                     36:   int jumpInst;          /* Addr of VDBE instruction to jump out of loop */
                     37:   WhereInfo *pWInfo;     /* Information about the WHERE clause */
                     38:   Vdbe *v;               /* The virtual database engine */
                     39:   Index *pIdx;           /* For looping over indices */
                     40:   int nIdx;              /* Number of indices that need updating */
                     41:   int nIdxTotal;         /* Total number of indices */
                     42:   int iCur;              /* VDBE Cursor number of pTab */
                     43:   sqlite *db;            /* The database structure */
                     44:   Index **apIdx = 0;     /* An array of indices that need updating too */
                     45:   char *aIdxUsed = 0;    /* aIdxUsed[i]==1 if the i-th index is used */
                     46:   int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                     47:                          ** an expression for the i-th column of the table.
                     48:                          ** aXRef[i]==-1 if the i-th column is not changed. */
                     49:   int chngRecno;         /* True if the record number is being changed */
                     50:   Expr *pRecnoExpr;      /* Expression defining the new record number */
                     51:   int openAll;           /* True if all indices need to be opened */
                     52:   int isView;            /* Trying to update a view */
                     53:   int iStackDepth;       /* Index of memory cell holding stack depth */
                     54:   AuthContext sContext;  /* The authorization context */
                     55: 
                     56:   int before_triggers;         /* True if there are any BEFORE triggers */
                     57:   int after_triggers;          /* True if there are any AFTER triggers */
                     58:   int row_triggers_exist = 0;  /* True if any row triggers exist */
                     59: 
                     60:   int newIdx      = -1;  /* index of trigger "new" temp table       */
                     61:   int oldIdx      = -1;  /* index of trigger "old" temp table       */
                     62: 
                     63:   sContext.pParse = 0;
                     64:   if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
                     65:   db = pParse->db;
                     66:   assert( pTabList->nSrc==1 );
                     67:   iStackDepth = pParse->nMem++;
                     68: 
                     69:   /* Locate the table which we want to update. 
                     70:   */
                     71:   pTab = sqliteSrcListLookup(pParse, pTabList);
                     72:   if( pTab==0 ) goto update_cleanup;
                     73:   before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                     74:             TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
                     75:   after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                     76:             TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
                     77:   row_triggers_exist = before_triggers || after_triggers;
                     78:   isView = pTab->pSelect!=0;
                     79:   if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
                     80:     goto update_cleanup;
                     81:   }
                     82:   if( isView ){
                     83:     if( sqliteViewGetColumnNames(pParse, pTab) ){
                     84:       goto update_cleanup;
                     85:     }
                     86:   }
                     87:   aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
                     88:   if( aXRef==0 ) goto update_cleanup;
                     89:   for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
                     90: 
                     91:   /* If there are FOR EACH ROW triggers, allocate cursors for the
                     92:   ** special OLD and NEW tables
                     93:   */
                     94:   if( row_triggers_exist ){
                     95:     newIdx = pParse->nTab++;
                     96:     oldIdx = pParse->nTab++;
                     97:   }
                     98: 
                     99:   /* Allocate a cursors for the main database table and for all indices.
                    100:   ** The index cursors might not be used, but if they are used they
                    101:   ** need to occur right after the database cursor.  So go ahead and
                    102:   ** allocate enough space, just in case.
                    103:   */
                    104:   pTabList->a[0].iCursor = iCur = pParse->nTab++;
                    105:   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
                    106:     pParse->nTab++;
                    107:   }
                    108: 
                    109:   /* Resolve the column names in all the expressions of the
                    110:   ** of the UPDATE statement.  Also find the column index
                    111:   ** for each column to be updated in the pChanges array.  For each
                    112:   ** column to be updated, make sure we have authorization to change
                    113:   ** that column.
                    114:   */
                    115:   chngRecno = 0;
                    116:   for(i=0; i<pChanges->nExpr; i++){
                    117:     if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
                    118:       goto update_cleanup;
                    119:     }
                    120:     if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
                    121:       goto update_cleanup;
                    122:     }
                    123:     for(j=0; j<pTab->nCol; j++){
                    124:       if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
                    125:         if( j==pTab->iPKey ){
                    126:           chngRecno = 1;
                    127:           pRecnoExpr = pChanges->a[i].pExpr;
                    128:         }
                    129:         aXRef[j] = i;
                    130:         break;
                    131:       }
                    132:     }
                    133:     if( j>=pTab->nCol ){
                    134:       if( sqliteIsRowid(pChanges->a[i].zName) ){
                    135:         chngRecno = 1;
                    136:         pRecnoExpr = pChanges->a[i].pExpr;
                    137:       }else{
                    138:         sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
                    139:         goto update_cleanup;
                    140:       }
                    141:     }
                    142: #ifndef SQLITE_OMIT_AUTHORIZATION
                    143:     {
                    144:       int rc;
                    145:       rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
                    146:                            pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
                    147:       if( rc==SQLITE_DENY ){
                    148:         goto update_cleanup;
                    149:       }else if( rc==SQLITE_IGNORE ){
                    150:         aXRef[j] = -1;
                    151:       }
                    152:     }
                    153: #endif
                    154:   }
                    155: 
                    156:   /* Allocate memory for the array apIdx[] and fill it with pointers to every
                    157:   ** index that needs to be updated.  Indices only need updating if their
                    158:   ** key includes one of the columns named in pChanges or if the record
                    159:   ** number of the original table entry is changing.
                    160:   */
                    161:   for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
                    162:     if( chngRecno ){
                    163:       i = 0;
                    164:     }else {
                    165:       for(i=0; i<pIdx->nColumn; i++){
                    166:         if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
                    167:       }
                    168:     }
                    169:     if( i<pIdx->nColumn ) nIdx++;
                    170:   }
                    171:   if( nIdxTotal>0 ){
                    172:     apIdx = sqliteMalloc( sizeof(Index*) * nIdx + nIdxTotal );
                    173:     if( apIdx==0 ) goto update_cleanup;
                    174:     aIdxUsed = (char*)&apIdx[nIdx];
                    175:   }
                    176:   for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
                    177:     if( chngRecno ){
                    178:       i = 0;
                    179:     }else{
                    180:       for(i=0; i<pIdx->nColumn; i++){
                    181:         if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
                    182:       }
                    183:     }
                    184:     if( i<pIdx->nColumn ){
                    185:       apIdx[nIdx++] = pIdx;
                    186:       aIdxUsed[j] = 1;
                    187:     }else{
                    188:       aIdxUsed[j] = 0;
                    189:     }
                    190:   }
                    191: 
                    192:   /* Resolve the column names in all the expressions in the
                    193:   ** WHERE clause.
                    194:   */
                    195:   if( pWhere ){
                    196:     if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
                    197:       goto update_cleanup;
                    198:     }
                    199:     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
                    200:       goto update_cleanup;
                    201:     }
                    202:   }
                    203: 
                    204:   /* Start the view context
                    205:   */
                    206:   if( isView ){
                    207:     sqliteAuthContextPush(pParse, &sContext, pTab->zName);
                    208:   }
                    209: 
                    210:   /* Begin generating code.
                    211:   */
                    212:   v = sqliteGetVdbe(pParse);
                    213:   if( v==0 ) goto update_cleanup;
                    214:   sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
                    215: 
                    216:   /* If we are trying to update a view, construct that view into
                    217:   ** a temporary table.
                    218:   */
                    219:   if( isView ){
                    220:     Select *pView;
                    221:     pView = sqliteSelectDup(pTab->pSelect);
                    222:     sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
                    223:     sqliteSelectDelete(pView);
                    224:   }
                    225: 
                    226:   /* Begin the database scan
                    227:   */
                    228:   pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
                    229:   if( pWInfo==0 ) goto update_cleanup;
                    230: 
                    231:   /* Remember the index of every item to be updated.
                    232:   */
                    233:   sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
                    234: 
                    235:   /* End the database scan loop.
                    236:   */
                    237:   sqliteWhereEnd(pWInfo);
                    238: 
                    239:   /* Initialize the count of updated rows
                    240:   */
                    241:   if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
                    242:     sqliteVdbeAddOp(v, OP_Integer, 0, 0);
                    243:   }
                    244: 
                    245:   if( row_triggers_exist ){
                    246:     /* Create pseudo-tables for NEW and OLD
                    247:     */
                    248:     sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
                    249:     sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
                    250: 
                    251:     /* The top of the update loop for when there are triggers.
                    252:     */
                    253:     sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
                    254:     sqliteVdbeAddOp(v, OP_StackDepth, 0, 0);
                    255:     sqliteVdbeAddOp(v, OP_MemStore, iStackDepth, 1);
                    256:     loopStart = sqliteVdbeAddOp(v, OP_MemLoad, iStackDepth, 0);
                    257:     sqliteVdbeAddOp(v, OP_StackReset, 0, 0);
                    258:     jumpInst = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
                    259:     sqliteVdbeAddOp(v, OP_Dup, 0, 0);
                    260: 
                    261:     /* Open a cursor and make it point to the record that is
                    262:     ** being updated.
                    263:     */
                    264:     sqliteVdbeAddOp(v, OP_Dup, 0, 0);
                    265:     if( !isView ){
                    266:       sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
                    267:       sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
                    268:     }
                    269:     sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
                    270: 
                    271:     /* Generate the OLD table
                    272:     */
                    273:     sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
                    274:     sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
                    275:     sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
                    276: 
                    277:     /* Generate the NEW table
                    278:     */
                    279:     if( chngRecno ){
                    280:       sqliteExprCode(pParse, pRecnoExpr);
                    281:     }else{
                    282:       sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
                    283:     }
                    284:     for(i=0; i<pTab->nCol; i++){
                    285:       if( i==pTab->iPKey ){
                    286:         sqliteVdbeAddOp(v, OP_String, 0, 0);
                    287:         continue;
                    288:       }
                    289:       j = aXRef[i];
                    290:       if( j<0 ){
                    291:         sqliteVdbeAddOp(v, OP_Column, iCur, i);
                    292:       }else{
                    293:         sqliteExprCode(pParse, pChanges->a[j].pExpr);
                    294:       }
                    295:     }
                    296:     sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
                    297:     sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
                    298:     if( !isView ){
                    299:       sqliteVdbeAddOp(v, OP_Close, iCur, 0);
                    300:     }
                    301: 
                    302:     /* Fire the BEFORE and INSTEAD OF triggers
                    303:     */
                    304:     if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, 
                    305:           newIdx, oldIdx, onError, loopStart) ){
                    306:       goto update_cleanup;
                    307:     }
                    308:   }
                    309: 
                    310:   if( !isView ){
                    311:     /* 
                    312:     ** Open every index that needs updating.  Note that if any
                    313:     ** index could potentially invoke a REPLACE conflict resolution 
                    314:     ** action, then we need to open all indices because we might need
                    315:     ** to be deleting some records.
                    316:     */
                    317:     sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
                    318:     sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
                    319:     if( onError==OE_Replace ){
                    320:       openAll = 1;
                    321:     }else{
                    322:       openAll = 0;
                    323:       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
                    324:         if( pIdx->onError==OE_Replace ){
                    325:           openAll = 1;
                    326:           break;
                    327:         }
                    328:       }
                    329:     }
                    330:     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
                    331:       if( openAll || aIdxUsed[i] ){
                    332:         sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
                    333:         sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
                    334:         assert( pParse->nTab>iCur+i+1 );
                    335:       }
                    336:     }
                    337: 
                    338:     /* Loop over every record that needs updating.  We have to load
                    339:     ** the old data for each record to be updated because some columns
                    340:     ** might not change and we will need to copy the old value.
                    341:     ** Also, the old data is needed to delete the old index entires.
                    342:     ** So make the cursor point at the old record.
                    343:     */
                    344:     if( !row_triggers_exist ){
                    345:       sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
                    346:       jumpInst = loopStart = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
                    347:       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
                    348:     }
                    349:     sqliteVdbeAddOp(v, OP_NotExists, iCur, loopStart);
                    350: 
                    351:     /* If the record number will change, push the record number as it
                    352:     ** will be after the update. (The old record number is currently
                    353:     ** on top of the stack.)
                    354:     */
                    355:     if( chngRecno ){
                    356:       sqliteExprCode(pParse, pRecnoExpr);
                    357:       sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
                    358:     }
                    359: 
                    360:     /* Compute new data for this record.  
                    361:     */
                    362:     for(i=0; i<pTab->nCol; i++){
                    363:       if( i==pTab->iPKey ){
                    364:         sqliteVdbeAddOp(v, OP_String, 0, 0);
                    365:         continue;
                    366:       }
                    367:       j = aXRef[i];
                    368:       if( j<0 ){
                    369:         sqliteVdbeAddOp(v, OP_Column, iCur, i);
                    370:       }else{
                    371:         sqliteExprCode(pParse, pChanges->a[j].pExpr);
                    372:       }
                    373:     }
                    374: 
                    375:     /* Do constraint checks
                    376:     */
                    377:     sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
                    378:                                    onError, loopStart);
                    379: 
                    380:     /* Delete the old indices for the current record.
                    381:     */
                    382:     sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
                    383: 
                    384:     /* If changing the record number, delete the old record.
                    385:     */
                    386:     if( chngRecno ){
                    387:       sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
                    388:     }
                    389: 
                    390:     /* Create the new index entries and the new record.
                    391:     */
                    392:     sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
                    393:   }
                    394: 
                    395:   /* Increment the row counter 
                    396:   */
                    397:   if( db->flags & SQLITE_CountRows && !pParse->trigStack){
                    398:     sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
                    399:   }
                    400: 
                    401:   /* If there are triggers, close all the cursors after each iteration
                    402:   ** through the loop.  The fire the after triggers.
                    403:   */
                    404:   if( row_triggers_exist ){
                    405:     if( !isView ){
                    406:       for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
                    407:         if( openAll || aIdxUsed[i] )
                    408:           sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
                    409:       }
                    410:       sqliteVdbeAddOp(v, OP_Close, iCur, 0);
                    411:       pParse->nTab = iCur;
                    412:     }
                    413:     if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, 
                    414:           newIdx, oldIdx, onError, loopStart) ){
                    415:       goto update_cleanup;
                    416:     }
                    417:   }
                    418: 
                    419:   /* Repeat the above with the next record to be updated, until
                    420:   ** all record selected by the WHERE clause have been updated.
                    421:   */
                    422:   sqliteVdbeAddOp(v, OP_Goto, 0, loopStart);
                    423:   sqliteVdbeChangeP2(v, jumpInst, sqliteVdbeCurrentAddr(v));
                    424:   sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
                    425: 
                    426:   /* Close all tables if there were no FOR EACH ROW triggers */
                    427:   if( !row_triggers_exist ){
                    428:     for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
                    429:       if( openAll || aIdxUsed[i] ){
                    430:         sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
                    431:       }
                    432:     }
                    433:     sqliteVdbeAddOp(v, OP_Close, iCur, 0);
                    434:     pParse->nTab = iCur;
                    435:   }else{
                    436:     sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
                    437:     sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
                    438:   }
                    439: 
                    440:   sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
                    441:   sqliteEndWriteOperation(pParse);
                    442: 
                    443:   /*
                    444:   ** Return the number of rows that were changed.
                    445:   */
                    446:   if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
                    447:     sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC);
                    448:     sqliteVdbeAddOp(v, OP_Callback, 1, 0);
                    449:   }
                    450: 
                    451: update_cleanup:
                    452:   sqliteAuthContextPop(&sContext);
                    453:   sqliteFree(apIdx);
                    454:   sqliteFree(aXRef);
                    455:   sqliteSrcListDelete(pTabList);
                    456:   sqliteExprListDelete(pChanges);
                    457:   sqliteExprDelete(pWhere);
                    458:   return;
                    459: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>