示例#1
0
/*
** This routine generates VDBE code that causes a single row of a
** single table to be deleted.
**
** The VDBE must be in a particular state when this routine is called.
** These are the requirements:
**
**   1.  A read/write cursor pointing to pTab, the table containing the row
**       to be deleted, must be opened as cursor number "base".
**
**   2.  Read/write cursors for all indices of pTab must be open as
**       cursor number base+i for the i-th index.
**
**   3.  The record number of the row to be deleted must be on the top
**       of the stack.
**
** This routine pops the top of the stack to remove the record number
** and then generates code to remove both the table record and all index
** entries that point to that record.
*/
void sqliteGenerateRowDelete(
  sqlite *db,        /* The database containing the index */
  Vdbe *v,           /* Generate code into this VDBE */
  Table *pTab,       /* Table containing the row to be deleted */
  int iCur,          /* Cursor number for the table */
  int count          /* Increment the row change counter */
){
  int addr;
  addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
  sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
  sqliteVdbeAddOp(v, OP_Delete, iCur,
    (count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
  sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
}
示例#2
0
/*
** Process an UPDATE statement.
**
**   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
**          \_______/ \________/     \______/       \________________/
*            onError   pTabList      pChanges             pWhere
*/
void sqliteUpdate(
  Parse *pParse,         /* The parser context */
  SrcList *pTabList,     /* The table in which we should change things */
  ExprList *pChanges,    /* Things to be changed */
  Expr *pWhere,          /* The WHERE clause.  May be null */
  int onError            /* How to handle constraint errors */
){
  int i, j;              /* Loop counters */
  Table *pTab;           /* The table to be updated */
  int addr;              /* VDBE instruction address of the start of the loop */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Vdbe *v;               /* The virtual database engine */
  Index *pIdx;           /* For looping over indices */
  int nIdx;              /* Number of indices that need updating */
  int nIdxTotal;         /* Total number of indices */
  int iCur;              /* VDBE Cursor number of pTab */
  sqlite *db;            /* The database structure */
  Index **apIdx = 0;     /* An array of indices that need updating too */
  char *aIdxUsed = 0;    /* aIdxUsed[i]==1 if the i-th index is used */
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRecno;         /* True if the record number is being changed */
  Expr *pRecnoExpr;      /* Expression defining the new record number */
  int openAll;           /* True if all indices need to be opened */
  int isView;            /* Trying to update a view */
  AuthContext sContext;  /* The authorization context */

  int before_triggers;         /* True if there are any BEFORE triggers */
  int after_triggers;          /* True if there are any AFTER triggers */
  int row_triggers_exist = 0;  /* True if any row triggers exist */

  int newIdx      = -1;  /* index of trigger "new" temp table       */
  int oldIdx      = -1;  /* index of trigger "old" temp table       */

  sContext.pParse = 0;
  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
  db = pParse->db;
  assert( pTabList->nSrc==1 );

  /* Locate the table which we want to update. 
  */
  pTab = sqliteSrcListLookup(pParse, pTabList);
  if( pTab==0 ) goto update_cleanup;
  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
  row_triggers_exist = before_triggers || after_triggers;
  isView = pTab->pSelect!=0;
  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
    goto update_cleanup;
  }
  if( isView ){
    if( sqliteViewGetColumnNames(pParse, pTab) ){
      goto update_cleanup;
    }
  }
  aXRef = sqliteMalloc( sizeof(int) * pTab->nCol );
  if( aXRef==0 ) goto update_cleanup;
  for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;

  /* If there are FOR EACH ROW triggers, allocate cursors for the
  ** special OLD and NEW tables
  */
  if( row_triggers_exist ){
    newIdx = pParse->nTab++;
    oldIdx = pParse->nTab++;
  }

  /* Allocate a cursors for the main database table and for all indices.
  ** The index cursors might not be used, but if they are used they
  ** need to occur right after the database cursor.  So go ahead and
  ** allocate enough space, just in case.
  */
  pTabList->a[0].iCursor = iCur = pParse->nTab++;
  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
    pParse->nTab++;
  }

  /* Resolve the column names in all the expressions of the
  ** of the UPDATE statement.  Also find the column index
  ** for each column to be updated in the pChanges array.  For each
  ** column to be updated, make sure we have authorization to change
  ** that column.
  */
  chngRecno = 0;
  for(i=0; i<pChanges->nExpr; i++){
    if( sqliteExprResolveIds(pParse, pTabList, 0, pChanges->a[i].pExpr) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pChanges->a[i].pExpr, 0, 0) ){
      goto update_cleanup;
    }
    for(j=0; j<pTab->nCol; j++){
      if( sqliteStrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
        if( j==pTab->iPKey ){
          chngRecno = 1;
          pRecnoExpr = pChanges->a[i].pExpr;
        }
        aXRef[j] = i;
        break;
      }
    }
    if( j>=pTab->nCol ){
      if( sqliteIsRowid(pChanges->a[i].zName) ){
        chngRecno = 1;
        pRecnoExpr = pChanges->a[i].pExpr;
      }else{
        sqliteErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
        goto update_cleanup;
      }
    }
#ifndef SQLITE_OMIT_AUTHORIZATION
    {
      int rc;
      rc = sqliteAuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
                           pTab->aCol[j].zName, db->aDb[pTab->iDb].zName);
      if( rc==SQLITE_DENY ){
        goto update_cleanup;
      }else if( rc==SQLITE_IGNORE ){
        aXRef[j] = -1;
      }
    }
