Exemplo n.º 1
0
void sqliteDropProc(Parse *pParse, Token *pName){
  Object *pObj;
  char *zName;
  Vdbe *v = sqliteGetVdbe(pParse);
  sqlite *db = pParse->db;

  zName = sqliteStrNDup(pName->z, pName->n);
  sqliteDequote(zName);
  pObj = sqliteHashFind(&(db->aDb[0].objectHash), zName, pName->n+1);
  if( !pParse->explain && !pObj ){
    sqliteErrorMsg(pParse, "no such object: %T", pName);
    goto dropobject_cleanup;
  }

  /* Generate code to destroy the database record of the trigger.
  */
  if( v ){
    int base;
    static VdbeOpList dropObject[] = {
      { OP_Rewind,     0, ADDR(9),  0},
      { OP_String,     0, 0,        0}, /* 1 */
      { OP_Column,     0, 1,        0},
      { OP_Ne,         0, ADDR(8),  0},
      { OP_String,     0, 0,        "procedure"},
      { OP_Column,     0, 0,        0},
      { OP_Ne,         0, ADDR(8),  0},
      { OP_Delete,     0, 0,        0},
      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    };

    sqliteBeginWriteOperation(pParse, 0, 0);
    sqliteOpenMasterTable(v, 0);
    base = sqliteVdbeAddOpList(v,  ArraySize(dropObject), dropObject);
    sqliteVdbeChangeP3(v, base+1, zName, 0);
    if( pObj && pObj->iDb==0 ){
      sqliteChangeCookie(db, v);
    }
    sqliteVdbeAddOp(v, OP_Close, 0, 0);
    sqliteEndWriteOperation(pParse);
  }

  /*
   * If this is not an "explain", then delete the trigger structure.
   */
  if( !pParse->explain ){
    sqliteHashInsert(&(db->aDb[pObj->iDb].objectHash), zName, pName->n+1, 0);
    sqliteDeleteObject(pObj);
  }

dropobject_cleanup:
  sqliteFree(zName);
}
Exemplo n.º 2
0
/*
** Process a DELETE FROM statement.
*/
void sqliteDeleteFrom(
  Parse *pParse,         /* The parser context */
  SrcList *pTabList,     /* The table from which we should delete things */
  Expr *pWhere           /* The WHERE clause.  May be null */
){
  Vdbe *v;               /* The virtual database engine */
  Table *pTab;           /* The table from which records will be deleted */
  const char *zDb;       /* Name of database holding pTab */
  int end, addr;         /* A couple addresses of generated code */
  int i;                 /* Loop counter */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int iCur;              /* VDBE Cursor number for pTab */
  sqlite *db;            /* Main database structure */
  int isView;            /* True if attempting to delete from a view */
  AuthContext sContext;  /* Authorization context */

  int row_triggers_exist = 0;  /* True if any triggers exist */
  int before_triggers;         /* True if there are BEFORE triggers */
  int after_triggers;          /* True if there are AFTER triggers */
  int oldIdx = -1;             /* Cursor for the OLD table of AFTER triggers */

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

  /* Locate the table which we want to delete.  This table has to be
  ** put in an SrcList structure because some of the subroutines we
  ** will be calling are designed to work with multiple tables and expect
  ** an SrcList* parameter instead of just a Table* parameter.
  */
  pTab = sqliteSrcListLookup(pParse, pTabList);
  if( pTab==0 )  goto delete_from_cleanup;
  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                         TK_DELETE, TK_BEFORE, TK_ROW, 0);
  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                         TK_DELETE, TK_AFTER, TK_ROW, 0);
  row_triggers_exist = before_triggers || after_triggers;
  isView = pTab->pSelect!=0;
  if( sqliteIsReadOnly(pParse, pTab, before_triggers) ){
    goto delete_from_cleanup;
  }
  assert( pTab->iDb<db->nDb );
  zDb = db->aDb[pTab->iDb].zName;
  if( sqliteAuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){
    goto delete_from_cleanup;
  }

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

  /* Allocate a cursor used to store the old.* data for a trigger.
  */
  if( row_triggers_exist ){ 
    oldIdx = pParse->nTab++;
  }

  /* Resolve the column names in all the expressions.
  */
  assert( pTabList->nSrc==1 );
  iCur = pTabList->a[0].iCursor = pParse->nTab++;
  if( pWhere ){
    if( sqliteExprResolveIds(pParse, pTabList, 0, pWhere) ){
      goto delete_from_cleanup;
    }
    if( sqliteExprCheck(pParse, pWhere, 0, 0) ){
      goto delete_from_cleanup;
    }
  }

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

  /* Begin generating code.
  */
  v = sqliteGetVdbe(pParse);
  if( v==0 ){
    goto delete_from_cleanup;
  }
  sqliteBeginWriteOperation(pParse, row_triggers_exist, pTab->iDb);

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

  /* Initialize the counter of the number of rows deleted, if
  ** we are counting rows.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  /* Special case: A DELETE without a WHERE clause deletes everything.
  ** It is easier just to erase the whole table.  Note, however, that
  ** this means that the row change count will be incorrect.
  */
  if( pWhere==0 && !row_triggers_exist ){
    if( db->flags & SQLITE_CountRows ){
      /* If counting rows deleted, just count the total number of
      ** entries in the table. */
      int endOfLoop = sqliteVdbeMakeLabel(v);
      int addr;
      if( !isView ){
        sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
        sqliteVdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum);
      }
      sqliteVdbeAddOp(v, OP_Rewind, iCur, sqliteVdbeCurrentAddr(v)+2);
      addr = sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
      sqliteVdbeAddOp(v, OP_Next, iCur, addr);
      sqliteVdbeResolveLabel(v, endOfLoop);
      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
    }
    if( !isView ){
      sqliteVdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb);
      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
        sqliteVdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb);
      }
    }
  }

  /* The usual case: There is a WHERE clause so we have to scan through
  ** the table and pick which records to delete.
  */
  else{
    /* Begin the database scan
    */
    pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 1, 0);
    if( pWInfo==0 ) goto delete_from_cleanup;

    /* Remember the key of every item to be deleted.
    */
    sqliteVdbeAddOp(v, OP_ListWrite, 0, 0);
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
    }

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

    /* Open the pseudo-table used to store OLD if there are triggers.
    */
    if( row_triggers_exist ){
      sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
    }

    /* Delete every item whose key was written to the list during the
    ** database scan.  We have to delete items after the scan is complete
    ** because deleting an item can change the scan order.
    */
    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    end = sqliteVdbeMakeLabel(v);

    /* This is the beginning of the delete loop when there are
    ** row triggers.
    */
    if( row_triggers_exist ){
      addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
      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);

      sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
      sqliteVdbeAddOp(v, OP_RowData, iCur, 0);
      sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
      if( !isView ){
        sqliteVdbeAddOp(v, OP_Close, iCur, 0);
      }

      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
	  addr);
    }

    if( !isView ){
      /* Open cursors for the table we are deleting from and all its
      ** indices.  If there are row triggers, this happens inside the
      ** OP_ListRead loop because the cursor have to all be closed
      ** before the trigger fires.  If there are no row triggers, the
      ** cursors are opened only once on the outside the loop.
      */
      pParse->nTab = iCur + 1;
      sqliteOpenTableAndIndices(pParse, pTab, iCur);

      /* This is the beginning of the delete loop when there are no
      ** row triggers */
      if( !row_triggers_exist ){ 
        addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
      }

      /* Delete the row */
      sqliteGenerateRowDelete(db, v, pTab, iCur, pParse->trigStack==0);
    }

    /* If there are row triggers, close all cursors then invoke
    ** the AFTER triggers
    */
    if( row_triggers_exist ){
      if( !isView ){
        for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
          sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
        }
        sqliteVdbeAddOp(v, OP_Close, iCur, 0);
      }
      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, 
          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
	  addr);
    }

    /* End of the delete loop */
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_ListReset, 0, 0);

    /* Close the cursors after the loop if there are no row triggers */
    if( !row_triggers_exist ){
      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
        sqliteVdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum);
      }
      sqliteVdbeAddOp(v, OP_Close, iCur, 0);
      pParse->nTab = iCur;
    }
  }
  sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
  sqliteEndWriteOperation(pParse);

  /*
  ** Return the number of rows that were deleted.
  */
  if( db->flags & SQLITE_CountRows ){
    sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
    sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
    sqliteVdbeAddOp(v, OP_Callback, 1, 0);
  }

