diff options
| author | Ilia Alshanetsky <iliaa@php.net> | 2006-08-14 16:35:23 +0000 | 
|---|---|---|
| committer | Ilia Alshanetsky <iliaa@php.net> | 2006-08-14 16:35:23 +0000 | 
| commit | 5c01690d9b6b84ad576787f38805a85f75b3b82f (patch) | |
| tree | 701b795de27a18b9ee9e376eedd186a834cfa86a /ext/pdo_sqlite/sqlite/src/update.c | |
| parent | 3717342c9f6c08005cf3c32c721c81611a21d268 (diff) | |
| download | php-git-5c01690d9b6b84ad576787f38805a85f75b3b82f.tar.gz | |
MFB: Upgraded libsqlite in pdo_sqlite to 3.3.7
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/update.c')
| -rw-r--r-- | ext/pdo_sqlite/sqlite/src/update.c | 176 | 
1 files changed, 146 insertions, 30 deletions
| diff --git a/ext/pdo_sqlite/sqlite/src/update.c b/ext/pdo_sqlite/sqlite/src/update.c index b6c6b8b1ed..2565787f04 100644 --- a/ext/pdo_sqlite/sqlite/src/update.c +++ b/ext/pdo_sqlite/sqlite/src/update.c @@ -16,9 +16,22 @@  */  #include "sqliteInt.h" +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* Forward declaration */ +static void updateVirtualTable( +  Parse *pParse,       /* The parsing context */ +  SrcList *pSrc,       /* The virtual table to be modified */ +  Table *pTab,         /* The virtual table */ +  ExprList *pChanges,  /* The columns to change in the UPDATE statement */ +  Expr *pRowidExpr,    /* Expression used to recompute the rowid */ +  int *aXRef,          /* Mapping from columns of pTab to entries in pChanges */ +  Expr *pWhere         /* WHERE clause of the UPDATE statement */ +); +#endif /* SQLITE_OMIT_VIRTUALTABLE */ +  /* -** The most recently coded instruction was an OP_Column to retrieve column -** 'i' of table pTab. This routine sets the P3 parameter of the  +** The most recently coded instruction was an OP_Column to retrieve the +** i-th column of table pTab. This routine sets the P3 parameter of the   ** OP_Column to the default value, if any.  **  ** The default value of a column is specified by a DEFAULT clause in the  @@ -44,7 +57,7 @@  void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i){    if( pTab && !pTab->pSelect ){      sqlite3_value *pValue; -    u8 enc = sqlite3VdbeDb(v)->enc; +    u8 enc = ENC(sqlite3VdbeDb(v));      Column *pCol = &pTab->aCol[i];      sqlite3ValueFromExpr(pCol->pDflt, enc, pCol->affinity, &pValue);      if( pValue ){ @@ -89,6 +102,7 @@ void sqlite3Update(    int openAll = 0;       /* True if all indices need to be opened */    AuthContext sContext;  /* The authorization context */    NameContext sNC;       /* The name-context to resolve expressions in */ +  int iDb;               /* Database containing the table being updated */  #ifndef SQLITE_OMIT_TRIGGER    int isView;                  /* Trying to update a view */ @@ -99,7 +113,9 @@ void sqlite3Update(    int oldIdx      = -1;  /* index of trigger "old" temp table       */    sContext.pParse = 0; -  if( pParse->nErr || sqlite3_malloc_failed ) goto update_cleanup; +  if( pParse->nErr || sqlite3MallocFailed() ){ +    goto update_cleanup; +  }    db = pParse->db;    assert( pTabList->nSrc==1 ); @@ -107,6 +123,7 @@ void sqlite3Update(    */    pTab = sqlite3SrcListLookup(pParse, pTabList);    if( pTab==0 ) goto update_cleanup; +  iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);    /* Figure out if we have any triggers and if the table being    ** updated is a view @@ -126,10 +143,8 @@ void sqlite3Update(    if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){      goto update_cleanup;    } -  if( isView ){ -    if( sqlite3ViewGetColumnNames(pParse, pTab) ){ -      goto update_cleanup; -    } +  if( sqlite3ViewGetColumnNames(pParse, pTab) ){ +    goto update_cleanup;    }    aXRef = sqliteMallocRaw( sizeof(int) * pTab->nCol );    if( aXRef==0 ) goto update_cleanup; @@ -192,7 +207,7 @@ void sqlite3Update(      {        int rc;        rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, -                           pTab->aCol[j].zName, db->aDb[pTab->iDb].zName); +                           pTab->aCol[j].zName, db->aDb[iDb].zName);        if( rc==SQLITE_DENY ){          goto update_cleanup;        }else if( rc==SQLITE_IGNORE ){ @@ -231,7 +246,6 @@ void sqlite3Update(        }      }      if( i<pIdx->nColumn ){ -      if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;        apIdx[nIdx++] = pIdx;        aIdxUsed[j] = 1;      }else{ @@ -239,6 +253,24 @@ void sqlite3Update(      }    } +  /* Begin generating code. +  */ +  v = sqlite3GetVdbe(pParse); +  if( v==0 ) goto update_cleanup; +  if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); +  sqlite3BeginWriteOperation(pParse, 1, iDb); + +#ifndef SQLITE_OMIT_VIRTUALTABLE +  /* Virtual tables must be handled separately */ +  if( IsVirtual(pTab) ){ +    updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, +                       pWhere); +    pWhere = 0; +    pTabList = 0; +    goto update_cleanup; +  } +#endif +    /* Resolve the column names in all the expressions in the    ** WHERE clause.    */ @@ -252,20 +284,13 @@ void sqlite3Update(      sqlite3AuthContextPush(pParse, &sContext, pTab->zName);    } -  /* Begin generating code. -  */ -  v = sqlite3GetVdbe(pParse); -  if( v==0 ) goto update_cleanup; -  if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); -  sqlite3BeginWriteOperation(pParse, 1, pTab->iDb); -    /* If we are trying to update a view, realize that view into    ** a ephemeral table.    */    if( isView ){      Select *pView;      pView = sqlite3SelectDup(pTab->pSelect); -    sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0); +    sqlite3Select(pParse, pView, SRT_EphemTab, iCur, 0, 0, 0, 0);      sqlite3SelectDelete(pView);    } @@ -274,9 +299,9 @@ void sqlite3Update(    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0);    if( pWInfo==0 ) goto update_cleanup; -  /* Remember the index of every item to be updated. +  /* Remember the rowid of every item to be updated.    */ -  sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); +  sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);    sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);    /* End the database scan loop. @@ -307,7 +332,7 @@ void sqlite3Update(        /* Open a cursor and make it point to the record that is        ** being updated.        */ -      sqlite3OpenTableForReading(v, iCur, pTab); +      sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);      }      sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); @@ -355,16 +380,14 @@ void sqlite3Update(      }    } -  if( !isView ){ +  if( !isView && !IsVirtual(pTab) ){      /*       ** Open every index that needs updating.  Note that if any      ** index could potentially invoke a REPLACE conflict resolution       ** action, then we need to open all indices because we might need      ** to be deleting some records.      */ -    sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); -    sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum); -    sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); +    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);       if( onError==OE_Replace ){        openAll = 1;      }else{ @@ -378,9 +401,10 @@ void sqlite3Update(      }      for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){        if( openAll || aIdxUsed[i] ){ -        sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); +        KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); +        sqlite3VdbeAddOp(v, OP_Integer, iDb, 0);          sqlite3VdbeOp3(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, -                       (char*)&pIdx->keyInfo, P3_KEYINFO); +                       (char*)pKey, P3_KEYINFO_HANDOFF);          assert( pParse->nTab>iCur+i+1 );        }      } @@ -388,7 +412,7 @@ void sqlite3Update(      /* Loop over every record that needs updating.  We have to load      ** the old data for each record to be updated because some columns      ** might not change and we will need to copy the old value. -    ** Also, the old data is needed to delete the old index entires. +    ** Also, the old data is needed to delete the old index entries.      ** So make the cursor point at the old record.      */      if( !triggers_exist ){ @@ -429,7 +453,7 @@ void sqlite3Update(      /* Delete the old indices for the current record.      */ -    sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed); +    sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);      /* If changing the record number, delete the old record.      */ @@ -492,7 +516,7 @@ void sqlite3Update(    if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){      sqlite3VdbeAddOp(v, OP_Callback, 1, 0);      sqlite3VdbeSetNumCols(v, 1); -    sqlite3VdbeSetColName(v, 0, "rows updated", P3_STATIC); +    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);    }  update_cleanup: @@ -504,3 +528,95 @@ update_cleanup:    sqlite3ExprDelete(pWhere);    return;  } + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Generate code for an UPDATE of a virtual table. +** +** The strategy is that we create an ephemerial table that contains +** for each row to be changed: +** +**   (A)  The original rowid of that row. +**   (B)  The revised rowid for the row. (note1) +**   (C)  The content of every column in the row. +** +** Then we loop over this ephemeral table and for each row in +** the ephermeral table call VUpdate. +** +** When finished, drop the ephemeral table. +** +** (note1) Actually, if we know in advance that (A) is always the same +** as (B) we only store (A), then duplicate (A) when pulling +** it out of the ephemeral table before calling VUpdate. +*/ +static void updateVirtualTable( +  Parse *pParse,       /* The parsing context */ +  SrcList *pSrc,       /* The virtual table to be modified */ +  Table *pTab,         /* The virtual table */ +  ExprList *pChanges,  /* The columns to change in the UPDATE statement */ +  Expr *pRowid,        /* Expression used to recompute the rowid */ +  int *aXRef,          /* Mapping from columns of pTab to entries in pChanges */ +  Expr *pWhere         /* WHERE clause of the UPDATE statement */ +){ +  Vdbe *v = pParse->pVdbe;  /* Virtual machine under construction */ +  ExprList *pEList = 0;     /* The result set of the SELECT statement */ +  Select *pSelect = 0;      /* The SELECT statement */ +  Expr *pExpr;              /* Temporary expression */ +  int ephemTab;             /* Table holding the result of the SELECT */ +  int i;                    /* Loop counter */ +  int addr;                 /* Address of top of loop */ + +  /* Construct the SELECT statement that will find the new values for +  ** all updated rows.  +  */ +  pEList = sqlite3ExprListAppend(0, sqlite3CreateIdExpr("_rowid_"), 0); +  if( pRowid ){ +    pEList = sqlite3ExprListAppend(pEList, sqlite3ExprDup(pRowid), 0); +  } +  assert( pTab->iPKey<0 ); +  for(i=0; i<pTab->nCol; i++){ +    if( aXRef[i]>=0 ){ +      pExpr = sqlite3ExprDup(pChanges->a[aXRef[i]].pExpr); +    }else{ +      pExpr = sqlite3CreateIdExpr(pTab->aCol[i].zName); +    } +    pEList = sqlite3ExprListAppend(pEList, pExpr, 0); +  } +  pSelect = sqlite3SelectNew(pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0); +   +  /* Create the ephemeral table into which the update results will +  ** be stored. +  */ +  assert( v ); +  ephemTab = pParse->nTab++; +  sqlite3VdbeAddOp(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0)); + +  /* fill the ephemeral table  +  */ +  sqlite3Select(pParse, pSelect, SRT_Table, ephemTab, 0, 0, 0, 0); + +  /* +  ** Generate code to scan the ephemeral table and call VDelete and +  ** VInsert +  */ +  sqlite3VdbeAddOp(v, OP_Rewind, ephemTab, 0); +  addr = sqlite3VdbeCurrentAddr(v); +  sqlite3VdbeAddOp(v, OP_Column,  ephemTab, 0); +  if( pRowid ){ +    sqlite3VdbeAddOp(v, OP_Column, ephemTab, 1); +  }else{ +    sqlite3VdbeAddOp(v, OP_Dup, 0, 0); +  } +  for(i=0; i<pTab->nCol; i++){ +    sqlite3VdbeAddOp(v, OP_Column, ephemTab, i+1+(pRowid!=0)); +  } +  pParse->pVirtualLock = pTab; +  sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,  +                     (const char*)pTab->pVtab, P3_VTAB); +  sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr); +  sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0); + +  /* Cleanup */ +  sqlite3SelectDelete(pSelect);   +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ | 