#endif
  }

  /* Allocate memory for the array apIdx[] and fill it with pointers to every
  ** index that needs to be updated.  Indices only need updating if their
  ** key includes one of the columns named in pChanges or if the record
  ** number of the original table entry is changing.
  */
  for(nIdx=nIdxTotal=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdxTotal++){
    if( chngRecno ){
      i = 0;
    }else {
      for(i=0; i<pIdx->nColumn; i++){
        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
      }
    }
    if( i<pIdx->nColumn ) nIdx++;
  }
  if( nIdxTotal>0 ){
    apIdx = sqliteMalloc( sizeof(Index*) * nIdx + nIdxTotal );
    if( apIdx==0 ) goto update_cleanup;
    aIdxUsed = (char*)&apIdx[nIdx];
  }
  for(nIdx=j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
    if( chngRecno ){
      i = 0;
    }else{
      for(i=0; i<pIdx->nColumn; i++){
        if( aXRef[pIdx->aiColumn[i]]>=0 ) break;
      }
    }
    if( i<pIdx->nColumn ){
      apIdx[nIdx++] = pIdx;
      aIdxUsed[j] = 1;
    }else{
      aIdxUsed[j] = 0;
    }
  }

  /* Resolve the column names in all the expressions in the
  ** WHERE clause.
  */
  if( pWhere ){
    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
      goto update_cleanup;
    }
    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
      goto update_cleanup;
    }
  }

  /* Start the view context
  */
  if( isView ){
    sqliteAuthContextPush(pParse, &sContext, pTab->zName);
  }

  /* Begin generating code.
  */
  v = sqliteGetVdbe(pParse);
  if( v==0 ) goto update_cleanup;
  sqliteBeginWriteOperation(pParse, 1, pTab->iDb);

  /* If we are trying to update a view, construct that view into
  ** a temporary table.
  */
  if( isView ){
    Select *pView;
    pView = sqliteSelectDup(pTab->pSelect);
    sqliteSelect(pParse, pView, SRT_TempTable, iCur, 0, 0, 0);
    sqliteSelectDelete(pView);
  }

  /* Begin the database scan
  */
  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
  if( pWInfo==0 ) goto update_cleanup;

  /* Remember the index of every item to be updated.
  */
  sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);

  /* End the database scan loop.
  */
  sqliteWhereEnd(pWInfo);

  /* Initialize the count of updated rows
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  if( row_triggers_exist ){
    /* Create pseudo-tables for NEW and OLD
    */
    sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);

    /* The top of the update loop for when there are triggers.
    */
    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);

    /* Open a cursor and make it point to the record that is
    ** being updated.
    */
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    if( !isView ){
      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
      sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
    }
    sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);

    /* Generate the OLD table
    */
    sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
    sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);

    /* Generate the NEW table
    */
    if( chngRecno ){
      sqliteExprCode(pParse, pRecnoExpr);
    }else{
      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
    }
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        continue;
      }
      j = aXRef[i];
      if( j<0 ){
        sqliteVdbeAddOp(v, OP_Column, iCur, i);
      }else{
        sqliteExprCode(pParse, pChanges->a[j].pExpr);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
    if( !isView ){
      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
    }

    /* Fire the BEFORE and INSTEAD OF triggers
    */
    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, 
          newIdx, oldIdx, onError, addr) ){
      goto update_cleanup;
    }
  }

  if( !isView ){
    /* 
    ** 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.
    */
    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
    sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
    if( onError==OE_Replace ){
      openAll = 1;
    }else{
      openAll = 0;
      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
        if( pIdx->onError==OE_Replace ){
          openAll = 1;
          break;
        }
      }
    }
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      if( openAll || aIdxUsed[i] ){
        sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
        sqliteVdbeAddOp(v, OP_OpenWrite, iCur+i+1, pIdx->tnum);
        assert( pParse->nTab>iCur+i+1 );
      }
    }

    /* 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.
    ** So make the cursor point at the old record.
    */
    if( !row_triggers_exist ){
      sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
      addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    }
    sqliteVdbeAddOp(v, OP_NotExists, iCur, addr);

    /* If the record number will change, push the record number as it
    ** will be after the update. (The old record number is currently
    ** on top of the stack.)
    */
    if( chngRecno ){
      sqliteExprCode(pParse, pRecnoExpr);
      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
    }

    /* Compute new data for this record.  
    */
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        continue;
      }
      j = aXRef[i];
      if( j<0 ){
        sqliteVdbeAddOp(v, OP_Column, iCur, i);
      }else{
        sqliteExprCode(pParse, pChanges->a[j].pExpr);
      }
    }

    /* Do constraint checks
    */
    sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
                                   onError, addr);

    /* Delete the old indices for the current record.
    */
    sqliteGenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);

    /* If changing the record number, delete the old record.
    */
    if( chngRecno ){
      sqliteVdbeAddOp(v, OP_Delete, iCur, 0);
    }

    /* Create the new index entries and the new record.
    */
    sqliteCompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRecno, 1, -1);
  }

  /* Increment the row counter 
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
  }

  /* If there are triggers, close all the cursors after each iteration
  ** through the loop.  The fire the after triggers.
  */
  if( row_triggers_exist ){
    if( !isView ){
      for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
        if( openAll || aIdxUsed[i] )
          sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
      }
      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
      pParse->nTab = iCur;
    }
    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab, 
          newIdx, oldIdx, onError, addr) ){
      goto update_cleanup;
    }
  }

  /* Repeat the above with the next record to be updated, until
  ** all record selected by the WHERE clause have been updated.
  */
  sqliteVdbeAddOp(v, OP_Goto, 0, addr);
  sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
  sqliteVdbeAddOp(v, OP_ListReset, 0, 0);

  /* Close all tables if there were no FOR EACH ROW triggers */
  if( !row_triggers_exist ){
    for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
      if( openAll || aIdxUsed[i] ){
        sqliteVdbeAddOp(v, OP_Close, iCur+i+1, 0);
      }
    }
    sqliteVdbeAddOp(v, OP_Close, iCur, 0);
    pParse->nTab = iCur;
  }else{
    sqliteVdbeAddOp(v, OP_Close, newIdx, 0);
    sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
  }

  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
  sqliteEndWriteOperation(pParse);

  /*
  ** Return the number of rows that were changed.
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
    sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC);
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

update_cleanup:
  sqliteAuthContextPop(&sContext);
  sqliteFree(apIdx);
  sqliteFree(aXRef);
  sqliteSrcListDelete(pTabList);
  sqliteExprListDelete(pChanges);
  sqliteExprDelete(pWhere);
  return;
}
示例#3
0
文件: pragma.c 项目: AllardJ/Tomato
/*
** Process a pragma statement.  
**
** Pragmas are of this form:
**
**      PRAGMA id = value
**
** The identifier might also be a string.  The value is a string, and
** identifier, or a number.  If minusFlag is true, then the value is
** a number that was preceded by a minus sign.
*/
void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
  char *zLeft = 0;
  char *zRight = 0;
  sqlite *db = pParse->db;
  Vdbe *v = sqliteGetVdbe(pParse);
  if( v==0 ) return;

  zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
  sqliteDequote(zLeft);
  if( minusFlag ){
    zRight = 0;
    sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
  }else{
    zRight = sqliteStrNDup(pRight->z, pRight->n);
    sqliteDequote(zRight);
  }
  if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){
    sqliteFree(zLeft);
    sqliteFree(zRight);
    return;
  }
 
  /*
  **  PRAGMA default_cache_size
  **  PRAGMA default_cache_size=N
  **
  ** The first form reports the current persistent setting for the
  ** page cache size.  The value returned is the maximum number of
  ** pages in the page cache.  The second form sets both the current
  ** page cache size value and the persistent page cache size value
  ** stored in the database file.
  **
  ** The default cache size is stored in meta-value 2 of page 1 of the
  ** database file.  The cache size is actually the absolute value of
  ** this memory location.  The sign of meta-value 2 determines the
  ** synchronous setting.  A negative value means synchronous is off
  ** and a positive value means synchronous is on.
  */
  if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
    static VdbeOpList getCacheSize[] = {
      { OP_ReadCookie,  0, 2,        0},
      { OP_AbsValue,    0, 0,        0},
      { OP_Dup,         0, 0,        0},
      { OP_Integer,     0, 0,        0},
      { OP_Ne,          0, 6,        0},
      { OP_Integer,     0, 0,        0},  /* 5 */
      { OP_ColumnName,  0, 1,        "cache_size"},
      { OP_Callback,    1, 0,        0},
    };
    int addr;
    if( pRight->z==pLeft->z ){
      addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
      sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
    }else{
      int size = atoi(zRight);
      if( size<0 ) size = -size;
      sqliteBeginWriteOperation(pParse, 0, 0);
      sqliteVdbeAddOp(v, OP_Integer, size, 0);
      sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
      addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
      sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
      sqliteVdbeAddOp(v, OP_Negative, 0, 0);
      sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
      sqliteEndWriteOperation(pParse);
      db->cache_size = db->cache_size<0 ? -size : size;
      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
    }
  }else

  /*
  **  PRAGMA cache_size
  **  PRAGMA cache_size=N
  **
  ** The first form reports the current local setting for the
  ** page cache size.  The local setting can be different from
  ** the persistent cache size value that is stored in the database
  ** file itself.  The value returned is the maximum number of
  ** pages in the page cache.  The second form sets the local
  ** page cache size value.  It does not change the persistent
  ** cache size stored on the disk so the cache size will revert
  ** to its default value when the database is closed and reopened.
  ** N should be a positive integer.
  */
  if( sqliteStrICmp(zLeft,"cache_size")==0 ){
    static VdbeOpList getCacheSize[] = {
      { OP_ColumnName,  0, 1,        "cache_size"},
      { OP_Callback,    1, 0,        0},
    };
    if( pRight->z==pLeft->z ){
      int size = db->cache_size;;
      if( size<0 ) size = -size;
      sqliteVdbeAddOp(v, OP_Integer, size, 0);
      sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
    }else{
      int size = atoi(zRight);
      if( size<0 ) size = -size;
      if( db->cache_size<0 ) size = -size;
      db->cache_size = size;
      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
    }
  }else

  /*
  **  PRAGMA default_synchronous
  **  PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
  **
  ** The first form returns the persistent value of the "synchronous" setting
  ** that is stored in the database.  This is the synchronous setting that
  ** is used whenever the database is opened unless overridden by a separate
  ** "synchronous" pragma.  The second form changes the persistent and the
  ** local synchronous setting to the value given.
  **
  ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
  ** to make sure data is committed to disk.  Write operations are very fast,
  ** but a power failure can leave the database in an inconsistent state.
  ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
  ** make sure data is being written to disk.  The risk of corruption due to
  ** a power loss in this mode is negligible but non-zero.  If synchronous
  ** is FULL, extra fsync()s occur to reduce the risk of corruption to near
  ** zero, but with a write performance penalty.  The default mode is NORMAL.
  */
  if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
    static VdbeOpList getSync[] = {
      { OP_ColumnName,  0, 1,        "synchronous"},
      { OP_ReadCookie,  0, 3,        0},
      { OP_Dup,         0, 0,        0},
      { OP_If,          0, 0,        0},  /* 3 */
      { OP_ReadCookie,  0, 2,        0},
      { OP_Integer,     0, 0,        0},
      { OP_Lt,          0, 5,        0},
      { OP_AddImm,      1, 0,        0},
      { OP_Callback,    1, 0,        0},
      { OP_Halt,        0, 0,        0},
      { OP_AddImm,     -1, 0,        0},  /* 10 */
      { OP_Callback,    1, 0,        0}
    };
    if( pRight->z==pLeft->z ){
      int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
      sqliteVdbeChangeP2(v, addr+3, addr+10);
    }else{
      int addr;
      int size = db->cache_size;
      if( size<0 ) size = -size;
      sqliteBeginWriteOperation(pParse, 0, 0);
      sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
      addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
      sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
      sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
      sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
      db->safety_level = getSafetyLevel(zRight)+1;
      if( db->safety_level==1 ){
        sqliteVdbeAddOp(v, OP_Negative, 0, 0);
        size = -size;
      }
      sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
      sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
      sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
      sqliteEndWriteOperation(pParse);
      db->cache_size = size;
      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
    }
  }else

  /*
  **   PRAGMA synchronous
  **   PRAGMA synchronous=OFF|ON|NORMAL|FULL
  **
  ** Return or set the local value of the synchronous flag.  Changing
  ** the local value does not make changes to the disk file and the
  ** default value will be restored the next time the database is
  ** opened.
  */
  if( sqliteStrICmp(zLeft,"synchronous")==0 ){
    static VdbeOpList getSync[] = {
      { OP_ColumnName,  0, 1,        "synchronous"},
      { OP_Callback,    1, 0,        0},
    };
    if( pRight->z==pLeft->z ){
      sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
      sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
    }else{
      int size = db->cache_size;
      if( size<0 ) size = -size;
      db->safety_level = getSafetyLevel(zRight)+1;
      if( db->safety_level==1 ) size = -size;
      db->cache_size = size;
      sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
      sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
    }
  }else

#ifndef NDEBUG
  if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
    if( getBoolean(zRight) ){
      always_code_trigger_setup = 1;
    }else{
      always_code_trigger_setup = 0;
    }
  }else