delete_from_cleanup:
  sqliteAuthContextPop(&sContext);
  sqliteSrcListDelete(pTabList);
  sqliteExprDelete(pWhere);
  return;
}
Exemplo n.º 3
0
/*
** 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);
}
Exemplo n.º 4
0
/*
** Add an opcode that includes the p3 value.
*/
int sqliteVdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3, int p3type){
  int addr = sqliteVdbeAddOp(p, op, p1, p2);
  sqliteVdbeChangeP3(p, addr, zP3, p3type);
  return addr;
}
Exemplo n.º 5
0
/*
** This routine is called after the body of the procedure has been parsed
** in order to complete the process of building the procedure object.
*/
void sqliteFinishProc(
  Parse *pParse,          /* Parser context */
  Block *pBlock,		  /* The procedure body */
  Token *pAll             /* Token that describes the complete CREATE text */
){
  Object *no = 0;           /* The object whose construction is finishing up */
  sqlite *db = pParse->db;  /* The database */
  Vdbe *v = sqliteGetVdbe(pParse);

  if( pParse->nErr || pParse->pNewObject==0 ) goto objectfinish_cleanup;
  no = pParse->pNewObject;
  pParse->pNewObject = 0;

  sqliteCompileBlock(pParse, pBlock);
  sqliteVdbeAddOp(v, OP_Halt, 0, 0);

  /* save compiled body code, reset vdbe */
  if( !pParse->explain ){
    no->nOp = v->nOp;
    v->nOp = 0;
    no->aOp = v->aOp;
    v->aOp = 0;
    v->nOpAlloc = 0;
  }
  DbClearProperty(db, 0, DB_Locked);
  DbClearProperty(db, 1, DB_Locked);

  /* if we are not initializing build the sqlite_master entry */
  if( !db->init.busy ){
    static VdbeOpList insertObj[] = {
      { OP_NewRecno,   0, 0,  0           },
      { OP_String,     0, 0,  "procedure" },
      { OP_String,     0, 0,  0           },  /* 2: object name */
      { OP_String,     0, 0,  0           },  
      { OP_Integer,    0, 0,  0           },
      { OP_String,     0, 0,  0           },  /* 5: SQL */
      { OP_MakeRecord, 5, 0,  0           },
      { OP_PutIntKey,  0, 0,  0           },
    };
    int addr;

    /* Make an entry in the sqlite_master table */
    if( v==0 ) goto objectfinish_cleanup;
    sqliteBeginWriteOperation(pParse, 0, 0);
    sqliteOpenMasterTable(v, 0);
    addr = sqliteVdbeAddOpList(v, ArraySize(insertObj), insertObj);
    sqliteVdbeChangeP3(v, addr+2, no->name, 0); 
    sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
    if( no->iDb==0 ){
      sqliteChangeCookie(db, v);
    }
    sqliteVdbeAddOp(v, OP_Close, 0, 0);
    sqliteEndWriteOperation(pParse);
  }

  if( !pParse->explain ){
    sqliteHashInsert(&db->aDb[no->iDb].objectHash, 
                     no->name, strlen(no->name)+1, no);
    no = 0;
  }

objectfinish_cleanup:
  sqliteDeleteObject(no);
  sqliteDeleteObject(pParse->pNewObject);
  pParse->pNewObject = 0;
}
Exemplo n.º 6
0
/*
** Drop a trigger given a pointer to that trigger.  If nested is false,
** then also generate code to remove the trigger from the SQLITE_MASTER
** table.
*/
void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
  Table   *pTable;
  Vdbe *v;
  sqlite *db = pParse->db;

  assert( pTrigger->iDb<db->nDb );
  if( pTrigger->iDb>=2 ){
    sqliteErrorMsg(pParse, "triggers may not be removed from "
       "auxiliary database %s", db->aDb[pTrigger->iDb].zName);
    return;
  }
  pTable = sqliteFindTable(db, pTrigger->table,db->aDb[pTrigger->iTabDb].zName);
  assert(pTable);
  assert( pTable->iDb==pTrigger->iDb || pTrigger->iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
  {
    int code = SQLITE_DROP_TRIGGER;
    const char *zDb = db->aDb[pTrigger->iDb].zName;
    const char *zTab = SCHEMA_TABLE(pTrigger->iDb);
    if( pTrigger->iDb ) code = SQLITE_DROP_TEMP_TRIGGER;
    if( sqliteAuthCheck(pParse, code, pTrigger->name, pTable->zName, zDb) ||
      sqliteAuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
      return;
    }
  }
#endif

  /* Generate code to destroy the database record of the trigger.
  */
  if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
    int base;
    static VdbeOpList dropTrigger[] = {
      { OP_Rewind,     0, ADDR(9),  0},
      { OP_String,     0, 0,        0}, /* 1 */
      { OP_Column,     0, 1,        0},
      { OP_Ne,         0, ADDR(8),  0},
      { OP_String,     0, 0,        "trigger"},
      { OP_Column,     0, 0,        0},
      { OP_Ne,         0, ADDR(8),  0},
      { OP_Delete,     0, 0,        0},
      { OP_Next,       0, ADDR(1),  0}, /* 8 */
    };

    sqliteBeginWriteOperation(pParse, 0, 0);
    sqliteOpenMasterTable(v, pTrigger->iDb);
    base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
    sqliteVdbeChangeP3(v, base+1, pTrigger->name, 0);
    if( pTrigger->iDb==0 ){
      sqliteChangeCookie(db, v);
    }
    sqliteVdbeAddOp(v, OP_Close, 0, 0);
    sqliteEndWriteOperation(pParse);
  }

  /*
   * If this is not an "explain", then delete the trigger structure.
   */
  if( !pParse->explain ){
    const char *zName = pTrigger->name;
    int nName = strlen(zName);
    if( pTable->pTrigger == pTrigger ){
      pTable->pTrigger = pTrigger->pNext;
    }else{
      Trigger *cc = pTable->pTrigger;
      while( cc ){ 
        if( cc->pNext == pTrigger ){
          cc->pNext = cc->pNext->pNext;
          break;
        }
        cc = cc->pNext;
      }
      assert(cc);
    }
    sqliteHashInsert(&(db->aDb[pTrigger->iDb].trigHash), zName, nName+1, 0);
    sqliteDeleteTrigger(pTrigger);
  }
}
Exemplo n.º 7
0
/*
** This routine is called after all of the trigger actions have been parsed
** in order to complete the process of building the trigger.
*/
void sqliteFinishTrigger(
  Parse *pParse,          /* Parser context */
  TriggerStep *pStepList, /* The triggered program */
  Token *pAll             /* Token that describes the complete CREATE TRIGGER */
){
  Trigger *nt = 0;          /* The trigger whose construction is finishing up */
  sqlite *db = pParse->db;  /* The database */
  DbFixer sFix;

  if( pParse->nErr || pParse->pNewTrigger==0 ) goto triggerfinish_cleanup;
  nt = pParse->pNewTrigger;
  pParse->pNewTrigger = 0;
  nt->step_list = pStepList;
  while( pStepList ){
    pStepList->pTrig = nt;
    pStepList = pStepList->pNext;
  }
  if( sqliteFixInit(&sFix, pParse, nt->iDb, "trigger", &nt->nameToken) 
          && sqliteFixTriggerStep(&sFix, nt->step_list) ){
    goto triggerfinish_cleanup;
  }

  /* if we are not initializing, and this trigger is not on a TEMP table, 
  ** build the sqlite_master entry
  */
  if( !db->init.busy ){
    static VdbeOpList insertTrig[] = {
      { OP_NewRecno,   0, 0,  0          },
      { OP_String,     0, 0,  "trigger"  },
      { OP_String,     0, 0,  0          },  /* 2: trigger name */
      { OP_String,     0, 0,  0          },  /* 3: table name */
      { OP_Integer,    0, 0,  0          },
      { OP_String,     0, 0,  0          },  /* 5: SQL */
      { OP_MakeRecord, 5, 0,  0          },
      { OP_PutIntKey,  0, 0,  0          },
    };
    int addr;
    Vdbe *v;

    /* Make an entry in the sqlite_master table */
    v = sqliteGetVdbe(pParse);
    if( v==0 ) goto triggerfinish_cleanup;
    sqliteBeginWriteOperation(pParse, 0, 0);
    sqliteOpenMasterTable(v, nt->iDb);
    addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
    sqliteVdbeChangeP3(v, addr+2, nt->name, 0); 
    sqliteVdbeChangeP3(v, addr+3, nt->table, 0); 
    sqliteVdbeChangeP3(v, addr+5, pAll->z, pAll->n);
    if( nt->iDb==0 ){
      sqliteChangeCookie(db, v);
    }
    sqliteVdbeAddOp(v, OP_Close, 0, 0);
    sqliteEndWriteOperation(pParse);
  }

  if( !pParse->explain ){
    Table *pTab;
    sqliteHashInsert(&db->aDb[nt->iDb].trigHash, 
                     nt->name, strlen(nt->name)+1, nt);
    pTab = sqliteLocateTable(pParse, nt->table, db->aDb[nt->iTabDb].zName);
    assert( pTab!=0 );
    nt->pNext = pTab->pTrigger;
    pTab->pTrigger = nt;
    nt = 0;
  }

triggerfinish_cleanup:
  sqliteDeleteTrigger(nt);
  sqliteDeleteTrigger(pParse->pNewTrigger);
  pParse->pNewTrigger = 0;
  sqliteDeleteTriggerStep(pStepList);
}
Exemplo n.º 8
0
/*
** The COPY command is for compatibility with PostgreSQL and specificially
** for the ability to read the output of pg_dump.  The format is as
** follows:
**
**    COPY table FROM file [USING DELIMITERS string]
**
** "table" is an existing table name.  We will read lines of code from
** file to fill this table with data.  File might be "stdin".  The optional
** delimiter string identifies the field separators.  The default is a tab.
*/
void sqliteCopy(
  Parse *pParse,       /* The parser context */
  SrcList *pTableName, /* The name of the table into which we will insert */
  Token *pFilename,    /* The file from which to obtain information */
  Token *pDelimiter,   /* Use this as the field delimiter */
  int onError          /* What to do if a constraint fails */
){
  Table *pTab;
  int i;
  Vdbe *v;
  int addr, end;
  char *zFile = 0;
  const char *zDb;
  sqlite *db = pParse->db;


  if( sqlite_malloc_failed  ) goto copy_cleanup;
  assert( pTableName->nSrc==1 );
  pTab = sqliteSrcListLookup(pParse, pTableName);
  if( pTab==0 || sqliteIsReadOnly(pParse, pTab, 0) ) goto copy_cleanup;
  zFile = sqliteStrNDup(pFilename->z, pFilename->n);
  sqliteDequote(zFile);
  assert( pTab->iDb<db->nDb );
  zDb = db->aDb[pTab->iDb].zName;
  if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb)
      || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){
    goto copy_cleanup;
  }
  v = sqliteGetVdbe(pParse);
  if( v ){
    sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
    addr = sqliteVdbeOp3(v, OP_FileOpen, 0, 0, pFilename->z, pFilename->n);
    sqliteVdbeDequoteP3(v, addr);
    sqliteOpenTableAndIndices(pParse, pTab, 0);
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_Integer, 0, 0);  /* Initialize the row count */
    }
    end = sqliteVdbeMakeLabel(v);
    addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
    if( pDelimiter ){
      sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
      sqliteVdbeDequoteP3(v, addr);
    }else{
      sqliteVdbeChangeP3(v, addr, "\t", 1);
    }
    if( pTab->iPKey>=0 ){
      sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
    }else{
      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
    }
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        /* The integer primary key column is filled with NULL since its
        ** value is always pulled from the record number */
        sqliteVdbeAddOp(v, OP_String, 0, 0);
      }else{
        sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
      }
    }
    sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, pTab->iPKey>=0, 
                                   0, onError, addr);
    sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1);
    if( (db->flags & SQLITE_CountRows)!=0 ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);  /* Increment row count */
    }
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
    sqliteEndWriteOperation(pParse);
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
      sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
      sqliteVdbeAddOp(v, OP_Callback, 1, 0);
    }
  }
  
