Annotation of embedaddon/php/ext/sqlite/libsqlite/src/delete.c, revision 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 DELETE FROM statements.
        !            14: **
        !            15: ** $Id: delete.c 195361 2005-09-07 15:11:33Z iliaa $
        !            16: */
        !            17: #include "sqliteInt.h"
        !            18: 
        !            19: /*
        !            20: ** 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.
        !            23: */
        !            24: Table *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 = sqliteLocateTable(pParse, zTab, zDb);
        !            31:     pSrc->a[i].pTab = pTab;
        !            32:   }
        !            33:   return pTab;
        !            34: }
        !            35: 
        !            36: /*
        !            37: ** Check to make sure the given table is writable.  If it is not
        !            38: ** writable, generate an error message and return 1.  If it is
        !            39: ** writable return 0;
        !            40: */
        !            41: int sqliteIsReadOnly(Parse *pParse, Table *pTab, int viewOk){
        !            42:   if( pTab->readOnly ){
        !            43:     sqliteErrorMsg(pParse, "table %s may not be modified", pTab->zName);
        !            44:     return 1;
        !            45:   }
        !            46:   if( !viewOk && pTab->pSelect ){
        !            47:     sqliteErrorMsg(pParse, "cannot modify %s because it is a view",pTab->zName);
        !            48:     return 1;
        !            49:   }
        !            50:   return 0;
        !            51: }
        !            52: 
        !            53: /*
        !            54: ** Process a DELETE FROM statement.
        !            55: */
        !            56: void sqliteDeleteFrom(
        !            57:   Parse *pParse,         /* The parser context */
        !            58:   SrcList *pTabList,     /* The table from which we should delete things */
        !            59:   Expr *pWhere           /* The WHERE clause.  May be null */
        !            60: ){
        !            61:   Vdbe *v;               /* The virtual database engine */
        !            62:   Table *pTab;           /* The table from which records will be deleted */
        !            63:   const char *zDb;       /* Name of database holding pTab */
        !            64:   int end, addr;         /* A couple addresses of generated code */
        !            65:   int i;                 /* Loop counter */
        !            66:   WhereInfo *pWInfo;     /* Information about the WHERE clause */
        !            67:   Index *pIdx;           /* For looping over indices of the table */
        !            68:   int iCur;              /* VDBE Cursor number for pTab */
        !            69:   sqlite *db;            /* Main database structure */
        !            70:   int isView;            /* True if attempting to delete from a view */
        !            71:   AuthContext sContext;  /* Authorization context */
        !            72: 
        !            73:   int row_triggers_exist = 0;  /* True if any triggers exist */
        !            74:   int before_triggers;         /* True if there are BEFORE triggers */
        !            75:   int after_triggers;          /* True if there are AFTER triggers */
        !            76:   int oldIdx = -1;             /* Cursor for the OLD table of AFTER triggers */
        !            77: 
        !            78:   sContext.pParse = 0;
        !            79:   if( pParse->nErr || sqlite_malloc_failed ){
        !            80:     pTabList = 0;
        !            81:     goto delete_from_cleanup;
        !            82:   }
        !            83:   db = pParse->db;
        !            84:   assert( pTabList->nSrc==1 );
        !            85: 
        !            86:   /* Locate the table which we want to delete.  This table has to be
        !            87:   ** put in an SrcList structure because some of the subroutines we
        !            88:   ** will be calling are designed to work with multiple tables and expect
        !            89:   ** an SrcList* parameter instead of just a Table* parameter.
        !            90:   */
        !            91:   pTab = sqliteSrcListLookup(pParse, pTabList);
        !            92:   if( pTab==0 )  goto delete_from_cleanup;
        !            93:   before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
        !            94:                          TK_DELETE, TK_BEFORE, TK_ROW, 0);
        !            95:   after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
        !            96:                          TK_DELETE, TK_AFTER, TK_ROW, 0);
        !            97:   row_triggers_exist = before_triggers || after_triggers;
        !            98:   isView = pTab->pSelect!=0;
        !            99:   if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
        !           100:     goto delete_from_cleanup;
        !           101:   }
        !           102:   assert( pTab->iDb<db->nDb );
        !           103:   zDb = db->aDb[pTab->iDb].zName;
        !           104:   if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
        !           105:     goto delete_from_cleanup;
        !           106:   }
        !           107: 
        !           108:   /* If pTab is really a view, make sure it has been initialized.
        !           109:   */
        !           110:   if( isView && sqliteViewGetColumnNames(pParse, pTab) ){
        !           111:     goto delete_from_cleanup;
        !           112:   }
        !           113: 
        !           114:   /* Allocate a cursor used to store the old.* data for a trigger.
        !           115:   */
        !           116:   if( row_triggers_exist ){ 
        !           117:     oldIdx = pParse->nTab++;
        !           118:   }
        !           119: 
        !           120:   /* Resolve the column names in all the expressions.
        !           121:   */
        !           122:   assert( pTabList->nSrc==1 );
        !           123:   iCur = pTabList->a[0].iCursor = pParse->nTab++;
        !           124:   if( pWhere ){
        !           125:     if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
        !           126:       goto delete_from_cleanup;
        !           127:     }
        !           128:     if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
        !           129:       goto delete_from_cleanup;
        !           130:     }
        !           131:   }
        !           132: 
        !           133:   /* Start the view context
        !           134:   */
        !           135:   if( isView ){
        !           136:     sqliteAuthContextPush(pParse, &sContext, pTab->zName);
        !           137:   }
        !           138: 
        !           139:   /* Begin generating code.
        !           140:   */
        !           141:   v = sqliteGetVdbe(pParse);
        !           142:   if( v==0 ){
        !           143:     goto delete_from_cleanup;
        !           144:   }
        !           145:   sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);
        !           146: 
        !           147:   /* If we are trying to delete from a view, construct that view into
        !           148:   ** a temporary table.
        !           149:   */
        !           150:   if( isView ){
        !           151:     Select *pView = sqliteSelectDup(pTab->pSelect);
        !           152:     sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
        !           153:     sqliteSelectDelete(pView);
        !           154:   }
        !           155: 
        !           156:   /* Initialize the counter of the number of rows deleted, if
        !           157:   ** we are counting rows.
        !           158:   */
        !           159:   if( db->flags & SQLITE_CountRows ){
        !           160:     sqliteVdbeAddOp(v, OP_Integer, 0, 0);
        !           161:   }
        !           162: 
        !           163:   /* Special case: A DELETE without a WHERE clause deletes everything.
        !           164:   ** It is easier just to erase the whole table.  Note, however, that
        !           165:   ** this means that the row change count will be incorrect.
        !           166:   */
        !           167:   if( pWhere==0 && !row_triggers_exist ){
        !           168:     if( db->flags & SQLITE_CountRows ){
        !           169:       /* If counting rows deleted, just count the total number of
        !           170:       ** entries in the table. */
        !           171:       int endOfLoop = sqliteVdbeMakeLabel(v);
        !           172:       int addr;
        !           173:       if( !isView ){
        !           174:         sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
        !           175:         sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
        !           176:       }
        !           177:       sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2);
        !           178:       addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
        !           179:       sqliteVdbeAddOp(v, OP_Next, iCur, addr);
        !           180:       sqliteVdbeResolveLabel(v, endOfLoop);
        !           181:       sqliteVdbeAddOp(v, OP_Close, iCur, 0);
        !           182:     }
        !           183:     if( !isView ){
        !           184:       sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
        !           185:       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
        !           186:         sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
        !           187:       }
        !           188:     }
        !           189:   }
        !           190: 
        !           191:   /* The usual case: There is a WHERE clause so we have to scan through
        !           192:   ** the table and pick which records to delete.
        !           193:   */
        !           194:   else{
        !           195:     /* Begin the database scan
        !           196:     */
        !           197:     pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
        !           198:     if( pWInfo==0 ) goto delete_from_cleanup;
        !           199: 
        !           200:     /* Remember the key of every item to be deleted.
        !           201:     */
        !           202:     sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
        !           203:     if( db->flags & SQLITE_CountRows ){
        !           204:       sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
        !           205:     }
        !           206: 
        !           207:     /* End the database scan loop.
        !           208:     */
        !           209:     sqliteWhereEnd(pWInfo);
        !           210: 
        !           211:     /* Open the pseudo-table used to store OLD if there are triggers.
        !           212:     */
        !           213:     if( row_triggers_exist ){
        !           214:       sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
        !           215:     }
        !           216: 
        !           217:     /* Delete every item whose key was written to the list during the
        !           218:     ** database scan.  We have to delete items after the scan is complete
        !           219:     ** because deleting an item can change the scan order.
        !           220:     */
        !           221:     sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
        !           222:     end = sqliteVdbeMakeLabel(v);
        !           223: 
        !           224:     /* This is the beginning of the delete loop when there are
        !           225:     ** row triggers.
        !           226:     */
        !           227:     if( row_triggers_exist ){
        !           228:       addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
        !           229:       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
        !           230:       if( !isView ){
        !           231:         sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
        !           232:         sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
        !           233:       }
        !           234:       sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
        !           235: 
        !           236:       sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
        !           237:       sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
        !           238:       sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
        !           239:       if( !isView ){
        !           240:         sqliteVdbeAddOp(v, OP_Close, iCur, 0);
        !           241:       }
        !           242: 
        !           243:       sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
        !           244:           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
        !           245:          addr);
        !           246:     }
        !           247: 
        !           248:     if( !isView ){
        !           249:       /* Open cursors for the table we are deleting from and all its
        !           250:       ** indices.  If there are row triggers, this happens inside the
        !           251:       ** OP_ListRead loop because the cursor have to all be closed
        !           252:       ** before the trigger fires.  If there are no row triggers, the
        !           253:       ** cursors are opened only once on the outside the loop.
        !           254:       */
        !           255:       pParse->nTab = iCur + 1;
        !           256:       sqliteOpenTableAndIndices(pParse, pTab, iCur);
        !           257: 
        !           258:       /* This is the beginning of the delete loop when there are no
        !           259:       ** row triggers */
        !           260:       if( !row_triggers_exist ){ 
        !           261:         addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
        !           262:       }
        !           263: 
        !           264:       /* Delete the row */
        !           265:       sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
        !           266:     }
        !           267: 
        !           268:     /* If there are row triggers, close all cursors then invoke
        !           269:     ** the AFTER triggers
        !           270:     */
        !           271:     if( row_triggers_exist ){
        !           272:       if( !isView ){
        !           273:         for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        !           274:           sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
        !           275:         }
        !           276:         sqliteVdbeAddOp(v, OP_Close, iCur, 0);
        !           277:       }
        !           278:       sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, 
        !           279:           oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
        !           280:          addr);
        !           281:     }
        !           282: 
        !           283:     /* End of the delete loop */
        !           284:     sqliteVdbeAddOp(v, OP_Goto, 0, addr);
        !           285:     sqliteVdbeResolveLabel(v, end);
        !           286:     sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
        !           287: 
        !           288:     /* Close the cursors after the loop if there are no row triggers */
        !           289:     if( !row_triggers_exist ){
        !           290:       for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        !           291:         sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
        !           292:       }
        !           293:       sqliteVdbeAddOp(v, OP_Close, iCur, 0);
        !           294:       pParse->nTab = iCur;
        !           295:     }
        !           296:   }
        !           297:   sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
        !           298:   sqliteEndWriteOperation(pParse);
        !           299: 
        !           300:   /*
        !           301:   ** Return the number of rows that were deleted.
        !           302:   */
        !           303:   if( db->flags & SQLITE_CountRows ){
        !           304:     sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
        !           305:     sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
        !           306:     sqliteVdbeAddOp(v, OP_Callback, 1, 0);
        !           307:   }
        !           308: 
        !           309: delete_from_cleanup:
        !           310:   sqliteAuthContextPop(&sContext);
        !           311:   sqliteSrcListDelete(pTabList);
        !           312:   sqliteExprDelete(pWhere);
        !           313:   return;
        !           314: }
        !           315: 
        !           316: /*
        !           317: ** This routine generates VDBE code that causes a single row of a
        !           318: ** single table to be deleted.
        !           319: **
        !           320: ** The VDBE must be in a particular state when this routine is called.
        !           321: ** These are the requirements:
        !           322: **
        !           323: **   1.  A read/write cursor pointing to pTab, the table containing the row
        !           324: **       to be deleted, must be opened as cursor number "base".
        !           325: **
        !           326: **   2.  Read/write cursors for all indices of pTab must be open as
        !           327: **       cursor number base+i for the i-th index.
        !           328: **
        !           329: **   3.  The record number of the row to be deleted must be on the top
        !           330: **       of the stack.
        !           331: **
        !           332: ** This routine pops the top of the stack to remove the record number
        !           333: ** and then generates code to remove both the table record and all index
        !           334: ** entries that point to that record.
        !           335: */
        !           336: void sqliteGenerateRowDelete(
        !           337:   sqlite *db,        /* The database containing the index */
        !           338:   Vdbe *v,           /* Generate code into this VDBE */
        !           339:   Table *pTab,       /* Table containing the row to be deleted */
        !           340:   int iCur,          /* Cursor number for the table */
        !           341:   int count          /* Increment the row change counter */
        !           342: ){
        !           343:   int addr;
        !           344:   addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
        !           345:   sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
        !           346:   sqliteVdbeAddOp(v, OP_Delete, iCur,
        !           347:     (count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
        !           348:   sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
        !           349: }
        !           350: 
        !           351: /*
        !           352: ** This routine generates VDBE code that causes the deletion of all
        !           353: ** index entries associated with a single row of a single table.
        !           354: **
        !           355: ** The VDBE must be in a particular state when this routine is called.
        !           356: ** These are the requirements:
        !           357: **
        !           358: **   1.  A read/write cursor pointing to pTab, the table containing the row
        !           359: **       to be deleted, must be opened as cursor number "iCur".
        !           360: **
        !           361: **   2.  Read/write cursors for all indices of pTab must be open as
        !           362: **       cursor number iCur+i for the i-th index.
        !           363: **
        !           364: **   3.  The "iCur" cursor must be pointing to the row that is to be
        !           365: **       deleted.
        !           366: */
        !           367: void sqliteGenerateRowIndexDelete(
        !           368:   sqlite *db,        /* The database containing the index */
        !           369:   Vdbe *v,           /* Generate code into this VDBE */
        !           370:   Table *pTab,       /* Table containing the row to be deleted */
        !           371:   int iCur,          /* Cursor number for the table */
        !           372:   char *aIdxUsed     /* Only delete if aIdxUsed!=0 && aIdxUsed[i]!=0 */
        !           373: ){
        !           374:   int i;
        !           375:   Index *pIdx;
        !           376: 
        !           377:   for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        !           378:     int j;
        !           379:     if( aIdxUsed!=0 && aIdxUsed[i-1]==0 ) continue;
        !           380:     sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
        !           381:     for(j=0; j<pIdx->nColumn; j++){
        !           382:       int idx = pIdx->aiColumn[j];
        !           383:       if( idx==pTab->iPKey ){
        !           384:         sqliteVdbeAddOp(v, OP_Dup, j, 0);
        !           385:       }else{
        !           386:         sqliteVdbeAddOp(v, OP_Column, iCur, idx);
        !           387:       }
        !           388:     }
        !           389:     sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
        !           390:     if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
        !           391:     sqliteVdbeAddOp(v, OP_IdxDelete, iCur+i, 0);
        !           392:   }
        !           393: }

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