#endif

  if( flagPragma(pParse, zLeft, zRight) ){
    /* The flagPragma() call also generates any necessary code */
  }else

  if( sqliteStrICmp(zLeft, "table_info")==0 ){
    Table *pTab;
    pTab = sqliteFindTable(db, zRight, 0);
    if( pTab ){
      static VdbeOpList tableInfoPreface[] = {
        { OP_ColumnName,  0, 0,       "cid"},
        { OP_ColumnName,  1, 0,       "name"},
        { OP_ColumnName,  2, 0,       "type"},
        { OP_ColumnName,  3, 0,       "notnull"},
        { OP_ColumnName,  4, 0,       "dflt_value"},
        { OP_ColumnName,  5, 1,       "pk"},
      };
      int i;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
      sqliteViewGetColumnNames(pParse, pTab);
      for(i=0; i<pTab->nCol; i++){
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
        sqliteVdbeOp3(v, OP_String, 0, 0,
           pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
        sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
        sqliteVdbeOp3(v, OP_String, 0, 0,
           pTab->aCol[i].zDflt, P3_STATIC);
        sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
        sqliteVdbeAddOp(v, OP_Callback, 6, 0);
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "index_info")==0 ){
    Index *pIdx;
    Table *pTab;
    pIdx = sqliteFindIndex(db, zRight, 0);
    if( pIdx ){
      static VdbeOpList tableInfoPreface[] = {
        { OP_ColumnName,  0, 0,       "seqno"},
        { OP_ColumnName,  1, 0,       "cid"},
        { OP_ColumnName,  2, 1,       "name"},
      };
      int i;
      pTab = pIdx->pTable;
      sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
      for(i=0; i<pIdx->nColumn; i++){
        int cnum = pIdx->aiColumn[i];
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
        assert( pTab->nCol>cnum );
        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "index_list")==0 ){
    Index *pIdx;
    Table *pTab;
    pTab = sqliteFindTable(db, zRight, 0);
    if( pTab ){
      v = sqliteGetVdbe(pParse);
      pIdx = pTab->pIndex;
    }
    if( pTab && pIdx ){
      int i = 0; 
      static VdbeOpList indexListPreface[] = {
        { OP_ColumnName,  0, 0,       "seq"},
        { OP_ColumnName,  1, 0,       "name"},
        { OP_ColumnName,  2, 1,       "unique"},
      };

      sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
      while(pIdx){
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
        sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
        sqliteVdbeAddOp(v, OP_Callback, 3, 0);
        ++i;
        pIdx = pIdx->pNext;
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){
    FKey *pFK;
    Table *pTab;
    pTab = sqliteFindTable(db, zRight, 0);
    if( pTab ){
      v = sqliteGetVdbe(pParse);
      pFK = pTab->pFKey;
    }
    if( pTab && pFK ){
      int i = 0; 
      static VdbeOpList indexListPreface[] = {
        { OP_ColumnName,  0, 0,       "id"},
        { OP_ColumnName,  1, 0,       "seq"},
        { OP_ColumnName,  2, 0,       "table"},
        { OP_ColumnName,  3, 0,       "from"},
        { OP_ColumnName,  4, 1,       "to"},
      };

      sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
      while(pFK){
        int j;
        for(j=0; j<pFK->nCol; j++){
          sqliteVdbeAddOp(v, OP_Integer, i, 0);
          sqliteVdbeAddOp(v, OP_Integer, j, 0);
          sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
          sqliteVdbeOp3(v, OP_String, 0, 0,
                           pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
          sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
          sqliteVdbeAddOp(v, OP_Callback, 5, 0);
        }
        ++i;
        pFK = pFK->pNextFrom;
      }
    }
  }else

  if( sqliteStrICmp(zLeft, "database_list")==0 ){
    int i;
    static VdbeOpList indexListPreface[] = {
      { OP_ColumnName,  0, 0,       "seq"},
      { OP_ColumnName,  1, 0,       "name"},
      { OP_ColumnName,  2, 1,       "file"},
    };

    sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
    for(i=0; i<db->nDb; i++){
      if( db->aDb[i].pBt==0 ) continue;
      assert( db->aDb[i].zName!=0 );
      sqliteVdbeAddOp(v, OP_Integer, i, 0);
      sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
      sqliteVdbeOp3(v, OP_String, 0, 0,
           sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
      sqliteVdbeAddOp(v, OP_Callback, 3, 0);
    }
  }else


  /*
  **   PRAGMA temp_store
  **   PRAGMA temp_store = "default"|"memory"|"file"
  **
  ** Return or set the local value of the temp_store flag.  Changing
  ** the local value does not make changes to the disk file and the default
  ** value will be restored the next time the database is opened.
  **
  ** Note that it is possible for the library compile-time options to
  ** override this setting
  */
  if( sqliteStrICmp(zLeft, "temp_store")==0 ){
    static VdbeOpList getTmpDbLoc[] = {
      { OP_ColumnName,  0, 1,        "temp_store"},
      { OP_Callback,    1, 0,        0},
    };
    if( pRight->z==pLeft->z ){
      sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
      sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
    }else{
      changeTempStorage(pParse, zRight);
    }
  }else

  /*
  **   PRAGMA default_temp_store
  **   PRAGMA default_temp_store = "default"|"memory"|"file"
  **
  ** Return or set the value of the persistent temp_store flag.  Any
  ** change does not take effect until the next time the database is
  ** opened.
  **
  ** Note that it is possible for the library compile-time options to
  ** override this setting
  */
  if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
    static VdbeOpList getTmpDbLoc[] = {
      { OP_ColumnName,  0, 1,        "temp_store"},
      { OP_ReadCookie,  0, 5,        0},
      { OP_Callback,    1, 0,        0}};
    if( pRight->z==pLeft->z ){
      sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
    }else{
      sqliteBeginWriteOperation(pParse, 0, 0);
      sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0);
      sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
      sqliteEndWriteOperation(pParse);
    }
  }else

#ifndef NDEBUG
  if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
    extern void sqliteParserTrace(FILE*, char *);
    if( getBoolean(zRight) ){
      sqliteParserTrace(stdout, "parser: ");
    }else{
      sqliteParserTrace(0, 0);
    }
  }else
#endif

  if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
    int i, j, addr;

    /* Code that initializes the integrity check program.  Set the
    ** error count 0
    */
    static VdbeOpList initCode[] = {
      { OP_Integer,     0, 0,        0},
      { OP_MemStore,    0, 1,        0},
      { OP_ColumnName,  0, 1,        "integrity_check"},
    };

    /* Code to do an BTree integrity check on a single database file.
    */
    static VdbeOpList checkDb[] = {
      { OP_SetInsert,   0, 0,        "2"},
      { OP_Integer,     0, 0,        0},    /* 1 */
      { OP_OpenRead,    0, 2,        0},
      { OP_Rewind,      0, 7,        0},    /* 3 */
      { OP_Column,      0, 3,        0},    /* 4 */
      { OP_SetInsert,   0, 0,        0},
      { OP_Next,        0, 4,        0},    /* 6 */
      { OP_IntegrityCk, 0, 0,        0},    /* 7 */
      { OP_Dup,         0, 1,        0},
      { OP_String,      0, 0,        "ok"},
      { OP_StrEq,       0, 12,       0},    /* 10 */
      { OP_MemIncr,     0, 0,        0},
      { OP_String,      0, 0,        "*** in database "},
      { OP_String,      0, 0,        0},    /* 13 */
      { OP_String,      0, 0,        " ***\n"},
      { OP_Pull,        3, 0,        0},
      { OP_Concat,      4, 1,        0},
      { OP_Callback,    1, 0,        0},
    };

    /* Code that appears at the end of the integrity check.  If no error
    ** messages have been generated, output OK.  Otherwise output the
    ** error message
    */
    static VdbeOpList endCode[] = {
      { OP_MemLoad,     0, 0,        0},
      { OP_Integer,     0, 0,        0},
      { OP_Ne,          0, 0,        0},    /* 2 */
      { OP_String,      0, 0,        "ok"},
      { OP_Callback,    1, 0,        0},
    };

    /* Initialize the VDBE program */
    sqliteVdbeAddOpList(v, ArraySize(initCode), initCode);

    /* Do an integrity check on each database file */
    for(i=0; i<db->nDb; i++){
      HashElem *x;

      /* Do an integrity check of the B-Tree
      */
      addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
      sqliteVdbeChangeP1(v, addr+1, i);
      sqliteVdbeChangeP2(v, addr+3, addr+7);
      sqliteVdbeChangeP2(v, addr+6, addr+4);
      sqliteVdbeChangeP2(v, addr+7, i);
      sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
      sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);

      /* Make sure all the indices are constructed correctly.
      */
      sqliteCodeVerifySchema(pParse, i);
      for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx;
        int loopTop;

        if( pTab->pIndex==0 ) continue;
        sqliteVdbeAddOp(v, OP_Integer, i, 0);
        sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          if( pIdx->tnum==0 ) continue;
          sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
          sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
        }
        sqliteVdbeAddOp(v, OP_Integer, 0, 0);
        sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
        loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0);
        sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          int k, jmp2;
          static VdbeOpList idxErr[] = {
            { OP_MemIncr,     0,  0,  0},
            { OP_String,      0,  0,  "rowid "},
            { OP_Recno,       1,  0,  0},
            { OP_String,      0,  0,  " missing from index "},
            { OP_String,      0,  0,  0},    /* 4 */
            { OP_Concat,      4,  0,  0},
            { OP_Callback,    1,  0,  0},
          };
          sqliteVdbeAddOp(v, OP_Recno, 1, 0);
          for(k=0; k<pIdx->nColumn; k++){
            int idx = pIdx->aiColumn[k];
            if( idx==pTab->iPKey ){
              sqliteVdbeAddOp(v, OP_Recno, 1, 0);
            }else{
              sqliteVdbeAddOp(v, OP_Column, 1, idx);
            }
          }
          sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
          if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
          jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0);
          addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr);
          sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
          sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v));
        }
        sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
        sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
        for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
          static VdbeOpList cntIdx[] = {
             { OP_Integer,      0,  0,  0},
             { OP_MemStore,     2,  1,  0},
             { OP_Rewind,       0,  0,  0},  /* 2 */
             { OP_MemIncr,      2,  0,  0},
             { OP_Next,         0,  0,  0},  /* 4 */
             { OP_MemLoad,      1,  0,  0},
             { OP_MemLoad,      2,  0,  0},
             { OP_Eq,           0,  0,  0},  /* 7 */
             { OP_MemIncr,      0,  0,  0},
             { OP_String,       0,  0,  "wrong # of entries in index "},
             { OP_String,       0,  0,  0},  /* 10 */
             { OP_Concat,       2,  0,  0},
             { OP_Callback,     1,  0,  0},
          };
          if( pIdx->tnum==0 ) continue;
          addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
          sqliteVdbeChangeP1(v, addr+2, j+2);
          sqliteVdbeChangeP2(v, addr+2, addr+5);
          sqliteVdbeChangeP1(v, addr+4, j+2);
          sqliteVdbeChangeP2(v, addr+4, addr+3);
          sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
          sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
        }
      } 
    }
    addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode);
    sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
  }else

  {}
  sqliteFree(zLeft);
  sqliteFree(zRight);
}
示例#4
0
static int sqliteCompileStmt(
  Parse *pParse,    /* parse context */
  Block *b,         /* current block */
  Stmt* pStmt,      /* statement to compile */
  int *tailgoto,    /* set *tailgoto to 1 if last statement is a goto */
  int in_excep      /* set to 1 when compiling an exception handler */
){
  Vdbe *v = sqliteGetVdbe(pParse);
  SrcList dummy;
  int i, j, skipgoto = 0;

  dummy.nSrc = 0;

  if( tailgoto ) *tailgoto = 0;

  if( pStmt->op!=TK_RAISE && pStmt->op!=TK_PROCEDURE && pStmt->pExpr1 ){
    Expr *pExpr = pStmt->pExpr1;
    if( pStmt->op==TK_FOR ) {
      /* allocate the FOR counter variable (see case TK_FOR below) */
      sqliteAddProcVar(pParse, &(pExpr->pLeft->token));
    }
    if( sqliteExprProcResolve(pParse, b, pExpr) ){
      return 1;
    }
    if( sqliteExprCheck(pParse, pExpr, 0, 0) ){
      return 1;
    }
  }

  switch( pStmt->op ) {

  case TK_ASSIGN:{
    Expr *pLeft = pStmt->pExpr1->pLeft;
    Expr *pRight = pStmt->pExpr1->pRight;

    assert( pStmt->pExpr1->op==TK_ASSIGN );
	  assert( pLeft->op==TK_VAR );
    sqliteExprCode(pParse, pRight);
	  if( pLeft->flags==EP_NotNull ){
      i = sqliteVdbeMakeLabel(v);
      sqliteVdbeAddOp(v, OP_NotNull, -1, i);
	    sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
                           "attempt to store null in non-null var", P3_STATIC);
      sqliteVdbeResolveLabel(v, i);
    }
    sqliteVdbeAddOp(v, OP_MemStore, pLeft->iColumn, 1);
	  break;
  }

  case TK_BLOCK:{
    if( sqliteCompileBlock(pParse, pStmt->pBlock) ){
      return 1;
    }
	  break;
  }

  case TK_CASE:{
    int jumpInst, addr;
    int nStmt;
    int searched;

    nStmt = pStmt->pStmt1->nStmt;
    searched = pStmt->pExpr1==0;
    assert( nStmt>0 );
    j = sqliteVdbeMakeLabel(v);
    if( !searched ){
      sqliteExprCode(pParse, pStmt->pExpr1);
    }
    for(i=0; i<nStmt; i++){
      Stmt *pWhen = pStmt->pStmt1->a[i].pStmt;
      assert( pWhen->op==TK_WHEN );
      if( sqliteExprProcResolve(pParse, b, pWhen->pExpr1) ){
        return 1;
      }
      if( sqliteExprCheck(pParse, pWhen->pExpr1, 0, 0) ){
        return 1;
      }
      sqliteExprCode(pParse, pWhen->pExpr1);
      if( !searched ){
        sqliteVdbeAddOp(v, OP_Dup, 1, 1);
        jumpInst = sqliteVdbeAddOp(v, OP_Ne, 1, 0);
      }else{
        jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 1, 0);
      }
	    if( sqliteCompileList(pParse, b, pWhen->pStmt1, &skipgoto, 0) ){
	      return 1;
      }
      if( !skipgoto ) {
        sqliteVdbeAddOp(v, OP_Goto, 0, j);
      }
      addr = sqliteVdbeCurrentAddr(v);
      sqliteVdbeChangeP2(v, jumpInst, addr);
    }
    if( !searched ){
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
    }
    if( pStmt->pStmt2 ){
      assert( pStmt->pStmt2->op==TK_ELSE );
	    if( sqliteCompileList(pParse, b, pStmt->pStmt2->pStmt1, tailgoto, 0) ){
	      return 1;
      }
    }else{
      sqliteVdbeOp3(v, OP_Raise, 0, 0, "CASE_NOT_FOUND", P3_STATIC);
      if( tailgoto ) *tailgoto = 1;
    }
    sqliteVdbeResolveLabel(v, j);
    break;
  }

  case TK_EXIT:{
    if( pParse->iLoopExit==0 ) {
      sqliteErrorMsg(pParse, "EXIT used outside loop statement", 0);
      return 1;
    }
    if( pStmt->pExpr1 ) {
      sqliteExprCode(pParse, pStmt->pExpr1);
      sqliteVdbeAddOp(v, OP_If, 1, pParse->iLoopExit);
    } else {
      sqliteVdbeAddOp(v, OP_Goto, 0, pParse->iLoopExit);
      if( tailgoto ) *tailgoto = 1;
    }
	  break;
  }

  case TK_FOR:{
    Expr *pLow = pStmt->pExpr1->pRight->pLeft;
    Expr *pHigh = pStmt->pExpr1->pRight->pRight;
    int iCounter, iHigh, iPrevExit;

	  assert( pStmt->pExpr1->op==TK_ASSIGN );
	  assert( pStmt->pExpr1->pLeft->op==TK_VAR );
	  assert( pStmt->pExpr1->pRight->op==TK_FOR );
    iCounter = pParse->nMem-1;
    iHigh = pParse->nMem++;
    sqliteExprCode(pParse, pLow);
    sqliteVdbeAddOp(v, OP_MemStore, iCounter, 1);
    sqliteExprCode(pParse, pHigh);
    sqliteVdbeAddOp(v, OP_MemStore, iHigh, 1);
    sqliteVdbeAddOp(v, OP_MemLoad, iCounter, 0);
    i = sqliteVdbeCurrentAddr(v);
    sqliteVdbeAddOp(v, OP_MemLoad, iHigh, 0);
    iPrevExit = pParse->iLoopExit;
    pParse->iLoopExit = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_Gt, 1, pParse->iLoopExit);
	  if( sqliteCompileList(pParse, b, pStmt->pStmt1, 0, 0) ){
	    return 1;
    }
    sqliteVdbeAddOp(v, OP_MemLoad, iCounter, 0);
    sqliteVdbeAddOp(v, OP_Integer, 1, 0);
    sqliteVdbeAddOp(v, OP_Add, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iCounter, 0);
    sqliteVdbeAddOp(v, OP_Goto, 0, i);
    sqliteVdbeResolveLabel(v, pParse->iLoopExit);
    pParse->iLoopExit = iPrevExit;
    hideVar(b, iCounter);
    break;
  }

  case TK_IF: {
    i = sqliteVdbeMakeLabel(v);
    j = sqliteVdbeMakeLabel(v);
    sqliteExprCode(pParse, pStmt->pExpr1);
    sqliteVdbeAddOp(v, OP_IfNot, 1, j);
	  if( sqliteCompileList(pParse, b, pStmt->pStmt1, &skipgoto, 0) ){
	    return 1;
    }
    while( pStmt->pStmt2 ) {
      if( !skipgoto ) {
        sqliteVdbeAddOp(v, OP_Goto, 0, i);
      }
      sqliteVdbeResolveLabel(v, j);
      j = sqliteVdbeMakeLabel(v);
      pStmt = pStmt->pStmt2;
      assert( pStmt->op==TK_ELSE || pStmt->op==TK_ELSIF );
      if( pStmt->op==TK_ELSIF ) {
        if( sqliteExprProcResolve(pParse, b, pStmt->pExpr1) ){
          return 1;
        }
        if( sqliteExprCheck(pParse, pStmt->pExpr1, 0, 0) ){
          return 1;
        }
        sqliteExprCode(pParse, pStmt->pExpr1);
        sqliteVdbeAddOp(v, OP_IfNot, 1, j);
      }
	    if( sqliteCompileList(pParse, b, pStmt->pStmt1, &skipgoto, 0) ){
	      return 1;
      }
    }
    sqliteVdbeResolveLabel(v, i);
    sqliteVdbeResolveLabel(v, j);
	  break;
  }

  case TK_LOOP:{
    int iPrevExit = pParse->iLoopExit;
    pParse->iLoopExit = sqliteVdbeMakeLabel(v);
    i = sqliteVdbeCurrentAddr(v);
	  if( sqliteCompileList(pParse, b, pStmt->pStmt1, 0, 0) ){
	    return 1;
    }
    sqliteVdbeAddOp(v, OP_Goto, 0, i);
    sqliteVdbeResolveLabel(v, pParse->iLoopExit);
    pParse->iLoopExit = iPrevExit;
	  break;
  }

  case TK_NULL:{
	  break;
  }

  case TK_PRINT:{
    sqliteExprCode(pParse, pStmt->pExpr1);
    sqliteVdbeAddOp(v, OP_Print, 0, 0);
	  break;
  }

  case TK_PROCEDURE: {
    Expr *pExpr = pStmt->pExpr1;
    if( sqliteCompileCall(pParse, &(pExpr->token), pExpr->pList) ) {
      return 1;
    }
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
	  break;
  }

  case TK_RAISE:{
    if( pStmt->pExpr1==0 ) {
      if( !in_excep ) {
        sqliteErrorMsg(pParse, "RAISE without argument illegal outside exception handler", 0);
        return 1;
      }
      sqliteVdbeOp3(v, OP_Raise, 0, 0, 0, P3_STATIC);
    } else {
      char *zName = 0;
      sqliteSetNString(&zName, pStmt->pExpr1->token.z, pStmt->pExpr1->token.n, 0);
      sqliteVdbeOp3(v, OP_Raise, 0, 0, zName, P3_DYNAMIC);
    }
    if( tailgoto ) *tailgoto = 1;
	  break;
  }

  case TK_RETURN:{
    sqliteExprCode(pParse, pStmt->pExpr1);
    sqliteVdbeAddOp(v, OP_MemStore, b->mReturn, 1);
    sqliteVdbeAddOp(v, OP_Goto, 0, b->nExit);
    if( tailgoto ) *tailgoto = 1;
	  break;
  }

  case TK_SQL:{
	  sqliteCompileSQLStmt(pParse, b, pStmt->pSql);
	  break;
  }

  case TK_WHILE:{
    int iPrevExit = pParse->iLoopExit;
    pParse->iLoopExit = sqliteVdbeMakeLabel(v);
    i = sqliteVdbeCurrentAddr(v);
    sqliteExprCode(pParse, pStmt->pExpr1);
    sqliteVdbeAddOp(v, OP_IfNot, 1, pParse->iLoopExit);
	  if( sqliteCompileList(pParse, b, pStmt->pStmt1, 0, 0) ){
	    return 1;
    }
    sqliteVdbeAddOp(v, OP_Goto, 0, i);
    sqliteVdbeResolveLabel(v, pParse->iLoopExit);
    pParse->iLoopExit = iPrevExit;
	  break;
  }

  }
  return 0;
}
示例#5
0
文件: insert.c 项目: andreiw/polaris
/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
**    insert into TABLE (IDLIST) select
**
** The IDLIST following the table name is always optional.  If omitted,
** then a list of all columns for the table is substituted.  The IDLIST
** appears in the pColumn parameter.  pColumn is NULL if IDLIST is omitted.
**
** The pList parameter holds EXPRLIST in the first form of the INSERT
** statement above, and pSelect is NULL.  For the second form, pList is
** NULL and pSelect is a pointer to the select statement used to generate
** data for the insert.
**
** The code generated follows one of three templates.  For a simple
** select with data coming from a VALUES clause, the code executes
** once straight down through.  The template looks like this:
**
**         open write cursor to <table> and its indices
**         puts VALUES clause expressions onto the stack
**         write the resulting record into <table>
**         cleanup
**
** If the statement is of the form
**
**   INSERT INTO <table> SELECT ...
**
** And the SELECT clause does not read from <table> at any time, then
** the generated code follows this template:
**
**         goto B
**      A: setup for the SELECT
**         loop over the tables in the SELECT
**           gosub C
**         end loop
**         cleanup after the SELECT
**         goto D
**      B: open write cursor to <table> and its indices
**         goto A
**      C: insert the select result into <table>
**         return
**      D: cleanup
**
** The third template is used if the insert statement takes its
** values from a SELECT but the data is being inserted into a table
** that is also read as part of the SELECT.  In the third form,
** we have to use a intermediate table to store the results of
** the select.  The template is like this:
**
**         goto B
**      A: setup for the SELECT
**         loop over the tables in the SELECT
**           gosub C
**         end loop
**         cleanup after the SELECT
**         goto D
**      C: insert the select result into the intermediate table
**         return
**      B: open a cursor to an intermediate table
**         goto A
**      D: open write cursor to <table> and its indices
**         loop over the intermediate table
**           transfer values form intermediate table into <table>
**         end the loop
**         cleanup
*/
void sqliteInsert(
  Parse *pParse,        /* Parser context */
  SrcList *pTabList,    /* Name of table into which we are inserting */
  ExprList *pList,      /* List of values to be inserted */
  Select *pSelect,      /* A SELECT statement to use as the data source */
  IdList *pColumn,      /* Column names corresponding to IDLIST. */
  int onError           /* How to handle constraint errors */
){
  Table *pTab;          /* The table to insert into */
  char *zTab;           /* Name of the table into which we are inserting */
  const char *zDb;      /* Name of the database holding this table */
  int i, j, idx;        /* Loop counters */
  Vdbe *v;              /* Generate code into this virtual machine */
  Index *pIdx;          /* For looping over indices of the table */
  int nColumn;          /* Number of columns in the data */
  int base;             /* VDBE Cursor number for pTab */
  int iCont, iBreak;    /* Beginning and end of the loop over srcTab */
  sqlite *db;           /* The main database structure */
  int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
  int endOfLoop;        /* Label for the end of the insertion loop */
  int useTempTable;     /* Store SELECT results in intermediate table */
  int srcTab;           /* Data comes from this temporary cursor if >=0 */
  int iSelectLoop;      /* Address of code that implements the SELECT */
  int iCleanup;         /* Address of the cleanup code */
  int iInsertBlock;     /* Address of the subroutine used to insert data */
  int iCntMem;          /* Memory cell used for the row counter */
  int isView;           /* True if attempting to insert into a view */

  int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
  int before_triggers;        /* True if there are BEFORE triggers */
  int after_triggers;         /* True if there are AFTER triggers */
  int newIdx = -1;            /* Cursor for the NEW table */

  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  assert( pTabList->nSrc==1 );
  zTab = pTabList->a[0].zName;
  if( zTab==0 ) goto insert_cleanup;
  pTab = sqliteSrcListLookup(pParse, pTabList);
  if( pTab==0 ){
    goto insert_cleanup;
  }
  assert( pTab->iDb<db->nDb );
  zDb = db->aDb[pTab->iDb].zName;
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
    goto insert_cleanup;
  }

  /* Ensure that:
  *  (a) the table is not read-only, 
  *  (b) that if it is a view then ON INSERT triggers exist
  */
  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, 
                                       TK_BEFORE, TK_ROW, 0);
  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,
                                       TK_AFTER, TK_ROW, 0);
  row_triggers_exist = before_triggers || after_triggers;
  isView = pTab->pSelect!=0;
  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
    goto insert_cleanup;
  }
  if( pTab==0 ) goto insert_cleanup;

  /* If pTab is really a view, make sure it has been initialized.
  */
  if( isView && sqliteViewGetColumnNames(pParse, pTab) ){
    goto insert_cleanup;
  }

  /* Allocate a VDBE
  */
  v = sqliteGetVdbe(pParse);
  if( v==0 ) goto insert_cleanup;
  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist, pTab->iDb);

  /* if there are row triggers, allocate a temp table for new.* references. */
  if( row_triggers_exist ){
    newIdx = pParse->nTab++;
  }

  /* Figure out how many columns of data are supplied.  If the data
  ** is coming from a SELECT statement, then this step also generates
  ** all the code to implement the SELECT statement and invoke a subroutine
  ** to process each row of the result. (Template 2.) If the SELECT
  ** statement uses the the table that is being inserted into, then the
  ** subroutine is also coded here.  That subroutine stores the SELECT
  ** results in a temporary table. (Template 3.)
  */
  if( pSelect ){
    /* Data is coming from a SELECT.  Generate code to implement that SELECT
    */
    int rc, iInitCode;
    iInitCode = sqliteVdbeAddOp(v, OP_Goto, 0, 0);
    iSelectLoop = sqliteVdbeCurrentAddr(v);
    iInsertBlock = sqliteVdbeMakeLabel(v);
    rc = sqliteSelect(pParse, pSelect, SRT_Subroutine, iInsertBlock, 0,0,0);
    if( rc || pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
    iCleanup = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_Goto, 0, iCleanup);
    assert( pSelect->pEList );
    nColumn = pSelect->pEList->nExpr;

    /* Set useTempTable to TRUE if the result of the SELECT statement
    ** should be written into a temporary table.  Set to FALSE if each
    ** row of the SELECT can be written directly into the result table.
    **
    ** A temp table must be used if the table being updated is also one
    ** of the tables being read by the SELECT statement.  Also use a 
    ** temp table in the case of row triggers.
    */
    if( row_triggers_exist ){
      useTempTable = 1;
    }else{
      int addr = sqliteVdbeFindOp(v, OP_OpenRead, pTab->tnum);
      useTempTable = 0;
      if( addr>0 ){
        VdbeOp *pOp = sqliteVdbeGetOp(v, addr-2);
        if( pOp->opcode==OP_Integer && pOp->p1==pTab->iDb ){
          useTempTable = 1;
        }
      }
    }

    if( useTempTable ){
      /* Generate the subroutine that SELECT calls to process each row of
      ** the result.  Store the result in a temporary table
      */
      srcTab = pParse->nTab++;
      sqliteVdbeResolveLabel(v, iInsertBlock);
      sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0);
      sqliteVdbeAddOp(v, OP_NewRecno, srcTab, 0);
      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
      sqliteVdbeAddOp(v, OP_PutIntKey, srcTab, 0);
      sqliteVdbeAddOp(v, OP_Return, 0, 0);

      /* The following code runs first because the GOTO at the very top
      ** of the program jumps to it.  Create the temporary table, then jump
      ** back up and execute the SELECT code above.
      */
      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
      sqliteVdbeAddOp(v, OP_OpenTemp, srcTab, 0);
      sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
      sqliteVdbeResolveLabel(v, iCleanup);
    }else{
      sqliteVdbeChangeP2(v, iInitCode, sqliteVdbeCurrentAddr(v));
    }
  }else{
    /* This is the case if the data for the INSERT is coming from a VALUES
    ** clause
    */
    SrcList dummy;
    assert( pList!=0 );
    srcTab = -1;
    useTempTable = 0;
    assert( pList );
    nColumn = pList->nExpr;
    dummy.nSrc = 0;
    for(i=0; i<nColumn; i++){
      if( sqliteExprResolveIds(pParse, &dummy, 0, pList->a[i].pExpr) ){
        goto insert_cleanup;
      }
      if( sqliteExprCheck(pParse, pList->a[i].pExpr, 0, 0) ){
        goto insert_cleanup;
      }
    }
  }

  /* Make sure the number of columns in the source data matches the number
  ** of columns to be inserted into the table.
  */
  if( pColumn==0 && nColumn!=pTab->nCol ){
    sqliteErrorMsg(pParse, 
       "table %S has %d columns but %d values were supplied",
       pTabList, 0, pTab->nCol, nColumn);
    goto insert_cleanup;
  }
  if( pColumn!=0 && nColumn!=pColumn->nId ){
    sqliteErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
    goto insert_cleanup;
  }

  /* If the INSERT statement included an IDLIST term, then make sure
  ** all elements of the IDLIST really are columns of the table and 
  ** remember the column indices.
  **
  ** If the table has an INTEGER PRIMARY KEY column and that column
  ** is named in the IDLIST, then record in the keyColumn variable
  ** the index into IDLIST of the primary key column.  keyColumn is
  ** the index of the primary key as it appears in IDLIST, not as
  ** is appears in the original table.  (The index of the primary
  ** key in the original table is pTab->iPKey.)
  */
  if( pColumn ){
    for(i=0; i<pColumn->nId; i++){
      pColumn->a[i].idx = -1;
    }
    for(i=0; i<pColumn->nId; i++){
      for(j=0; j<pTab->nCol; j++){
        if( sqliteStrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
          pColumn->a[i].idx = j;
          if( j==pTab->iPKey ){
            keyColumn = i;
          }
          break;
        }
      }
      if( j>=pTab->nCol ){
        if( sqliteIsRowid(pColumn->a[i].zName) ){
          keyColumn = i;
        }else{
          sqliteErrorMsg(pParse, "table %S has no column named %s",
              pTabList, 0, pColumn->a[i].zName);
          pParse->nErr++;
          goto insert_cleanup;
        }
      }
    }
  }

  /* If there is no IDLIST term but the table has an integer primary
  ** key, the set the keyColumn variable to the primary key column index
  ** in the original table definition.
  */
  if( pColumn==0 ){
    keyColumn = pTab->iPKey;
  }

  /* Open the temp table for FOR EACH ROW triggers
  */
  if( row_triggers_exist ){
    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
  }
    
  /* Initialize the count of rows to be inserted
  */
  if( db->flags & SQLITE_CountRows ){
    iCntMem = pParse->nMem++;
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
    sqliteVdbeAddOp(v, OP_MemStore, iCntMem, 1);
  }

  /* Open tables and indices if there are no row triggers */
  if( !row_triggers_exist ){
    base = pParse->nTab;
    idx = sqliteOpenTableAndIndices(pParse, pTab, base);
    pParse->nTab += idx;
  }

  /* If the data source is a temporary table, then we have to create
  ** a loop because there might be multiple rows of data.  If the data
  ** source is a subroutine call from the SELECT statement, then we need
  ** to launch the SELECT statement processing.
  */
  if( useTempTable ){
    iBreak = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
    iCont = sqliteVdbeCurrentAddr(v);
  }else if( pSelect ){
    sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
    sqliteVdbeResolveLabel(v, iInsertBlock);
  }

  /* Run the BEFORE and INSTEAD OF triggers, if there are any
  */
  endOfLoop = sqliteVdbeMakeLabel(v);
  if( before_triggers ){

    /* build the NEW.* reference row.  Note that if there is an INTEGER
    ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
    ** translated into a unique ID for the row.  But on a BEFORE trigger,
    ** we do not know what the unique ID will be (because the insert has
    ** not happened yet) so we substitute a rowid of -1
    */
    if( keyColumn<0 ){
      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
    }else if( useTempTable ){
      sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
    }else if( pSelect ){
      sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
    }else{
      sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
    }

    /* Create the new column data
    */
    for(i=0; i<pTab->nCol; i++){
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( pColumn && j>=pColumn->nId ){
        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
      }else if( useTempTable ){
        sqliteVdbeAddOp(v, OP_Column, srcTab, j); 
      }else if( pSelect ){
        sqliteVdbeAddOp(v, OP_Dup, nColumn-j-1, 1);
      }else{
        sqliteExprCode(pParse, pList->a[j].pExpr);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);

    /* Fire BEFORE or INSTEAD OF triggers */
    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, 
        newIdx, -1, onError, endOfLoop) ){
      goto insert_cleanup;
    }
  }

  /* If any triggers exists, the opening of tables and indices is deferred
  ** until now.
  */
  if( row_triggers_exist && !isView ){
    base = pParse->nTab;
    idx = sqliteOpenTableAndIndices(pParse, pTab, base);
    pParse->nTab += idx;
  }

  /* Push the record number for the new entry onto the stack.  The
  ** record number is a randomly generate integer created by NewRecno
  ** except when the table has an INTEGER PRIMARY KEY column, in which
  ** case the record number is the same as that column. 
  */
  if( !isView ){
    if( keyColumn>=0 ){
      if( useTempTable ){
        sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
      }else if( pSelect ){
        sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
      }else{
        sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
      }
      /* If the PRIMARY KEY expression is NULL, then use OP_NewRecno
      ** to generate a unique primary key value.
      */
      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
    }else{
      sqliteVdbeAddOp(v, OP_NewRecno, base, 0);
    }

    /* Push onto the stack, data for all columns of the new entry, beginning
    ** with the first column.
    */
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        /* The value of the INTEGER PRIMARY KEY column is always a NULL.
        ** Whenever this column is read, the record number will be substituted
        ** in its place.  So will fill this column with a NULL to avoid
        ** taking up data space with information that will never be used. */
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        continue;
      }
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
      }
      if( pColumn && j>=pColumn->nId ){
        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
      }else if( useTempTable ){
        sqliteVdbeAddOp(v, OP_Column, srcTab, j); 
      }else if( pSelect ){
        sqliteVdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
      }else{
        sqliteExprCode(pParse, pList->a[j].pExpr);
      }
    }

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
    sqliteGenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
                                   0, onError, endOfLoop);
    sqliteCompleteInsertion(pParse, pTab, base, 0,0,0,
                            after_triggers ? newIdx : -1);
  }

  /* Update the count of rows that are inserted
  */
  if( (db->flags & SQLITE_CountRows)!=0 ){
    sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0);
  }

  if( row_triggers_exist ){
    /* Close all tables opened */
    if( !isView ){
      sqliteVdbeAddOp(v, OP_Close, base, 0);
      for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
        sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
      }
    }

    /* Code AFTER triggers */
    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_AFTER, pTab, newIdx, -1, 
          onError, endOfLoop) ){
      goto insert_cleanup;
    }
  }

  /* The bottom of the loop, if the data source is a SELECT statement
  */
  sqliteVdbeResolveLabel(v, endOfLoop);
  if( useTempTable ){
    sqliteVdbeAddOp(v, OP_Next, srcTab, iCont);
    sqliteVdbeResolveLabel(v, iBreak);
    sqliteVdbeAddOp(v, OP_Close, srcTab, 0);
  }else if( pSelect ){
    sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
    sqliteVdbeAddOp(v, OP_Return, 0, 0);
    sqliteVdbeResolveLabel(v, iCleanup);
  }

  if( !row_triggers_exist ){
    /* Close all tables opened */
    sqliteVdbeAddOp(v, OP_Close, base, 0);
    for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
      sqliteVdbeAddOp(v, OP_Close, idx+base, 0);
    }
  }

  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
  sqliteEndWriteOperation(pParse);

  /*
  ** Return the number of rows inserted.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows inserted", P3_STATIC);
    sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0);
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

insert_cleanup:
  sqliteSrcListDelete(pTabList);
  if( pList ) sqliteExprListDelete(pList);
  if( pSelect ) sqliteSelectDelete(pSelect);
  sqliteIdListDelete(pColumn);
}
示例#6
0
文件: insert.c 项目: andreiw/polaris
/*
** Generate code to do a constraint check prior to an INSERT or an UPDATE.
**
** When this routine is called, the stack contains (from bottom to top)
** the following values:
**
**    1.  The recno of the row to be updated before the update.  This
**        value is omitted unless we are doing an UPDATE that involves a
**        change to the record number.
**
**    2.  The recno of the row after the update.
**
**    3.  The data in the first column of the entry after the update.
**
**    i.  Data from middle columns...
**
**    N.  The data in the last column of the entry after the update.
**
** The old recno shown as entry (1) above is omitted unless both isUpdate
** and recnoChng are 1.  isUpdate is true for UPDATEs and false for
** INSERTs and recnoChng is true if the record number is being changed.
**
** The code generated by this routine pushes additional entries onto
** the stack which are the keys for new index entries for the new record.
** The order of index keys is the same as the order of the indices on
** the pTable->pIndex list.  A key is only created for index i if 
** aIdxUsed!=0 and aIdxUsed[i]!=0.
**
** This routine also generates code to check constraints.  NOT NULL,
** CHECK, and UNIQUE constraints are all checked.  If a constraint fails,
** then the appropriate action is performed.  There are five possible
** actions: ROLLBACK, ABORT, FAIL, REPLACE, and IGNORE.
**
**  Constraint type  Action       What Happens
**  ---------------  ----------   ----------------------------------------
**  any              ROLLBACK     The current transaction is rolled back and
**                                sqlite_exec() returns immediately with a
**                                return code of SQLITE_CONSTRAINT.
**
**  any              ABORT        Back out changes from the current command
**                                only (do not do a complete rollback) then
**                                cause sqlite_exec() to return immediately
**                                with SQLITE_CONSTRAINT.
**
**  any              FAIL         Sqlite_exec() returns immediately with a
**                                return code of SQLITE_CONSTRAINT.  The
**                                transaction is not rolled back and any
**                                prior changes are retained.
**
**  any              IGNORE       The record number and data is popped from
**                                the stack and there is an immediate jump
**                                to label ignoreDest.
**
**  NOT NULL         REPLACE      The NULL value is replace by the default
**                                value for that column.  If the default value
**                                is NULL, the action is the same as ABORT.
**
**  UNIQUE           REPLACE      The other row that conflicts with the row
**                                being inserted is removed.
**
**  CHECK            REPLACE      Illegal.  The results in an exception.
**
** Which action to take is determined by the overrideError parameter.
** Or if overrideError==OE_Default, then the pParse->onError parameter
** is used.  Or if pParse->onError==OE_Default then the onError value
** for the constraint is used.
**
** The calling routine must open a read/write cursor for pTab with
** cursor number "base".  All indices of pTab must also have open
** read/write cursors with cursor number base+i for the i-th cursor.
** Except, if there is no possibility of a REPLACE action then
** cursors do not need to be open for indices where aIdxUsed[i]==0.
**
** If the isUpdate flag is true, it means that the "base" cursor is
** initially pointing to an entry that is being updated.  The isUpdate
** flag causes extra code to be generated so that the "base" cursor
** is still pointing at the same entry after the routine returns.
** Without the isUpdate flag, the "base" cursor might be moved.
*/
void sqliteGenerateConstraintChecks(
  Parse *pParse,      /* The parser context */
  Table *pTab,        /* the table into which we are inserting */
  int base,           /* Index of a read/write cursor pointing at pTab */
  char *aIdxUsed,     /* Which indices are used.  NULL means all are used */
  int recnoChng,      /* True if the record number will change */
  int isUpdate,       /* True for UPDATE, False for INSERT */
  int overrideError,  /* Override onError to this if not OE_Default */
  int ignoreDest      /* Jump to this label on an OE_Ignore resolution */
){
  int i;
  Vdbe *v;
  int nCol;
  int onError;
  int addr;
  int extra;
  int iCur;
  Index *pIdx;
  int seenReplace = 0;
  int jumpInst1, jumpInst2;
  int contAddr;
  int hasTwoRecnos = (isUpdate && recnoChng);

  v = sqliteGetVdbe(pParse);
  assert( v!=0 );
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  nCol = pTab->nCol;

  /* Test all NOT NULL constraints.
  */
  for(i=0; i<nCol; i++){
    if( i==pTab->iPKey ){
      continue;
    }
    onError = pTab->aCol[i].notNull;
    if( onError==OE_None ) continue;
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( pParse->db->onError!=OE_Default ){
      onError = pParse->db->onError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    if( onError==OE_Replace && pTab->aCol[i].zDflt==0 ){
      onError = OE_Abort;
    }
    sqliteVdbeAddOp(v, OP_Dup, nCol-1-i, 1);
    addr = sqliteVdbeAddOp(v, OP_NotNull, 1, 0);
    switch( onError ){
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {
        char *zMsg = 0;
        sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
        sqliteSetString(&zMsg, pTab->zName, ".", pTab->aCol[i].zName,
                        " may not be NULL", (char*)0);
        sqliteVdbeChangeP3(v, -1, zMsg, P3_DYNAMIC);
        break;
      }
      case OE_Ignore: {
        sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
        break;
      }
      case OE_Replace: {
        sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
        sqliteVdbeAddOp(v, OP_Push, nCol-i, 0);
        break;
      }
      default: assert(0);
    }
    sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
  }

  /* Test all CHECK constraints
  */
  /**** TBD ****/

  /* If we have an INTEGER PRIMARY KEY, make sure the primary key
  ** of the new record does not previously exist.  Except, if this
  ** is an UPDATE and the primary key is not changing, that is OK.
  */
  if( recnoChng ){
    onError = pTab->keyConf;
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( pParse->db->onError!=OE_Default ){
      onError = pParse->db->onError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    
    if( isUpdate ){
      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
      jumpInst1 = sqliteVdbeAddOp(v, OP_Eq, 0, 0);
    }
    sqliteVdbeAddOp(v, OP_Dup, nCol, 1);
    jumpInst2 = sqliteVdbeAddOp(v, OP_NotExists, base, 0);
    switch( onError ){
      default: {
        onError = OE_Abort;
        /* Fall thru into the next case */
      }
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {
        sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
                         "PRIMARY KEY must be unique", P3_STATIC);
        break;
      }
      case OE_Replace: {
        sqliteGenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
        if( isUpdate ){
          sqliteVdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1);
          sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
        }
        seenReplace = 1;
        break;
      }
      case OE_Ignore: {
        assert( seenReplace==0 );
        sqliteVdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0);
        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
        break;
      }
    }
    contAddr = sqliteVdbeCurrentAddr(v);
    sqliteVdbeChangeP2(v, jumpInst2, contAddr);
    if( isUpdate ){
      sqliteVdbeChangeP2(v, jumpInst1, contAddr);
      sqliteVdbeAddOp(v, OP_Dup, nCol+1, 1);
      sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
    }
  }

  /* Test all UNIQUE constraints by creating entries for each UNIQUE
  ** index and making sure that duplicate entries do not already exist.
  ** Add the new records to the indices as we go.
  */
  extra = -1;
  for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
    if( aIdxUsed && aIdxUsed[iCur]==0 ) continue;  /* Skip unused indices */
    extra++;

    /* Create a key for accessing the index entry */
    sqliteVdbeAddOp(v, OP_Dup, nCol+extra, 1);
    for(i=0; i<pIdx->nColumn; i++){
      int idx = pIdx->aiColumn[i];
      if( idx==pTab->iPKey ){
        sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol+1, 1);
      }else{
        sqliteVdbeAddOp(v, OP_Dup, i+extra+nCol-idx, 1);
      }
    }
    jumpInst1 = sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
    if( pParse->db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);

    /* Find out what action to take in case there is an indexing conflict */
    onError = pIdx->onError;
    if( onError==OE_None ) continue;  /* pIdx is not a UNIQUE index */
    if( overrideError!=OE_Default ){
      onError = overrideError;
    }else if( pParse->db->onError!=OE_Default ){
      onError = pParse->db->onError;
    }else if( onError==OE_Default ){
      onError = OE_Abort;
    }
    if( seenReplace ){
      if( onError==OE_Ignore ) onError = OE_Replace;
      else if( onError==OE_Fail ) onError = OE_Abort;
    }
    

    /* Check to see if the new index entry will be unique */
    sqliteVdbeAddOp(v, OP_Dup, extra+nCol+1+hasTwoRecnos, 1);
    jumpInst2 = sqliteVdbeAddOp(v, OP_IsUnique, base+iCur+1, 0);

    /* Generate code that executes if the new index entry is not unique */
    switch( onError ){
      case OE_Rollback:
      case OE_Abort:
      case OE_Fail: {
        int j, n1, n2;
        char zErrMsg[200];
        strcpy(zErrMsg, pIdx->nColumn>1 ? "columns " : "column ");
        n1 = strlen(zErrMsg);
        for(j=0; j<pIdx->nColumn && n1<sizeof(zErrMsg)-30; j++){
          char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
          n2 = strlen(zCol);
          if( j>0 ){
            strcpy(&zErrMsg[n1], ", ");
            n1 += 2;
          }
          if( n1+n2>sizeof(zErrMsg)-30 ){
            strcpy(&zErrMsg[n1], "...");
            n1 += 3;
            break;
          }else{
            strcpy(&zErrMsg[n1], zCol);
            n1 += n2;
          }
        }
        strcpy(&zErrMsg[n1], 
            pIdx->nColumn>1 ? " are not unique" : " is not unique");
        sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
        break;
      }
      case OE_Ignore: {
        assert( seenReplace==0 );
        sqliteVdbeAddOp(v, OP_Pop, nCol+extra+3+hasTwoRecnos, 0);
        sqliteVdbeAddOp(v, OP_Goto, 0, ignoreDest);
        break;
      }
      case OE_Replace: {
        sqliteGenerateRowDelete(pParse->db, v, pTab, base, 0);
        if( isUpdate ){
          sqliteVdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1);
          sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
        }
        seenReplace = 1;
        break;
      }
      default: assert(0);
    }
    contAddr = sqliteVdbeCurrentAddr(v);