copy_cleanup:
  sqliteSrcListDelete(pTableName);
  sqliteFree(zFile);
  return;
}
Exemplo n.º 9
0
/*
** 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);
  }
}
Exemplo n.º 10
0
/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an (opaque) structure that contains
** information needed to terminate the loop.  Later, the calling routine
** should invoke sqliteWhereEnd() with the return value of this function
** in order to complete the WHERE clause processing.
**
** If an error occurs, this routine returns NULL.
**
** The basic idea is to do a nested loop, one loop for each table in
** the FROM clause of a select.  (INSERT and UPDATE statements are the
** same as a SELECT with only a single table in the FROM clause.)  For
** example, if the SQL is this:
**
**       SELECT * FROM t1, t2, t3 WHERE ...;
**
** Then the code generated is conceptually like the following:
**
**      foreach row1 in t1 do       \    Code generated
**        foreach row2 in t2 do      |-- by sqliteWhereBegin()
**          foreach row3 in t3 do   /
**            ...
**          end                     \    Code generated
**        end                        |-- by sqliteWhereEnd()
**      end                         /
**
** There are Btree cursors associated with each table.  t1 uses cursor
** number pTabList->a[0].iCursor.  t2 uses the cursor pTabList->a[1].iCursor.
** And so forth.  This routine generates code to open those VDBE cursors
** and sqliteWhereEnd() generates the code to close them.
**
** If the WHERE clause is empty, the foreach loops must each scan their
** entire tables.  Thus a three-way join is an O(N^3) operation.  But if
** the tables have indices and there are terms in the WHERE clause that
** refer to those indices, a complete table scan can be avoided and the
** code will run much faster.  Most of the work of this routine is checking
** to see if there are indices that can be used to speed up the loop.
**
** Terms of the WHERE clause are also used to limit which rows actually
** make it to the "..." in the middle of the loop.  After each "foreach",
** terms of the WHERE clause that use only terms in that loop and outer
** loops are evaluated and if false a jump is made around all subsequent
** inner loops (or around the "..." if the test occurs within the inner-
** most loop)
**
** OUTER JOINS
**
** An outer join of tables t1 and t2 is conceptally coded as follows:
**
**    foreach row1 in t1 do
**      flag = 0
**      foreach row2 in t2 do
**        start:
**          ...
**          flag = 1
**      end
**      if flag==0 then
**        move the row2 cursor to a null row
**        goto start
**      fi
**    end
**
** ORDER BY CLAUSE PROCESSING
**
** *ppOrderBy is a pointer to the ORDER BY clause of a SELECT statement,
** if there is one.  If there is no ORDER BY clause or if this routine
** is called from an UPDATE or DELETE statement, then ppOrderBy is NULL.
**
** If an index can be used so that the natural output order of the table
** scan is correct for the ORDER BY clause, then that index is used and
** *ppOrderBy is set to NULL.  This is an optimization that prevents an
** unnecessary sort of the result set if an index appropriate for the
** ORDER BY clause already exists.
**
** If the where clause loops cannot be arranged to provide the correct
** output order, then the *ppOrderBy is unchanged.
*/
WhereInfo *sqliteWhereBegin(
    Parse *pParse,       /* The parser context */
    SrcList *pTabList,   /* A list of all tables to be scanned */
    Expr *pWhere,        /* The WHERE clause */
    int pushKey,         /* If TRUE, leave the table key on the stack */
    ExprList **ppOrderBy /* An ORDER BY clause, or NULL */
) {
    int i;                     /* Loop counter */
    WhereInfo *pWInfo;         /* Will become the return value of this function */
    Vdbe *v = pParse->pVdbe;   /* The virtual database engine */
    int brk, cont = 0;         /* Addresses used during code generation */
    int nExpr;           /* Number of subexpressions in the WHERE clause */
    int loopMask;        /* One bit set for each outer loop */
    int haveKey;         /* True if KEY is on the stack */
    ExprMaskSet maskSet; /* The expression mask set */
    int iDirectEq[32];   /* Term of the form ROWID==X for the N-th table */
    int iDirectLt[32];   /* Term of the form ROWID<X or ROWID<=X */
    int iDirectGt[32];   /* Term of the form ROWID>X or ROWID>=X */
    ExprInfo aExpr[101]; /* The WHERE clause is divided into these expressions */

    /* pushKey is only allowed if there is a single table (as in an INSERT or
    ** UPDATE statement)
    */
    assert( pushKey==0 || pTabList->nSrc==1 );

    /* Split the WHERE clause into separate subexpressions where each
    ** subexpression is separated by an AND operator.  If the aExpr[]
    ** array fills up, the last entry might point to an expression which
    ** contains additional unfactored AND operators.
    */
    initMaskSet(&maskSet);
    memset(aExpr, 0, sizeof(aExpr));
    nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
    if( nExpr==ARRAYSIZE(aExpr) ) {
        char zBuf[50];
        sprintf(zBuf, "%d", (int)ARRAYSIZE(aExpr)-1);
        sqliteSetString(&pParse->zErrMsg, "WHERE clause too complex - no more "
                        "than ", zBuf, " terms allowed", (char*)0);
        pParse->nErr++;
        return 0;
    }

    /* Allocate and initialize the WhereInfo structure that will become the
    ** return value.
    */
    pWInfo = sqliteMalloc( sizeof(WhereInfo) + pTabList->nSrc*sizeof(WhereLevel));
    if( sqlite_malloc_failed ) {
        sqliteFree(pWInfo);
        return 0;
    }
    pWInfo->pParse = pParse;
    pWInfo->pTabList = pTabList;
    pWInfo->peakNTab = pWInfo->savedNTab = pParse->nTab;
    pWInfo->iBreak = sqliteVdbeMakeLabel(v);

    /* Special case: a WHERE clause that is constant.  Evaluate the
    ** expression and either jump over all of the code or fall thru.
    */
    if( pWhere && (pTabList->nSrc==0 || sqliteExprIsConstant(pWhere)) ) {
        sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
        pWhere = 0;
    }

    /* Analyze all of the subexpressions.
    */
    for(i=0; i<nExpr; i++) {
        exprAnalyze(&maskSet, &aExpr[i]);

        /* If we are executing a trigger body, remove all references to
        ** new.* and old.* tables from the prerequisite masks.
        */
        if( pParse->trigStack ) {
            int x;
            if( (x = pParse->trigStack->newIdx) >= 0 ) {
                int mask = ~getMask(&maskSet, x);
                aExpr[i].prereqRight &= mask;
                aExpr[i].prereqLeft &= mask;
                aExpr[i].prereqAll &= mask;
            }
            if( (x = pParse->trigStack->oldIdx) >= 0 ) {
                int mask = ~getMask(&maskSet, x);
                aExpr[i].prereqRight &= mask;
                aExpr[i].prereqLeft &= mask;
                aExpr[i].prereqAll &= mask;
            }
        }
    }

    /* Figure out what index to use (if any) for each nested loop.
    ** Make pWInfo->a[i].pIdx point to the index to use for the i-th nested
    ** loop where i==0 is the outer loop and i==pTabList->nSrc-1 is the inner
    ** loop.
    **
    ** If terms exist that use the ROWID of any table, then set the
    ** iDirectEq[], iDirectLt[], or iDirectGt[] elements for that table
    ** to the index of the term containing the ROWID.  We always prefer
    ** to use a ROWID which can directly access a table rather than an
    ** index which requires reading an index first to get the rowid then
    ** doing a second read of the actual database table.
    **
    ** Actually, if there are more than 32 tables in the join, only the
    ** first 32 tables are candidates for indices.  This is (again) due
    ** to the limit of 32 bits in an integer bitmask.
    */
    loopMask = 0;
    for(i=0; i<pTabList->nSrc && i<ARRAYSIZE(iDirectEq); i++) {
        int j;
        int iCur = pTabList->a[i].iCursor;    /* The cursor for this table */
        int mask = getMask(&maskSet, iCur);   /* Cursor mask for this table */
        Table *pTab = pTabList->a[i].pTab;
        Index *pIdx;
        Index *pBestIdx = 0;
        int bestScore = 0;

        /* Check to see if there is an expression that uses only the
        ** ROWID field of this table.  For terms of the form ROWID==expr
        ** set iDirectEq[i] to the index of the term.  For terms of the
        ** form ROWID<expr or ROWID<=expr set iDirectLt[i] to the term index.
        ** For terms like ROWID>expr or ROWID>=expr set iDirectGt[i].
        **
        ** (Added:) Treat ROWID IN expr like ROWID=expr.
        */
        pWInfo->a[i].iCur = -1;
        iDirectEq[i] = -1;
        iDirectLt[i] = -1;
        iDirectGt[i] = -1;
        for(j=0; j<nExpr; j++) {
            if( aExpr[j].idxLeft==iCur && aExpr[j].p->pLeft->iColumn<0
                    && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ) {
                switch( aExpr[j].p->op ) {
                case TK_IN:
                case TK_EQ:
                    iDirectEq[i] = j;
                    break;
                case TK_LE:
                case TK_LT:
                    iDirectLt[i] = j;
                    break;
                case TK_GE:
                case TK_GT:
                    iDirectGt[i] = j;
                    break;
                }
            }
            if( aExpr[j].idxRight==iCur && aExpr[j].p->pRight->iColumn<0
                    && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ) {
                switch( aExpr[j].p->op ) {
                case TK_EQ:
                    iDirectEq[i] = j;
                    break;
                case TK_LE:
                case TK_LT:
                    iDirectGt[i] = j;
                    break;
                case TK_GE:
                case TK_GT:
                    iDirectLt[i] = j;
                    break;
                }
            }
        }
        if( iDirectEq[i]>=0 ) {
            loopMask |= mask;
            pWInfo->a[i].pIdx = 0;
            continue;
        }

        /* Do a search for usable indices.  Leave pBestIdx pointing to
        ** the "best" index.  pBestIdx is left set to NULL if no indices
        ** are usable.
        **
        ** The best index is determined as follows.  For each of the
        ** left-most terms that is fixed by an equality operator, add
        ** 8 to the score.  The right-most term of the index may be
        ** constrained by an inequality.  Add 1 if for an "x<..." constraint
        ** and add 2 for an "x>..." constraint.  Chose the index that
        ** gives the best score.
        **
        ** This scoring system is designed so that the score can later be
        ** used to determine how the index is used.  If the score&7 is 0
        ** then all constraints are equalities.  If score&1 is not 0 then
        ** there is an inequality used as a termination key.  (ex: "x<...")
        ** If score&2 is not 0 then there is an inequality used as the
        ** start key.  (ex: "x>...").  A score or 4 is the special case
        ** of an IN operator constraint.  (ex:  "x IN ...").
        **
        ** The IN operator (as in "<expr> IN (...)") is treated the same as
        ** an equality comparison except that it can only be used on the
        ** left-most column of an index and other terms of the WHERE clause
        ** cannot be used in conjunction with the IN operator to help satisfy
        ** other columns of the index.
        */
        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext) {
            int eqMask = 0;  /* Index columns covered by an x=... term */
            int ltMask = 0;  /* Index columns covered by an x<... term */
            int gtMask = 0;  /* Index columns covered by an x>... term */
            int inMask = 0;  /* Index columns covered by an x IN .. term */
            int nEq, m, score;

            if( pIdx->nColumn>32 ) continue;  /* Ignore indices too many columns */
            for(j=0; j<nExpr; j++) {
                if( aExpr[j].idxLeft==iCur
                        && (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ) {
                    int iColumn = aExpr[j].p->pLeft->iColumn;
                    int k;
                    for(k=0; k<pIdx->nColumn; k++) {
                        if( pIdx->aiColumn[k]==iColumn ) {
                            switch( aExpr[j].p->op ) {
                            case TK_IN: {
                                if( k==0 ) inMask |= 1;
                                break;
                            }
                            case TK_EQ: {
                                eqMask |= 1<<k;
                                break;
                            }
                            case TK_LE:
                            case TK_LT: {
                                ltMask |= 1<<k;
                                break;
                            }
                            case TK_GE:
                            case TK_GT: {
                                gtMask |= 1<<k;
                                break;
                            }
                            default: {
                                /* CANT_HAPPEN */
                                assert( 0 );
                                break;
                            }
                            }
                            break;
                        }
                    }
                }
                if( aExpr[j].idxRight==iCur
                        && (aExpr[j].prereqLeft & loopMask)==aExpr[j].prereqLeft ) {
                    int iColumn = aExpr[j].p->pRight->iColumn;
                    int k;
                    for(k=0; k<pIdx->nColumn; k++) {
                        if( pIdx->aiColumn[k]==iColumn ) {
                            switch( aExpr[j].p->op ) {
                            case TK_EQ: {
                                eqMask |= 1<<k;
                                break;
                            }
                            case TK_LE:
                            case TK_LT: {
                                gtMask |= 1<<k;
                                break;
                            }
                            case TK_GE:
                            case TK_GT: {
                                ltMask |= 1<<k;
                                break;
                            }
                            default: {
                                /* CANT_HAPPEN */
                                assert( 0 );
                                break;
                            }
                            }
                            break;
                        }
                    }
                }
            }

            /* The following loop ends with nEq set to the number of columns
            ** on the left of the index with == constraints.
            */
            for(nEq=0; nEq<pIdx->nColumn; nEq++) {
                m = (1<<(nEq+1))-1;
                if( (m & eqMask)!=m ) break;
            }
            score = nEq*8;   /* Base score is 8 times number of == constraints */
            m = 1<<nEq;
            if( m & ltMask ) score++;    /* Increase score for a < constraint */
            if( m & gtMask ) score+=2;   /* Increase score for a > constraint */
            if( score==0 && inMask ) score = 4;  /* Default score for IN constraint */
            if( score>bestScore ) {
                pBestIdx = pIdx;
                bestScore = score;
            }
        }
        pWInfo->a[i].pIdx = pBestIdx;
        pWInfo->a[i].score = bestScore;
        pWInfo->a[i].bRev = 0;
        loopMask |= mask;
        if( pBestIdx ) {
            pWInfo->a[i].iCur = pParse->nTab++;
            pWInfo->peakNTab = pParse->nTab;
        }
    }

    /* Check to see if the ORDER BY clause is or can be satisfied by the
    ** use of an index on the first table.
    */
    if( ppOrderBy && *ppOrderBy && pTabList->nSrc>0 ) {
        Index *pSortIdx;
        Index *pIdx;
        Table *pTab;
        int bRev = 0;

        pTab = pTabList->a[0].pTab;
        pIdx = pWInfo->a[0].pIdx;
        if( pIdx && pWInfo->a[0].score==4 ) {
            /* If there is already an IN index on the left-most table,
            ** it will not give the correct sort order.
            ** So, pretend that no suitable index is found.
            */
            pSortIdx = 0;
        } else if( iDirectEq[0]>=0 || iDirectLt[0]>=0 || iDirectGt[0]>=0 ) {
            /* If the left-most column is accessed using its ROWID, then do
            ** not try to sort by index.
            */
            pSortIdx = 0;
        } else {
            int nEqCol = (pWInfo->a[0].score+4)/8;
            pSortIdx = findSortingIndex(pTab, pTabList->a[0].iCursor,
                                        *ppOrderBy, pIdx, nEqCol, &bRev);
        }
        if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ) {
            if( pIdx==0 ) {
                pWInfo->a[0].pIdx = pSortIdx;
                pWInfo->a[0].iCur = pParse->nTab++;
                pWInfo->peakNTab = pParse->nTab;
            }
            pWInfo->a[0].bRev = bRev;
            *ppOrderBy = 0;
        }
    }

    /* Open all tables in the pTabList and all indices used by those tables.
    */
    for(i=0; i<pTabList->nSrc; i++) {
        Table *pTab;

        pTab = pTabList->a[i].pTab;
        if( pTab->isTransient || pTab->pSelect ) continue;
        sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
        sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
        sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
        sqliteCodeVerifySchema(pParse, pTab->iDb);
        if( pWInfo->a[i].pIdx!=0 ) {
            sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
            sqliteVdbeAddOp(v, OP_OpenRead,
                            pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
            sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
        }
    }

    /* Generate the code to do the search
    */
    loopMask = 0;
    for(i=0; i<pTabList->nSrc; i++) {
        int j, k;
        int iCur = pTabList->a[i].iCursor;
        Index *pIdx;
        WhereLevel *pLevel = &pWInfo->a[i];

        /* If this is the right table of a LEFT OUTER JOIN, allocate and
        ** initialize a memory cell that records if this table matches any
        ** row of the left table of the join.
        */
        if( i>0 && (pTabList->a[i-1].jointype & JT_LEFT)!=0 ) {
            if( !pParse->nMem ) pParse->nMem++;
            pLevel->iLeftJoin = pParse->nMem++;
            sqliteVdbeAddOp(v, OP_String, 0, 0);
            sqliteVdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
        }

        pIdx = pLevel->pIdx;
        pLevel->inOp = OP_Noop;
        if( i<ARRAYSIZE(iDirectEq) && iDirectEq[i]>=0 ) {
            /* Case 1:  We can directly reference a single row using an
            **          equality comparison against the ROWID field.  Or
            **          we reference multiple rows using a "rowid IN (...)"
            **          construct.
            */
            k = iDirectEq[i];
            assert( k<nExpr );
            assert( aExpr[k].p!=0 );
            assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
            brk = pLevel->brk = sqliteVdbeMakeLabel(v);
            if( aExpr[k].idxLeft==iCur ) {
                Expr *pX = aExpr[k].p;
                if( pX->op!=TK_IN ) {
                    sqliteExprCode(pParse, aExpr[k].p->pRight);
                } else if( pX->pList ) {
                    sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
                    pLevel->inOp = OP_SetNext;
                    pLevel->inP1 = pX->iTable;
                    pLevel->inP2 = sqliteVdbeCurrentAddr(v);
                } else {
                    assert( pX->pSelect );
                    sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
                    sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
                    pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
                    pLevel->inOp = OP_Next;
                    pLevel->inP1 = pX->iTable;
                }
            } else {
                sqliteExprCode(pParse, aExpr[k].p->pLeft);
            }
            aExpr[k].p = 0;
            cont = pLevel->cont = sqliteVdbeMakeLabel(v);
            sqliteVdbeAddOp(v, OP_MustBeInt, 1, brk);
            haveKey = 0;
            sqliteVdbeAddOp(v, OP_NotExists, iCur, brk);
            pLevel->op = OP_Noop;
        } else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ) {
            /* Case 2:  There is an index and all terms of the WHERE clause that
            **          refer to the index use the "==" or "IN" operators.
            */
            int start;
            int testOp;
            int nColumn = (pLevel->score+4)/8;
            brk = pLevel->brk = sqliteVdbeMakeLabel(v);
            for(j=0; j<nColumn; j++) {
                for(k=0; k<nExpr; k++) {
                    Expr *pX = aExpr[k].p;
                    if( pX==0 ) continue;
                    if( aExpr[k].idxLeft==iCur
                            && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
                            && pX->pLeft->iColumn==pIdx->aiColumn[j]
                      ) {
                        if( pX->op==TK_EQ ) {
                            sqliteExprCode(pParse, pX->pRight);
                            aExpr[k].p = 0;
                            break;
                        }
                        if( pX->op==TK_IN && nColumn==1 ) {
                            if( pX->pList ) {
                                sqliteVdbeAddOp(v, OP_SetFirst, pX->iTable, brk);
                                pLevel->inOp = OP_SetNext;
                                pLevel->inP1 = pX->iTable;
                                pLevel->inP2 = sqliteVdbeCurrentAddr(v);
                            } else {
                                assert( pX->pSelect );
                                sqliteVdbeAddOp(v, OP_Rewind, pX->iTable, brk);
                                sqliteVdbeAddOp(v, OP_KeyAsData, pX->iTable, 1);
                                pLevel->inP2 = sqliteVdbeAddOp(v, OP_FullKey, pX->iTable, 0);
                                pLevel->inOp = OP_Next;
                                pLevel->inP1 = pX->iTable;
                            }
                            aExpr[k].p = 0;
                            break;
                        }
                    }
                    if( aExpr[k].idxRight==iCur
                            && aExpr[k].p->op==TK_EQ
                            && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
                            && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, aExpr[k].p->pLeft);
                        aExpr[k].p = 0;
                        break;
                    }
                }
            }
            pLevel->iMem = pParse->nMem++;
            cont = pLevel->cont = sqliteVdbeMakeLabel(v);
            sqliteVdbeAddOp(v, OP_NotNull, -nColumn, sqliteVdbeCurrentAddr(v)+3);
            sqliteVdbeAddOp(v, OP_Pop, nColumn, 0);
            sqliteVdbeAddOp(v, OP_Goto, 0, brk);
            sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0);
            sqliteAddIdxKeyType(v, pIdx);
            if( nColumn==pIdx->nColumn || pLevel->bRev ) {
                sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
                testOp = OP_IdxGT;
            } else {
                sqliteVdbeAddOp(v, OP_Dup, 0, 0);
                sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
                sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
                testOp = OP_IdxGE;
            }
            if( pLevel->bRev ) {
                /* Scan in reverse order */
                sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
                sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
                start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
                sqliteVdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk);
                pLevel->op = OP_Prev;
            } else {
                /* Scan in the forward order */
                sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
                start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
                sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
                pLevel->op = OP_Next;
            }
            sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
            sqliteVdbeAddOp(v, OP_IdxIsNull, nColumn, cont);
            sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
            if( i==pTabList->nSrc-1 && pushKey ) {
                haveKey = 1;
            } else {
                sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
                haveKey = 0;
            }
            pLevel->p1 = pLevel->iCur;
            pLevel->p2 = start;
        } else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ) {
            /* Case 3:  We have an inequality comparison against the ROWID field.
            */
            int testOp = OP_Noop;
            int start;

            brk = pLevel->brk = sqliteVdbeMakeLabel(v);
            cont = pLevel->cont = sqliteVdbeMakeLabel(v);
            if( iDirectGt[i]>=0 ) {
                k = iDirectGt[i];
                assert( k<nExpr );
                assert( aExpr[k].p!=0 );
                assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
                if( aExpr[k].idxLeft==iCur ) {
                    sqliteExprCode(pParse, aExpr[k].p->pRight);
                } else {
                    sqliteExprCode(pParse, aExpr[k].p->pLeft);
                }
                sqliteVdbeAddOp(v, OP_ForceInt,
                                aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk);
                sqliteVdbeAddOp(v, OP_MoveTo, iCur, brk);
                aExpr[k].p = 0;
            } else {
                sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
            }
            if( iDirectLt[i]>=0 ) {
                k = iDirectLt[i];
                assert( k<nExpr );
                assert( aExpr[k].p!=0 );
                assert( aExpr[k].idxLeft==iCur || aExpr[k].idxRight==iCur );
                if( aExpr[k].idxLeft==iCur ) {
                    sqliteExprCode(pParse, aExpr[k].p->pRight);
                } else {
                    sqliteExprCode(pParse, aExpr[k].p->pLeft);
                }
                /* sqliteVdbeAddOp(v, OP_MustBeInt, 0, sqliteVdbeCurrentAddr(v)+1); */
                pLevel->iMem = pParse->nMem++;
                sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
                if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ) {
                    testOp = OP_Ge;
                } else {
                    testOp = OP_Gt;
                }
                aExpr[k].p = 0;
            }
            start = sqliteVdbeCurrentAddr(v);
            pLevel->op = OP_Next;
            pLevel->p1 = iCur;
            pLevel->p2 = start;
            if( testOp!=OP_Noop ) {
                sqliteVdbeAddOp(v, OP_Recno, iCur, 0);
                sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
                sqliteVdbeAddOp(v, testOp, 0, brk);
            }
            haveKey = 0;
        } else if( pIdx==0 ) {
            /* Case 4:  There is no usable index.  We must do a complete
            **          scan of the entire database table.
            */
            int start;

            brk = pLevel->brk = sqliteVdbeMakeLabel(v);
            cont = pLevel->cont = sqliteVdbeMakeLabel(v);
            sqliteVdbeAddOp(v, OP_Rewind, iCur, brk);
            start = sqliteVdbeCurrentAddr(v);
            pLevel->op = OP_Next;
            pLevel->p1 = iCur;
            pLevel->p2 = start;
            haveKey = 0;
        } else {
            /* Case 5: The WHERE clause term that refers to the right-most
            **         column of the index is an inequality.  For example, if
            **         the index is on (x,y,z) and the WHERE clause is of the
            **         form "x=5 AND y<10" then this case is used.  Only the
            **         right-most column can be an inequality - the rest must
            **         use the "==" operator.
            **
            **         This case is also used when there are no WHERE clause
            **         constraints but an index is selected anyway, in order
            **         to force the output order to conform to an ORDER BY.
            */
            int score = pLevel->score;
            int nEqColumn = score/8;
            int start;
            int leFlag, geFlag;
            int testOp;

            /* Evaluate the equality constraints
            */
            for(j=0; j<nEqColumn; j++) {
                for(k=0; k<nExpr; k++) {
                    if( aExpr[k].p==0 ) continue;
                    if( aExpr[k].idxLeft==iCur
                            && aExpr[k].p->op==TK_EQ
                            && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
                            && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, aExpr[k].p->pRight);
                        aExpr[k].p = 0;
                        break;
                    }
                    if( aExpr[k].idxRight==iCur
                            && aExpr[k].p->op==TK_EQ
                            && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
                            && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, aExpr[k].p->pLeft);
                        aExpr[k].p = 0;
                        break;
                    }
                }
            }

            /* Duplicate the equality term values because they will all be
            ** used twice: once to make the termination key and once to make the
            ** start key.
            */
            for(j=0; j<nEqColumn; j++) {
                sqliteVdbeAddOp(v, OP_Dup, nEqColumn-1, 0);
            }

            /* Labels for the beginning and end of the loop
            */
            cont = pLevel->cont = sqliteVdbeMakeLabel(v);
            brk = pLevel->brk = sqliteVdbeMakeLabel(v);

            /* Generate the termination key.  This is the key value that
            ** will end the search.  There is no termination key if there
            ** are no equality terms and no "X<..." term.
            **
            ** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
            ** key computed here really ends up being the start key.
            */
            if( (score & 1)!=0 ) {
                for(k=0; k<nExpr; k++) {
                    Expr *pExpr = aExpr[k].p;
                    if( pExpr==0 ) continue;
                    if( aExpr[k].idxLeft==iCur
                            && (pExpr->op==TK_LT || pExpr->op==TK_LE)
                            && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
                            && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, pExpr->pRight);
                        leFlag = pExpr->op==TK_LE;
                        aExpr[k].p = 0;
                        break;
                    }
                    if( aExpr[k].idxRight==iCur
                            && (pExpr->op==TK_GT || pExpr->op==TK_GE)
                            && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
                            && pExpr->pRight->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, pExpr->pLeft);
                        leFlag = pExpr->op==TK_GE;
                        aExpr[k].p = 0;
                        break;
                    }
                }
                testOp = OP_IdxGE;
            } else {
                testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop;
                leFlag = 1;
            }
            if( testOp!=OP_Noop ) {
                int nCol = nEqColumn + (score & 1);
                pLevel->iMem = pParse->nMem++;
                sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
                sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
                sqliteVdbeAddOp(v, OP_Goto, 0, brk);
                sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
                sqliteAddIdxKeyType(v, pIdx);
                if( leFlag ) {
                    sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
                }
                if( pLevel->bRev ) {
                    sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk);
                } else {
                    sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
                }
            } else if( pLevel->bRev ) {
                sqliteVdbeAddOp(v, OP_Last, pLevel->iCur, brk);
            }

            /* Generate the start key.  This is the key that defines the lower
            ** bound on the search.  There is no start key if there are no
            ** equality terms and if there is no "X>..." term.  In
            ** that case, generate a "Rewind" instruction in place of the
            ** start key search.
            **
            ** 2002-Dec-04: In the case of a reverse-order search, the so-called
            ** "start" key really ends up being used as the termination key.
            */
            if( (score & 2)!=0 ) {
                for(k=0; k<nExpr; k++) {
                    Expr *pExpr = aExpr[k].p;
                    if( pExpr==0 ) continue;
                    if( aExpr[k].idxLeft==iCur
                            && (pExpr->op==TK_GT || pExpr->op==TK_GE)
                            && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight
                            && pExpr->pLeft->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, pExpr->pRight);
                        geFlag = pExpr->op==TK_GE;
                        aExpr[k].p = 0;
                        break;
                    }
                    if( aExpr[k].idxRight==iCur
                            && (pExpr->op==TK_LT || pExpr->op==TK_LE)
                            && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft
                            && pExpr->pRight->iColumn==pIdx->aiColumn[j]
                      ) {
                        sqliteExprCode(pParse, pExpr->pLeft);
                        geFlag = pExpr->op==TK_LE;
                        aExpr[k].p = 0;
                        break;
                    }
                }
            } else {
                geFlag = 1;
            }
            if( nEqColumn>0 || (score&2)!=0 ) {
                int nCol = nEqColumn + ((score&2)!=0);
                sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3);
                sqliteVdbeAddOp(v, OP_Pop, nCol, 0);
                sqliteVdbeAddOp(v, OP_Goto, 0, brk);
                sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0);
                sqliteAddIdxKeyType(v, pIdx);
                if( !geFlag ) {
                    sqliteVdbeAddOp(v, OP_IncrKey, 0, 0);
                }
                if( pLevel->bRev ) {
                    pLevel->iMem = pParse->nMem++;
                    sqliteVdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
                    testOp = OP_IdxLT;
                } else {
                    sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk);
                }
            } else if( pLevel->bRev ) {
                testOp = OP_Noop;
            } else {
                sqliteVdbeAddOp(v, OP_Rewind, pLevel->iCur, brk);
            }

            /* Generate the the top of the loop.  If there is a termination
            ** key we have to test for that key and abort at the top of the
            ** loop.
            */
            start = sqliteVdbeCurrentAddr(v);
            if( testOp!=OP_Noop ) {
                sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
                sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk);
            }
            sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0);
            sqliteVdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont);
            sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0);
            if( i==pTabList->nSrc-1 && pushKey ) {
                haveKey = 1;
            } else {
                sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
                haveKey = 0;
            }

            /* Record the instruction used to terminate the loop.
            */
            pLevel->op = pLevel->bRev ? OP_Prev : OP_Next;
            pLevel->p1 = pLevel->iCur;
            pLevel->p2 = start;
        }
        loopMask |= getMask(&maskSet, iCur);

        /* Insert code to test every subexpression that can be completely
        ** computed using the current set of tables.
        */
        for(j=0; j<nExpr; j++) {
            if( aExpr[j].p==0 ) continue;
            if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue;
            if( pLevel->iLeftJoin && !ExprHasProperty(aExpr[j].p,EP_FromJoin) ) {
                continue;
            }
            if( haveKey ) {
                haveKey = 0;
                sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
            }
            sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
            aExpr[j].p = 0;
        }
        brk = cont;

        /* For a LEFT OUTER JOIN, generate code that will record the fact that
        ** at least one row of the right table has matched the left table.
        */
        if( pLevel->iLeftJoin ) {
            pLevel->top = sqliteVdbeCurrentAddr(v);
            sqliteVdbeAddOp(v, OP_Integer, 1, 0);
            sqliteVdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
            for(j=0; j<nExpr; j++) {
                if( aExpr[j].p==0 ) continue;
                if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue;
                if( haveKey ) {
                    /* Cannot happen.  "haveKey" can only be true if pushKey is true
                    ** an pushKey can only be true for DELETE and UPDATE and there are
                    ** no outer joins with DELETE and UPDATE.
                    */
                    haveKey = 0;
                    sqliteVdbeAddOp(v, OP_MoveTo, iCur, 0);
                }
                sqliteExprIfFalse(pParse, aExpr[j].p, cont, 1);
                aExpr[j].p = 0;
            }
        }
    }
    pWInfo->iContinue = cont;
    if( pushKey && !haveKey ) {
        sqliteVdbeAddOp(v, OP_Recno, pTabList->a[0].iCursor, 0);
    }
    freeMaskSet(&maskSet);
    return pWInfo;
}
Exemplo n.º 11
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;
  }
}