#if NULL_DISTINCT_FOR_UNIQUE
    sqliteVdbeChangeP2(v, jumpInst1, contAddr);
#endif
    sqliteVdbeChangeP2(v, jumpInst2, contAddr);
  }
}
示例#7
0
/*
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is true but execution
** continues straight thru if the expression is false.
**
** If the expression evaluates to NULL (neither true nor false), then
** take the jump if the jumpIfNull flag is true.
*/
void sqliteExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
  Vdbe *v = pParse->pVdbe;
  int op = 0;
  if( v==0 || pExpr==0 ) return;
  switch( pExpr->op ){
    case TK_LT:       op = OP_Lt;       break;
    case TK_LE:       op = OP_Le;       break;
    case TK_GT:       op = OP_Gt;       break;
    case TK_GE:       op = OP_Ge;       break;
    case TK_NE:       op = OP_Ne;       break;
    case TK_EQ:       op = OP_Eq;       break;
    case TK_ISNULL:   op = OP_IsNull;   break;
    case TK_NOTNULL:  op = OP_NotNull;  break;
    default:  break;
  }
  switch( pExpr->op ){
    case TK_AND: {
      int d2 = sqliteVdbeMakeLabel(v);
      sqliteExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull);
      sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
      sqliteVdbeResolveLabel(v, d2);
      break;
    }
    case TK_OR: {
      sqliteExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
      sqliteExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
      break;
    }
    case TK_NOT: {
      sqliteExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
      break;
    }
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:
    case TK_NE:
    case TK_EQ: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteExprCode(pParse, pExpr->pRight);
      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
        op += 6;  /* Convert numeric opcodes to text opcodes */
      }
      sqliteVdbeAddOp(v, op, jumpIfNull, dest);
      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteVdbeAddOp(v, op, 1, dest);
      break;
    }
    case TK_IN: {
      int addr;
      sqliteExprCode(pParse, pExpr->pLeft);
      addr = sqliteVdbeCurrentAddr(v);
      sqliteVdbeAddOp(v, OP_NotNull, -1, addr+3);
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      sqliteVdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
      if( pExpr->pSelect ){
        sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, dest);
      }else{
        sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, dest);
      }
      break;
    }
    case TK_BETWEEN: {
      int addr;
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
      sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
      addr = sqliteVdbeAddOp(v, OP_Lt, !jumpIfNull, 0);
      sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
      sqliteVdbeAddOp(v, OP_Le, jumpIfNull, dest);
      sqliteVdbeAddOp(v, OP_Integer, 0, 0);
      sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      break;
    }
    default: {
      sqliteExprCode(pParse, pExpr);
      sqliteVdbeAddOp(v, OP_If, jumpIfNull, dest);
      break;
    }
  }
}
示例#8
0
/*
** Generate code into the current Vdbe to evaluate the given
** expression and leave the result on the top of stack.
*/
void sqliteExprCode(Parse *pParse, Expr *pExpr){
  Vdbe *v = pParse->pVdbe;
  int op;
  if( v==0 || pExpr==0 ) return;
  switch( pExpr->op ){
    case TK_PLUS:     op = OP_Add;      break;
    case TK_MINUS:    op = OP_Subtract; break;
    case TK_STAR:     op = OP_Multiply; break;
    case TK_SLASH:    op = OP_Divide;   break;
    case TK_AND:      op = OP_And;      break;
    case TK_OR:       op = OP_Or;       break;
    case TK_LT:       op = OP_Lt;       break;
    case TK_LE:       op = OP_Le;       break;
    case TK_GT:       op = OP_Gt;       break;
    case TK_GE:       op = OP_Ge;       break;
    case TK_NE:       op = OP_Ne;       break;
    case TK_EQ:       op = OP_Eq;       break;
    case TK_ISNULL:   op = OP_IsNull;   break;
    case TK_NOTNULL:  op = OP_NotNull;  break;
    case TK_NOT:      op = OP_Not;      break;
    case TK_UMINUS:   op = OP_Negative; break;
    case TK_BITAND:   op = OP_BitAnd;   break;
    case TK_BITOR:    op = OP_BitOr;    break;
    case TK_BITNOT:   op = OP_BitNot;   break;
    case TK_LSHIFT:   op = OP_ShiftLeft;  break;
    case TK_RSHIFT:   op = OP_ShiftRight; break;
    case TK_REM:      op = OP_Remainder;  break;
    default: break;
  }
  switch( pExpr->op ){
    case TK_COLUMN: {
      if( pParse->useAgg ){
        sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
      }else if( pExpr->iColumn>=0 ){
        sqliteVdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
      }else{
        sqliteVdbeAddOp(v, OP_Recno, pExpr->iTable, 0);
      }
      break;
    }
    case TK_STRING:
    case TK_FLOAT:
    case TK_INTEGER: {
      if( pExpr->op==TK_INTEGER && sqliteFitsIn32Bits(pExpr->token.z) ){
        sqliteVdbeAddOp(v, OP_Integer, atoi(pExpr->token.z), 0);
      }else{
        sqliteVdbeAddOp(v, OP_String, 0, 0);
      }
      assert( pExpr->token.z );
      sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
      sqliteVdbeDequoteP3(v, -1);
      break;
    }
    case TK_NULL: {
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      break;
    }
    case TK_VARIABLE: {
      sqliteVdbeAddOp(v, OP_Variable, pExpr->iTable, 0);
      break;
    }
    case TK_LT:
    case TK_LE:
    case TK_GT:
    case TK_GE:
    case TK_NE:
    case TK_EQ: {
      if( pParse->db->file_format>=4 && sqliteExprType(pExpr)==SQLITE_SO_TEXT ){
        op += 6;  /* Convert numeric opcodes to text opcodes */
      }
      /* Fall through into the next case */
    }
    case TK_AND:
    case TK_OR:
    case TK_PLUS:
    case TK_STAR:
    case TK_MINUS:
    case TK_REM:
    case TK_BITAND:
    case TK_BITOR:
    case TK_SLASH: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteExprCode(pParse, pExpr->pRight);
      sqliteVdbeAddOp(v, op, 0, 0);
      break;
    }
    case TK_LSHIFT:
    case TK_RSHIFT: {
      sqliteExprCode(pParse, pExpr->pRight);
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteVdbeAddOp(v, op, 0, 0);
      break;
    }
    case TK_CONCAT: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteExprCode(pParse, pExpr->pRight);
      sqliteVdbeAddOp(v, OP_Concat, 2, 0);
      break;
    }
    case TK_UMINUS: {
      assert( pExpr->pLeft );
      if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
        Token *p = &pExpr->pLeft->token;
        char *z = sqliteMalloc( p->n + 2 );
        sprintf(z, "-%.*s", p->n, p->z);
        if( pExpr->pLeft->op==TK_INTEGER && sqliteFitsIn32Bits(z) ){
          sqliteVdbeAddOp(v, OP_Integer, atoi(z), 0);
        }else{
          sqliteVdbeAddOp(v, OP_String, 0, 0);
        }
        sqliteVdbeChangeP3(v, -1, z, p->n+1);
        sqliteFree(z);
        break;
      }
      /* Fall through into TK_NOT */
    }
    case TK_BITNOT:
    case TK_NOT: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteVdbeAddOp(v, op, 0, 0);
      break;
    }
    case TK_ISNULL:
    case TK_NOTNULL: {
      int dest;
      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
      sqliteExprCode(pParse, pExpr->pLeft);
      dest = sqliteVdbeCurrentAddr(v) + 2;
      sqliteVdbeAddOp(v, op, 1, dest);
      sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
      break;
    }
    case TK_AGG_FUNCTION: {
      sqliteVdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
      break;
    }
    case TK_GLOB:
    case TK_LIKE:
    case TK_FUNCTION: {
      ExprList *pList = pExpr->pList;
      int nExpr = pList ? pList->nExpr : 0;
      FuncDef *pDef;
      int nId;
      const char *zId;
      getFunctionName(pExpr, &zId, &nId);
      pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0);
      assert( pDef!=0 );
      nExpr = sqliteExprCodeExprList(pParse, pList, pDef->includeTypes);
      sqliteVdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
      break;
    }
    case TK_SELECT: {
      sqliteVdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
      break;
    }
    case TK_IN: {
      int addr;
      sqliteVdbeAddOp(v, OP_Integer, 1, 0);
      sqliteExprCode(pParse, pExpr->pLeft);
      addr = sqliteVdbeCurrentAddr(v);
      sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4);
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      sqliteVdbeAddOp(v, OP_String, 0, 0);
      sqliteVdbeAddOp(v, OP_Goto, 0, addr+6);
      if( pExpr->pSelect ){
        sqliteVdbeAddOp(v, OP_Found, pExpr->iTable, addr+6);
      }else{
        sqliteVdbeAddOp(v, OP_SetFound, pExpr->iTable, addr+6);
      }
      sqliteVdbeAddOp(v, OP_AddImm, -1, 0);
      break;
    }
    case TK_BETWEEN: {
      sqliteExprCode(pParse, pExpr->pLeft);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
      sqliteExprCode(pParse, pExpr->pList->a[0].pExpr);
      sqliteVdbeAddOp(v, OP_Ge, 0, 0);
      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
      sqliteExprCode(pParse, pExpr->pList->a[1].pExpr);
      sqliteVdbeAddOp(v, OP_Le, 0, 0);
      sqliteVdbeAddOp(v, OP_And, 0, 0);
      break;
    }
    case TK_UPLUS:
    case TK_AS: {
      sqliteExprCode(pParse, pExpr->pLeft);
      break;
    }
    case TK_CASE: {
      int expr_end_label;
      int jumpInst;
      int addr;
      int nExpr;
      int i;

      assert(pExpr->pList);
      assert((pExpr->pList->nExpr % 2) == 0);
      assert(pExpr->pList->nExpr > 0);
      nExpr = pExpr->pList->nExpr;
      expr_end_label = sqliteVdbeMakeLabel(v);
      if( pExpr->pLeft ){
        sqliteExprCode(pParse, pExpr->pLeft);
      }
      for(i=0; i<nExpr; i=i+2){
        sqliteExprCode(pParse, pExpr->pList->a[i].pExpr);
        if( pExpr->pLeft ){
          sqliteVdbeAddOp(v, OP_Dup, 1, 1);
          jumpInst = sqliteVdbeAddOp(v, OP_Ne, 1, 0);
          sqliteVdbeAddOp(v, OP_Pop, 1, 0);
        }else{
          jumpInst = sqliteVdbeAddOp(v, OP_IfNot, 1, 0);
        }
        sqliteExprCode(pParse, pExpr->pList->a[i+1].pExpr);
        sqliteVdbeAddOp(v, OP_Goto, 0, expr_end_label);
        addr = sqliteVdbeCurrentAddr(v);
        sqliteVdbeChangeP2(v, jumpInst, addr);
      }
      if( pExpr->pLeft ){
        sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      }
      if( pExpr->pRight ){
        sqliteExprCode(pParse, pExpr->pRight);
      }else{
        sqliteVdbeAddOp(v, OP_String, 0, 0);
      }
      sqliteVdbeResolveLabel(v, expr_end_label);
      break;
    }
    case TK_RAISE: {
      if( !pParse->trigStack ){
        sqliteErrorMsg(pParse,
                       "RAISE() may only be used within a trigger-program");
        pParse->nErr++;
	return;
      }
      if( pExpr->iColumn == OE_Rollback ||
	  pExpr->iColumn == OE_Abort ||
	  pExpr->iColumn == OE_Fail ){
	  sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
                           pExpr->token.z, pExpr->token.n);
	  sqliteVdbeDequoteP3(v, -1);
      } else {
	  assert( pExpr->iColumn == OE_Ignore );
	  sqliteVdbeOp3(v, OP_Goto, 0, pParse->trigStack->ignoreJump,
                           "(IGNORE jump)", 0);
      }
    }
    break;
  }
}