Example #1
0
 static Select sqlite3SelectNew(
 Parse pParse,        /* Parsing context */
 ExprList pEList,     /* which columns to include in the result */
 SrcList pSrc,        /* the FROM clause -- which tables to scan */
 Expr pWhere,         /* the WHERE clause */
 ExprList pGroupBy,   /* the GROUP BY clause */
 Expr pHaving,        /* the HAVING clause */
 ExprList pOrderBy,   /* the ORDER BY clause */
 int isDistinct,       /* true if the DISTINCT keyword is present */
 Expr pLimit,         /* LIMIT value.  NULL means not used */
 Expr pOffset         /* OFFSET value.  NULL means no offset */
 )
 {
   Select pNew;
   //           Select standin;
   sqlite3 db = pParse.db;
   pNew = new Select();//sqlite3DbMallocZero(db, sizeof(*pNew) );
   Debug.Assert( //db.mallocFailed != 0 ||
   null == pOffset || pLimit != null ); /* OFFSET implies LIMIT */
   //if( pNew==null   ){
   //  pNew = standin;
   //  memset(pNew, 0, sizeof(*pNew));
   //}
   if ( pEList == null )
   {
     pEList = sqlite3ExprListAppend( pParse, null, sqlite3Expr( db, TK_ALL, null ) );
   }
   pNew.pEList = pEList;
   pNew.pSrc = pSrc;
   pNew.pWhere = pWhere;
   pNew.pGroupBy = pGroupBy;
   pNew.pHaving = pHaving;
   pNew.pOrderBy = pOrderBy;
   pNew.selFlags = (u16)( isDistinct != 0 ? SF_Distinct : 0 );
   pNew.op = TK_SELECT;
   pNew.pLimit = pLimit;
   pNew.pOffset = pOffset;
   Debug.Assert( pOffset == null || pLimit != null );
   pNew.addrOpenEphm[0] = -1;
   pNew.addrOpenEphm[1] = -1;
   pNew.addrOpenEphm[2] = -1;
   //if ( db.mallocFailed != 0 )
   //{
   //  clearSelect( db, pNew );
   //  //if ( pNew != standin ) sqlite3DbFree( db, ref pNew );
   //  pNew = null;
   //}
   return pNew;
 }
Example #2
0
        private void AuthRead(Expr Expr, Schema Schema, SrcList TabList)
        {
            //sqlite3 *db = pParse->db;
            //Table *pTab = 0;      /* The table being read */
            //const char *zCol;     /* Name of the column of the table */
            //int iSrc;             /* Index in pTabList->a[] of table being read */
            //int iDb;              /* The index of the database the expression refers to */
            //int iCol;             /* Index of column in table */

            //if( db->xAuth==0 ) return;
            //iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
            //if( iDb<0 ){
            //  /* An attempt to read a column out of a subquery or other
            //  ** temporary table. */
            //  return;
            //}

            //assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
            //if( pExpr->op==TK_TRIGGER ){
            //  pTab = pParse->pTriggerTab;
            //}else{
            //  assert( pTabList );
            //  for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
            //    if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
            //      pTab = pTabList->a[iSrc].pTab;
            //      break;
            //    }
            //  }
            //}
            //iCol = pExpr->iColumn;
            //if( NEVER(pTab==0) ) return;

            //if( iCol>=0 ){
            //  assert( iCol<pTab->nCol );
            //  zCol = pTab->aCol[iCol].zName;
            //}else if( pTab->iPKey>=0 ){
            //  assert( pTab->iPKey<pTab->nCol );
            //  zCol = pTab->aCol[pTab->iPKey].zName;
            //}else{
            //  zCol = "ROWID";
            //}
            //assert( iDb>=0 && iDb<db->nDb );
            //if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){
            //  pExpr->op = TK_NULL;
            //}
        }
Example #3
0
    /*
    ** 2001 September 15
    **
    ** The author disclaims copyright to this source code.  In place of
    ** a legal notice, here is a blessing:
    **
    **    May you do good and not evil.
    **    May you find forgiveness for yourself and forgive others.
    **    May you share freely, never taking more than you give.
    **
    *************************************************************************
    ** This file contains C code routines that are called by the parser
    ** in order to generate code for DELETE FROM statements.
    *************************************************************************
    **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
    **  C#-SQLite is an independent reimplementation of the SQLite software library
    **
    **  SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
    **
    *************************************************************************
    */
    //#include "sqliteInt.h"

    /*
    ** Look up every table that is named in pSrc.  If any table is not found,
    ** add an error message to pParse.zErrMsg and return NULL.  If all tables
    ** are found, return a pointer to the last table.
    */
    static Table sqlite3SrcListLookup( Parse pParse, SrcList pSrc )
    {
      SrcList_item pItem = pSrc.a[0];
      Table pTab;
      Debug.Assert( pItem != null && pSrc.nSrc == 1 );
      pTab = sqlite3LocateTable( pParse, 0, pItem.zName, pItem.zDatabase );
      sqlite3DeleteTable( pParse.db, ref pItem.pTab );
      pItem.pTab = pTab;
      if ( pTab != null )
      {
        pTab.nRef++;
      }
      if ( sqlite3IndexedByLookup( pParse, pItem ) != 0 )
      {
        pTab = null;
      }
      return pTab;
    }
Example #4
0
 public static Select New(Parse parse, ExprList list, SrcList src, Expr where_, ExprList groupBy, Expr having, ExprList orderBy, SF selFlags, Expr limit, Expr offset)
 {
     Context ctx = parse.Ctx;
     Select newSelect = new Select();
     Debug.Assert(ctx.MallocFailed || offset == null || limit != null); // OFFSET implies LIMIT
     // Select standin;
     if (newSelect == null)
     {
         Debug.Assert(ctx.MallocFailed);
         //newSelect = standin;
         //_memset(newSelect, 0, sizeof(newSelect));
     }
     if (list == null)
         list = Expr.ListAppend(parse, null, Expr.Expr_(ctx, TK.ALL, null));
     newSelect.EList = list;
     if (src == null) src = new SrcList();
     newSelect.Src = src;
     newSelect.Where = where_;
     newSelect.GroupBy = groupBy;
     newSelect.Having = having;
     newSelect.OrderBy = orderBy;
     newSelect.SelFlags = selFlags;
     newSelect.OP = TK.SELECT;
     newSelect.Limit = limit;
     newSelect.Offset = offset;
     Debug.Assert(offset == null || limit != null);
     newSelect.AddrOpenEphms[0] = (OP) - 1;
     newSelect.AddrOpenEphms[1] = (OP) - 1;
     newSelect.AddrOpenEphms[2] = (OP) - 1;
     if (ctx.MallocFailed)
     {
         ClearSelect(ctx, newSelect);
         //if (newSelect != standin) C._tagfree(ctx, ref newSelect);
         newSelect = null;
     }
     else
         Debug.Assert(newSelect.Src != null || parse.Errs > 0);
     //Debug.Assert(newSelect != standin);
     return newSelect;
 }
Example #5
0
    static int sqlite3Select(
    Parse pParse,         /* The parser context */
    Select p,             /* The SELECT statement being coded. */
    ref SelectDest pDest /* What to do with the query results */
    )
    {
      int i, j;               /* Loop counters */
      WhereInfo pWInfo;       /* Return from sqlite3WhereBegin() */
      Vdbe v;                 /* The virtual machine under construction */
      bool isAgg;             /* True for select lists like "count()" */
      ExprList pEList = new ExprList();      /* List of columns to extract. */
      SrcList pTabList = new SrcList();     /* List of tables to select from */
      Expr pWhere;            /* The WHERE clause.  May be NULL */
      ExprList pOrderBy;      /* The ORDER BY clause.  May be NULL */
      ExprList pGroupBy;      /* The GROUP BY clause.  May be NULL */
      Expr pHaving;           /* The HAVING clause.  May be NULL */
      bool isDistinct;        /* True if the DISTINCT keyword is present */
      int distinct;           /* Table to use for the distinct set */
      int rc = 1;             /* Value to return from this function */
      int addrSortIndex;      /* Address of an OP_OpenEphemeral instruction */
      AggInfo sAggInfo;       /* Information used by aggregate queries */
      int iEnd;               /* Address of the end of the query */
      sqlite3 db;             /* The database connection */

#if !SQLITE_OMIT_EXPLAIN
      int iRestoreSelectId = pParse.iSelectId;
      pParse.iSelectId = pParse.iNextSelectId++;
#endif

      db = pParse.db;
      if ( p == null /*|| db.mallocFailed != 0 */ || pParse.nErr != 0 )
      {
        return 1;
      }
#if !SQLITE_OMIT_AUTHORIZATION
if (sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0)) return 1;
#endif
      sAggInfo = new AggInfo();// memset(sAggInfo, 0, sAggInfo).Length;

      if ( pDest.eDest <= SRT_Discard ) //IgnorableOrderby(pDest))
      {
        Debug.Assert( pDest.eDest == SRT_Exists || pDest.eDest == SRT_Union ||
        pDest.eDest == SRT_Except || pDest.eDest == SRT_Discard );
        /* If ORDER BY makes no difference in the output then neither does
        ** DISTINCT so it can be removed too. */
        sqlite3ExprListDelete( db, ref p.pOrderBy );
        p.pOrderBy = null;
        p.selFlags = (u16)( p.selFlags & ~SF_Distinct );
      }
      sqlite3SelectPrep( pParse, p, null );
      pOrderBy = p.pOrderBy;
      pTabList = p.pSrc;
      pEList = p.pEList;
      if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
      {
        goto select_end;
      }
      isAgg = ( p.selFlags & SF_Aggregate ) != 0;
      Debug.Assert( pEList != null );

      /* Begin generating code.
      */
      v = sqlite3GetVdbe( pParse );
      if ( v == null )
        goto select_end;

      /* If writing to memory or generating a set
      ** only a single column may be output.
      */
#if !SQLITE_OMIT_SUBQUERY
      if ( checkForMultiColumnSelectError( pParse, pDest, pEList.nExpr ) )
      {
        goto select_end;
      }
#endif

      /* Generate code for all sub-queries in the FROM clause
*/
#if !SQLITE_OMIT_SUBQUERY || !SQLITE_OMIT_VIEW
      for ( i = 0; p.pPrior == null && i < pTabList.nSrc; i++ )
      {
        SrcList_item pItem = pTabList.a[i];
        SelectDest dest = new SelectDest();
        Select pSub = pItem.pSelect;
        bool isAggSub;

        if ( pSub == null || pItem.isPopulated != 0 )
          continue;

        /* Increment Parse.nHeight by the height of the largest expression
        ** tree refered to by this, the parent select. The child select
        ** may contain expression trees of at most
        ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
        ** more conservative than necessary, but much easier than enforcing
        ** an exact limit.
        */
        pParse.nHeight += sqlite3SelectExprHeight( p );

        /* Check to see if the subquery can be absorbed into the parent. */
        isAggSub = ( pSub.selFlags & SF_Aggregate ) != 0;
        if ( flattenSubquery( pParse, p, i, isAgg, isAggSub ) != 0 )
        {
          if ( isAggSub )
          {
            isAgg = true;
            p.selFlags |= SF_Aggregate;
          }
          i = -1;
        }
        else
        {
          sqlite3SelectDestInit( dest, SRT_EphemTab, pItem.iCursor );
          Debug.Assert( 0 == pItem.isPopulated );
          explainSetInteger( ref pItem.iSelectId, (int)pParse.iNextSelectId );
          sqlite3Select( pParse, pSub, ref dest );
          pItem.isPopulated = 1;
          pItem.pTab.nRowEst = (uint)pSub.nSelectRow;
        }
        //if ( /* pParse.nErr != 0 || */ db.mallocFailed != 0 )
        //{
        //  goto select_end;
        //}
        pParse.nHeight -= sqlite3SelectExprHeight( p );
        pTabList = p.pSrc;
        if ( !( pDest.eDest <= SRT_Discard ) )//        if( null==IgnorableOrderby(pDest) )
        {
          pOrderBy = p.pOrderBy;
        }
      }
      pEList = p.pEList;
#endif
      pWhere = p.pWhere;
      pGroupBy = p.pGroupBy;
      pHaving = p.pHaving;
      isDistinct = ( p.selFlags & SF_Distinct ) != 0;

#if  !SQLITE_OMIT_COMPOUND_SELECT
      /* If there is are a sequence of queries, do the earlier ones first.
*/
      if ( p.pPrior != null )
      {
        if ( p.pRightmost == null )
        {
          Select pLoop, pRight = null;
          int cnt = 0;
          int mxSelect;
          for ( pLoop = p; pLoop != null; pLoop = pLoop.pPrior, cnt++ )
          {
            pLoop.pRightmost = p;
            pLoop.pNext = pRight;
            pRight = pLoop;
          }
          mxSelect = db.aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
          if ( mxSelect != 0 && cnt > mxSelect )
          {
            sqlite3ErrorMsg( pParse, "too many terms in compound SELECT" );
            goto select_end;
          }
        }
        rc = multiSelect( pParse, p, pDest );
        explainSetInteger( ref pParse.iSelectId, iRestoreSelectId );
        return rc;
      }
#endif

      /* If possible, rewrite the query to use GROUP BY instead of DISTINCT.
** GROUP BY might use an index, DISTINCT never does.
*/
      Debug.Assert( p.pGroupBy == null || ( p.selFlags & SF_Aggregate ) != 0 );
      if ( ( p.selFlags & ( SF_Distinct | SF_Aggregate ) ) == SF_Distinct )
      {
        p.pGroupBy = sqlite3ExprListDup( db, p.pEList, 0 );
        pGroupBy = p.pGroupBy;
        p.selFlags = (u16)( p.selFlags & ~SF_Distinct );
      }

      /* If there is both a GROUP BY and an ORDER BY clause and they are
      ** identical, then disable the ORDER BY clause since the GROUP BY
      ** will cause elements to come out in the correct order.  This is
      ** an optimization - the correct answer should result regardless.
      ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
      ** to disable this optimization for testing purposes.
      */
      if ( sqlite3ExprListCompare( p.pGroupBy, pOrderBy ) == 0
      && ( db.flags & SQLITE_GroupByOrder ) == 0 )
      {
        pOrderBy = null;
      }

      /* If there is an ORDER BY clause, then this sorting
      ** index might end up being unused if the data can be
      ** extracted in pre-sorted order.  If that is the case, then the
      ** OP_OpenEphemeral instruction will be changed to an OP_Noop once
      ** we figure out that the sorting index is not needed.  The addrSortIndex
      ** variable is used to facilitate that change.
      */
      if ( pOrderBy != null )
      {
        KeyInfo pKeyInfo;
        pKeyInfo = keyInfoFromExprList( pParse, pOrderBy );
        pOrderBy.iECursor = pParse.nTab++;
        p.addrOpenEphm[2] = addrSortIndex =
        sqlite3VdbeAddOp4( v, OP_OpenEphemeral,
        pOrderBy.iECursor, pOrderBy.nExpr + 2, 0,
        pKeyInfo, P4_KEYINFO_HANDOFF );
      }
      else
      {
        addrSortIndex = -1;
      }

      /* If the output is destined for a temporary table, open that table.
      */
      if ( pDest.eDest == SRT_EphemTab )
      {
        sqlite3VdbeAddOp2( v, OP_OpenEphemeral, pDest.iParm, pEList.nExpr );
      }

      /* Set the limiter.
      */
      iEnd = sqlite3VdbeMakeLabel( v );
      p.nSelectRow = (double)LARGEST_INT64;
      computeLimitRegisters( pParse, p, iEnd );

      /* Open a virtual index to use for the distinct set.
      */
      if ( ( p.selFlags & SF_Distinct ) != 0 )
      {
        KeyInfo pKeyInfo;
        Debug.Assert( isAgg || pGroupBy != null );
        distinct = pParse.nTab++;
        pKeyInfo = keyInfoFromExprList( pParse, p.pEList );
        sqlite3VdbeAddOp4( v, OP_OpenEphemeral, distinct, 0, 0,
        pKeyInfo, P4_KEYINFO_HANDOFF );
        sqlite3VdbeChangeP5( v, BTREE_UNORDERED );
      }
      else
      {
        distinct = -1;
      }

      /* Aggregate and non-aggregate queries are handled differently */
      if ( !isAgg && pGroupBy == null )
      {
        /* This case is for non-aggregate queries
        ** Begin the database scan
        */
        pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref pOrderBy, 0 );
        if ( pWInfo == null )
          goto select_end;
        if ( pWInfo.nRowOut < p.nSelectRow )
          p.nSelectRow = pWInfo.nRowOut;

        /* If sorting index that was created by a prior OP_OpenEphemeral
        ** instruction ended up not being needed, then change the OP_OpenEphemeral
        ** into an OP_Noop.
        */
        if ( addrSortIndex >= 0 && pOrderBy == null )
        {
          sqlite3VdbeChangeToNoop( v, addrSortIndex, 1 );
          p.addrOpenEphm[2] = -1;
        }

        /* Use the standard inner loop
        */
        Debug.Assert( !isDistinct );
        selectInnerLoop( pParse, p, pEList, 0, 0, pOrderBy, -1, pDest,
        pWInfo.iContinue, pWInfo.iBreak );

        /* End the database scan loop.
        */
        sqlite3WhereEnd( pWInfo );
      }
      else
      {
        /* This is the processing for aggregate queries */
        NameContext sNC;    /* Name context for processing aggregate information */
        int iAMem;          /* First Mem address for storing current GROUP BY */
        int iBMem;          /* First Mem address for previous GROUP BY */
        int iUseFlag;       /* Mem address holding flag indicating that at least
** one row of the input to the aggregator has been
** processed */
        int iAbortFlag;     /* Mem address which causes query abort if positive */
        int groupBySort;    /* Rows come from source in GR BY' clause thanROUP BY order */

        int addrEnd;        /* End of processing for this SELECT */

        /* Remove any and all aliases between the result set and the
        ** GROUP BY clause.
        */
        if ( pGroupBy != null )
        {
          int k;                        /* Loop counter */
          ExprList_item pItem;          /* For looping over expression in a list */

          for ( k = p.pEList.nExpr; k > 0; k-- )//, pItem++)
          {
            pItem = p.pEList.a[p.pEList.nExpr - k];
            pItem.iAlias = 0;
          }
          for ( k = pGroupBy.nExpr; k > 0; k-- )//, pItem++ )
          {
            pItem = pGroupBy.a[pGroupBy.nExpr - k];
            pItem.iAlias = 0;
          }
          if ( p.nSelectRow > (double)100 )
            p.nSelectRow = (double)100;
        }
        else
        {
          p.nSelectRow = (double)1;
        }

        /* Create a label to jump to when we want to abort the query */
        addrEnd = sqlite3VdbeMakeLabel( v );

        /* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
        ** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
        ** SELECT statement.
        */
        sNC = new NameContext(); // memset(sNC, 0, sNC).Length;
        sNC.pParse = pParse;
        sNC.pSrcList = pTabList;
        sNC.pAggInfo = sAggInfo;
        sAggInfo.nSortingColumn = pGroupBy != null ? pGroupBy.nExpr + 1 : 0;
        sAggInfo.pGroupBy = pGroupBy;
        sqlite3ExprAnalyzeAggList( sNC, pEList );
        sqlite3ExprAnalyzeAggList( sNC, pOrderBy );
        if ( pHaving != null )
        {
          sqlite3ExprAnalyzeAggregates( sNC, ref pHaving );
        }
        sAggInfo.nAccumulator = sAggInfo.nColumn;
        for ( i = 0; i < sAggInfo.nFunc; i++ )
        {
          Debug.Assert( !ExprHasProperty( sAggInfo.aFunc[i].pExpr, EP_xIsSelect ) );
          sqlite3ExprAnalyzeAggList( sNC, sAggInfo.aFunc[i].pExpr.x.pList );
        }
        //      if ( db.mallocFailed != 0 ) goto select_end;

        /* Processing for aggregates with GROUP BY is very different and
        ** much more complex than aggregates without a GROUP BY.
        */
        if ( pGroupBy != null )
        {
          KeyInfo pKeyInfo;  /* Keying information for the group by clause */
          int j1;             /* A-vs-B comparision jump */
          int addrOutputRow;  /* Start of subroutine that outputs a result row */
          int regOutputRow;   /* Return address register for output subroutine */
          int addrSetAbort;   /* Set the abort flag and return */
          int addrTopOfLoop;  /* Top of the input loop */
          int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
          int addrReset;      /* Subroutine for resetting the accumulator */
          int regReset;       /* Return address register for reset subroutine */

          /* If there is a GROUP BY clause we might need a sorting index to
          ** implement it.  Allocate that sorting index now.  If it turns out
          ** that we do not need it after all, the OpenEphemeral instruction
          ** will be converted into a Noop.
          */
          sAggInfo.sortingIdx = pParse.nTab++;
          pKeyInfo = keyInfoFromExprList( pParse, pGroupBy );
          addrSortingIdx = sqlite3VdbeAddOp4( v, OP_OpenEphemeral,
          sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
          0, pKeyInfo, P4_KEYINFO_HANDOFF );

          /* Initialize memory locations used by GROUP BY aggregate processing
          */
          iUseFlag = ++pParse.nMem;
          iAbortFlag = ++pParse.nMem;
          regOutputRow = ++pParse.nMem;
          addrOutputRow = sqlite3VdbeMakeLabel( v );
          regReset = ++pParse.nMem;
          addrReset = sqlite3VdbeMakeLabel( v );
          iAMem = pParse.nMem + 1;
          pParse.nMem += pGroupBy.nExpr;
          iBMem = pParse.nMem + 1;
          pParse.nMem += pGroupBy.nExpr;
          sqlite3VdbeAddOp2( v, OP_Integer, 0, iAbortFlag );
#if SQLITE_DEBUG
          VdbeComment( v, "clear abort flag" );
#endif
          sqlite3VdbeAddOp2( v, OP_Integer, 0, iUseFlag );
#if SQLITE_DEBUG
          VdbeComment( v, "indicate accumulator empty" );
#endif

          /* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
          sqlite3VdbeAddOp2( v, OP_Gosub, regReset, addrReset );
          pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref pGroupBy, 0 );
          if ( pWInfo == null )
            goto select_end;
          if ( pGroupBy == null )
          {
            /* The optimizer is able to deliver rows in group by order so
            ** we do not have to sort.  The OP_OpenEphemeral table will be
            ** cancelled later because we still need to use the pKeyInfo
            */
            pGroupBy = p.pGroupBy;
            groupBySort = 0;
          }
          else
          {
            /* Rows are coming out in undetermined order.  We have to push
            ** each row into a sorting index, terminate the first loop,
            ** then loop over the sorting index in order to get the output
            ** in sorted order
            */
            int regBase;
            int regRecord;
            int nCol;
            int nGroupBy;

            explainTempTable( pParse,
            isDistinct && 0 == ( p.selFlags & SF_Distinct ) ? "DISTINCT" : "GROUP BY" );

            groupBySort = 1;
            nGroupBy = pGroupBy.nExpr;
            nCol = nGroupBy + 1;
            j = nGroupBy + 1;
            for ( i = 0; i < sAggInfo.nColumn; i++ )
            {
              if ( sAggInfo.aCol[i].iSorterColumn >= j )
              {
                nCol++;
                j++;
              }
            }
            regBase = sqlite3GetTempRange( pParse, nCol );
            sqlite3ExprCacheClear( pParse );
            sqlite3ExprCodeExprList( pParse, pGroupBy, regBase, false );
            sqlite3VdbeAddOp2( v, OP_Sequence, sAggInfo.sortingIdx, regBase + nGroupBy );
            j = nGroupBy + 1;
            for ( i = 0; i < sAggInfo.nColumn; i++ )
            {
              AggInfo_col pCol = sAggInfo.aCol[i];
              if ( pCol.iSorterColumn >= j )
              {
                int r1 = j + regBase;
                int r2;
                r2 = sqlite3ExprCodeGetColumn( pParse,
                pCol.pTab, pCol.iColumn, pCol.iTable, r1 );
                if ( r1 != r2 )
                {
                  sqlite3VdbeAddOp2( v, OP_SCopy, r2, r1 );
                }
                j++;
              }
            }
            regRecord = sqlite3GetTempReg( pParse );
            sqlite3VdbeAddOp3( v, OP_MakeRecord, regBase, nCol, regRecord );
            sqlite3VdbeAddOp2( v, OP_IdxInsert, sAggInfo.sortingIdx, regRecord );
            sqlite3ReleaseTempReg( pParse, regRecord );
            sqlite3ReleaseTempRange( pParse, regBase, nCol );
            sqlite3WhereEnd( pWInfo );
            sqlite3VdbeAddOp2( v, OP_Sort, sAggInfo.sortingIdx, addrEnd );
#if SQLITE_DEBUG
            VdbeComment( v, "GROUP BY sort" );
#endif
            sAggInfo.useSortingIdx = 1;
            sqlite3ExprCacheClear( pParse );
          }

          /* Evaluate the current GROUP BY terms and store in b0, b1, b2...
          ** (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
          ** Then compare the current GROUP BY terms against the GROUP BY terms
          ** from the previous row currently stored in a0, a1, a2...
          */
          addrTopOfLoop = sqlite3VdbeCurrentAddr( v );
          sqlite3ExprCacheClear( pParse );
          for ( j = 0; j < pGroupBy.nExpr; j++ )
          {
            if ( groupBySort != 0 )
            {
              sqlite3VdbeAddOp3( v, OP_Column, sAggInfo.sortingIdx, j, iBMem + j );
            }
            else
            {
              sAggInfo.directMode = 1;
              sqlite3ExprCode( pParse, pGroupBy.a[j].pExpr, iBMem + j );
            }
          }
          sqlite3VdbeAddOp4( v, OP_Compare, iAMem, iBMem, pGroupBy.nExpr,
          pKeyInfo, P4_KEYINFO );
          j1 = sqlite3VdbeCurrentAddr( v );
          sqlite3VdbeAddOp3( v, OP_Jump, j1 + 1, 0, j1 + 1 );

          /* Generate code that runs whenever the GROUP BY changes.
          ** Changes in the GROUP BY are detected by the previous code
          ** block.  If there were no changes, this block is skipped.
          **
          ** This code copies current group by terms in b0,b1,b2,...
          ** over to a0,a1,a2.  It then calls the output subroutine
          ** and resets the aggregate accumulator registers in preparation
          ** for the next GROUP BY batch.
          */
          sqlite3ExprCodeMove( pParse, iBMem, iAMem, pGroupBy.nExpr );
          sqlite3VdbeAddOp2( v, OP_Gosub, regOutputRow, addrOutputRow );
#if SQLITE_DEBUG
          VdbeComment( v, "output one row" );
#endif
          sqlite3VdbeAddOp2( v, OP_IfPos, iAbortFlag, addrEnd );
#if SQLITE_DEBUG
          VdbeComment( v, "check abort flag" );
#endif
          sqlite3VdbeAddOp2( v, OP_Gosub, regReset, addrReset );
#if SQLITE_DEBUG
          VdbeComment( v, "reset accumulator" );
#endif

          /* Update the aggregate accumulators based on the content of
** the current row
*/
          sqlite3VdbeJumpHere( v, j1 );
          updateAccumulator( pParse, sAggInfo );
          sqlite3VdbeAddOp2( v, OP_Integer, 1, iUseFlag );
#if SQLITE_DEBUG
          VdbeComment( v, "indicate data in accumulator" );
#endif
          /* End of the loop
*/
          if ( groupBySort != 0 )
          {
            sqlite3VdbeAddOp2( v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop );
          }
          else
          {
            sqlite3WhereEnd( pWInfo );
            sqlite3VdbeChangeToNoop( v, addrSortingIdx, 1 );
          }

          /* Output the final row of result
          */
          sqlite3VdbeAddOp2( v, OP_Gosub, regOutputRow, addrOutputRow );
#if SQLITE_DEBUG
          VdbeComment( v, "output final row" );
#endif
          /* Jump over the subroutines
*/
          sqlite3VdbeAddOp2( v, OP_Goto, 0, addrEnd );

          /* Generate a subroutine that outputs a single row of the result
          ** set.  This subroutine first looks at the iUseFlag.  If iUseFlag
          ** is less than or equal to zero, the subroutine is a no-op.  If
          ** the processing calls for the query to abort, this subroutine
          ** increments the iAbortFlag memory location before returning in
          ** order to signal the caller to abort.
          */
          addrSetAbort = sqlite3VdbeCurrentAddr( v );
          sqlite3VdbeAddOp2( v, OP_Integer, 1, iAbortFlag );
          VdbeComment( v, "set abort flag" );
          sqlite3VdbeAddOp1( v, OP_Return, regOutputRow );
          sqlite3VdbeResolveLabel( v, addrOutputRow );
          addrOutputRow = sqlite3VdbeCurrentAddr( v );
          sqlite3VdbeAddOp2( v, OP_IfPos, iUseFlag, addrOutputRow + 2 );
          VdbeComment( v, "Groupby result generator entry point" );
          sqlite3VdbeAddOp1( v, OP_Return, regOutputRow );
          finalizeAggFunctions( pParse, sAggInfo );
          sqlite3ExprIfFalse( pParse, pHaving, addrOutputRow + 1, SQLITE_JUMPIFNULL );
          selectInnerLoop( pParse, p, p.pEList, 0, 0, pOrderBy,
          distinct, pDest,
          addrOutputRow + 1, addrSetAbort );
          sqlite3VdbeAddOp1( v, OP_Return, regOutputRow );
          VdbeComment( v, "end groupby result generator" );

          /* Generate a subroutine that will reset the group-by accumulator
          */
          sqlite3VdbeResolveLabel( v, addrReset );
          resetAccumulator( pParse, sAggInfo );
          sqlite3VdbeAddOp1( v, OP_Return, regReset );

        } /* endif pGroupBy.  Begin aggregate queries without GROUP BY: */
        else
        {
          ExprList pDel = null;
#if !SQLITE_OMIT_BTREECOUNT
          Table pTab;
          if ( ( pTab = isSimpleCount( p, sAggInfo ) ) != null )
          {
            /* If isSimpleCount() returns a pointer to a Table structure, then
            ** the SQL statement is of the form:
            **
            **   SELECT count() FROM <tbl>
            **
            ** where the Table structure returned represents table <tbl>.
            **
            ** This statement is so common that it is optimized specially. The
            ** OP_Count instruction is executed either on the intkey table that
            ** contains the data for table <tbl> or on one of its indexes. It
            ** is better to execute the op on an index, as indexes are almost
            ** always spread across less pages than their corresponding tables.
            */
            int iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );
            int iCsr = pParse.nTab++;     /* Cursor to scan b-tree */
            Index pIdx;                   /* Iterator variable */
            KeyInfo pKeyInfo = null;      /* Keyinfo for scanned index */
            Index pBest = null;           /* Best index found so far */
            int iRoot = pTab.tnum;        /* Root page of scanned b-tree */

            sqlite3CodeVerifySchema( pParse, iDb );
            sqlite3TableLock( pParse, iDb, pTab.tnum, 0, pTab.zName );

            /* Search for the index that has the least amount of columns. If
            ** there is such an index, and it has less columns than the table
            ** does, then we can assume that it consumes less space on disk and
            ** will therefore be cheaper to scan to determine the query result.
            ** In this case set iRoot to the root page number of the index b-tree
            ** and pKeyInfo to the KeyInfo structure required to navigate the
            ** index.
            **
            ** (2011-04-15) Do not do a full scan of an unordered index.
            **
            ** In practice the KeyInfo structure will not be used. It is only
            ** passed to keep OP_OpenRead happy.
            */
            for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
            {
              if ( pIdx.bUnordered == 0 && ( null == pBest || pIdx.nColumn < pBest.nColumn ) )
              {
                pBest = pIdx;
              }
            }
            if ( pBest != null && pBest.nColumn < pTab.nCol )
            {
              iRoot = pBest.tnum;
              pKeyInfo = sqlite3IndexKeyinfo( pParse, pBest );
            }

            /* Open a read-only cursor, execute the OP_Count, close the cursor. */
            sqlite3VdbeAddOp3( v, OP_OpenRead, iCsr, iRoot, iDb );
            if ( pKeyInfo != null )
            {
              sqlite3VdbeChangeP4( v, -1, pKeyInfo, P4_KEYINFO_HANDOFF );
            }
            sqlite3VdbeAddOp2( v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem );
            sqlite3VdbeAddOp1( v, OP_Close, iCsr );
            explainSimpleCount( pParse, pTab, pBest );
          }
          else
#endif //* SQLITE_OMIT_BTREECOUNT */
          {

            /* Check if the query is of one of the following forms:
            **
            **   SELECT min(x) FROM ...
            **   SELECT max(x) FROM ...
            **
            ** If it is, then ask the code in where.c to attempt to sort results
            ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
            ** If where.c is able to produce results sorted in this order, then
            ** add vdbe code to break out of the processing loop after the
            ** first iteration (since the first iteration of the loop is
            ** guaranteed to operate on the row with the minimum or maximum
            ** value of x, the only row required).
            **
            ** A special flag must be passed to sqlite3WhereBegin() to slightly
            ** modify behavior as follows:
            **
            **   + If the query is a "SELECT min(x)", then the loop coded by
            **     where.c should not iterate over any values with a NULL value
            **     for x.
            **
            **   + The optimizer code in where.c (the thing that decides which
            **     index or indices to use) should place a different priority on
            **     satisfying the 'ORDER BY' clause than it does in other cases.
            **     Refer to code and comments in where.c for details.
            */
            ExprList pMinMax = null;
            int flag = minMaxQuery( p );
            if ( flag != 0 )
            {
              Debug.Assert( !ExprHasProperty( p.pEList.a[0].pExpr, EP_xIsSelect ) );
              pMinMax = sqlite3ExprListDup( db, p.pEList.a[0].pExpr.x.pList, 0 );
              pDel = pMinMax;
              if ( pMinMax != null )///* && 0 == db.mallocFailed */ )
              {
                pMinMax.a[0].sortOrder = (u8)( flag != WHERE_ORDERBY_MIN ? 1 : 0 );
                pMinMax.a[0].pExpr.op = TK_COLUMN;
              }
            }

            /* This case runs if the aggregate has no GROUP BY clause.  The
            ** processing is much simpler since there is only a single row
            ** of output.
            */
            resetAccumulator( pParse, sAggInfo );
            pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref pMinMax, (byte)flag );
            if ( pWInfo == null )
            {
              sqlite3ExprListDelete( db, ref pDel );
              goto select_end;
            }
            updateAccumulator( pParse, sAggInfo );
            if ( pMinMax == null && flag != 0 )
            {
              sqlite3VdbeAddOp2( v, OP_Goto, 0, pWInfo.iBreak );
#if SQLITE_DEBUG
              VdbeComment( v, "%s() by index",
              ( flag == WHERE_ORDERBY_MIN ? "min" : "max" ) );
#endif
            }
            sqlite3WhereEnd( pWInfo );
            finalizeAggFunctions( pParse, sAggInfo );
          }

          pOrderBy = null;
          sqlite3ExprIfFalse( pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL );
          selectInnerLoop( pParse, p, p.pEList, 0, 0, null, -1,
          pDest, addrEnd, addrEnd );

          sqlite3ExprListDelete( db, ref pDel );
        }
        sqlite3VdbeResolveLabel( v, addrEnd );

      } /* endif aggregate query */

      if ( distinct >= 0 )
      {
        explainTempTable( pParse, "DISTINCT" );
      }

      /* If there is an ORDER BY clause, then we need to sort the results
      ** and send them to the callback one by one.
      */
      if ( pOrderBy != null )
      {
        explainTempTable( pParse, "ORDER BY" );
        generateSortTail( pParse, p, v, pEList.nExpr, pDest );
      }

      /* Jump here to skip this query
      */
      sqlite3VdbeResolveLabel( v, iEnd );

      /* The SELECT was successfully coded.   Set the return code to 0
      ** to indicate no errors.
      */
      rc = 0;

    /* Control jumps to here if an error is encountered above, or upon
    ** successful coding of the SELECT.
    */
select_end:
      explainSetInteger( ref pParse.iSelectId, iRestoreSelectId );

      /* Identify column names if results of the SELECT are to be output.
      */
      if ( rc == SQLITE_OK && pDest.eDest == SRT_Output )
      {
        generateColumnNames( pParse, pTabList, pEList );
      }

      sqlite3DbFree( db, ref sAggInfo.aCol );
      sqlite3DbFree( db, ref sAggInfo.aFunc );
      return rc;
    }
Example #6
0
        /* Make sure "isView" and other macros defined above are undefined. Otherwise
        ** thely may interfere with compilation of other functions in this file
        ** (or in another file, if this file becomes part of the amalgamation).  */
        //#ifdef isView
        // #undef isView
        //#endif
        //#ifdef pTrigger
        // #undef pTrigger
        //#endif

#if !SQLITE_OMIT_VIRTUALTABLE
/*
** Generate code for an UPDATE of a virtual table.
**
** The strategy is that we create an ephemerial table that contains
** for each row to be changed:
**
**   (A)  The original rowid of that row.
**   (B)  The revised rowid for the row. (note1)
**   (C)  The content of every column in the row.
**
** Then we loop over this ephemeral table and for each row in
** the ephermeral table call VUpdate.
**
** When finished, drop the ephemeral table.
**
** (note1) Actually, if we know in advance that (A) is always the same
** as (B) we only store (A), then duplicate (A) when pulling
** it out of the ephemeral table before calling VUpdate.
*/
        static void updateVirtualTable(
            Parse pParse,      /* The parsing context */
            SrcList pSrc,      /* The virtual table to be modified */
            Table pTab,        /* The virtual table */
            ExprList pChanges, /* The columns to change in the UPDATE statement */
            Expr pRowid,       /* Expression used to recompute the rowid */
            int aXRef,         /* Mapping from columns of pTab to entries in pChanges */
            Expr pWhere        /* WHERE clause of the UPDATE statement */
            )
        {
            Vdbe        v       = pParse.pVdbe; /* Virtual machine under construction */
            ExprList    pEList  = 0;            /* The result set of the SELECT statement */
            Select      pSelect = 0;            /* The SELECT statement */
            Expr        pExpr;                  /* Temporary expression */
            int         ephemTab;               /* Table holding the result of the SELECT */
            int         i;                      /* Loop counter */
            int         addr;                   /* Address of top of loop */
            int         iReg;                   /* First register in set passed to OP_VUpdate */
            sqlite3     db    = pParse.db;      /* Database connection */
            const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
            SelectDest  dest;

/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
            pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_"));
            if (pRowid)
            {
                pEList = sqlite3ExprListAppend(pParse, pEList,
                                               sqlite3ExprDup(db, pRowid, 0), 0);
            }
            Debug.Assert(pTab.iPKey < 0);
            for (i = 0; i < pTab.nCol; i++)
            {
                if (aXRef[i] >= 0)
                {
                    pExpr = sqlite3ExprDup(db, pChanges.a[aXRef[i]].pExpr, 0);
                }
                else
                {
                    pExpr = sqlite3Expr(db, TK_ID, pTab.aCol[i].zName);
                }
                pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
            }
            pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);

/* Create the ephemeral table into which the update results will
** be stored.
*/
            Debug.Assert(v);
            ephemTab = pParse.nTab++;
            sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab.nCol + 1 + (pRowid != 0));
            sqlite3VdbeChangeP5(v, BTREE_UNORDERED);

/* fill the ephemeral table
 */
            sqlite3SelectDestInit(dest, SRT_Table, ephemTab);
            sqlite3Select(pParse, pSelect, ref dest);

/* Generate code to scan the ephemeral table and call VUpdate. */
            iReg         = ++pParse.nMem;
            pParse.nMem += pTab.nCol + 1;
            addr         = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
            sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg);
            sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid
                                                       1 : 0), iReg + 1);
            for (i = 0; i < pTab.nCol; i++)
            {
                sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i + 1 + (pRowid != 0), iReg + 2 + i);
            }
            sqlite3VtabMakeWritable(pParse, pTab);
            sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab.nCol + 2, iReg, pVTab, P4_VTAB);
            sqlite3MayAbort(pParse);
            sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr + 1);
            sqlite3VdbeJumpHere(v, addr);
            sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

/* Cleanup */
            sqlite3SelectDelete(pSelect);
        }
Example #7
0
 public static Select New(Parse parse, int dummy1, SrcList src, int dummy2, int dummy3, int dummy4, int dummy5, SF selFlags, int dummy6, int dummy7) { return New(parse, null, src, null, null, null, null, selFlags, null, null); }
Example #8
0
/*
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
** command.
*/
        static void sqlite3AlterRenameTable(
            Parse pParse,        /* Parser context. */
            SrcList pSrc,        /* The table to rename. */
            Token pName          /* The new table name. */
            )
        {
            int     iDb;               /* Database that contains the table */
            string  zDb;               /* Name of database iDb */
            Table   pTab;              /* Table being renamed */
            string  zName = null;      /* NULL-terminated version of pName */
            sqlite3 db    = pParse.db; /* Database connection */
            int     nTabName;          /* Number of UTF-8 characters in zTabName */
            string  zTabName;          /* Original name of the table */
            Vdbe    v;

#if !SQLITE_OMIT_TRIGGER
            string zWhere = "";  /* Where clause to locate temp triggers */
#endif
            VTable pVTab = null; /* Non-zero if this is a v-tab with an xRename() */
            int    savedDbFlags; /* Saved value of db->flags */

            savedDbFlags = db.flags;

            //if ( NEVER( db.mallocFailed != 0 ) ) goto exit_rename_table;
            Debug.Assert(pSrc.nSrc == 1);
            Debug.Assert(sqlite3BtreeHoldsAllMutexes(pParse.db));
            pTab = sqlite3LocateTable(pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase);
            if (pTab == null)
            {
                goto exit_rename_table;
            }
            iDb       = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);
            zDb       = db.aDb[iDb].zName;
            db.flags |= SQLITE_PreferBuiltin;

            /* Get a NULL terminated version of the new table name. */
            zName = sqlite3NameFromToken(db, pName);
            if (zName == null)
            {
                goto exit_rename_table;
            }

            /* Check that a table or index named 'zName' does not already exist
            ** in database iDb. If so, this is an error.
            */
            if (sqlite3FindTable(db, zName, zDb) != null || sqlite3FindIndex(db, zName, zDb) != null)
            {
                sqlite3ErrorMsg(pParse,
                                "there is already another table or index with this name: %s", zName);
                goto exit_rename_table;
            }

            /* Make sure it is not a system table being altered, or a reserved name
            ** that the table is being renamed to.
            */
            if (SQLITE_OK != isSystemTable(pParse, pTab.zName))
            {
                goto exit_rename_table;
            }
            if (SQLITE_OK != sqlite3CheckObjectName(pParse, zName))
            {
                goto exit_rename_table;
            }

#if !SQLITE_OMIT_VIEW
            if (pTab.pSelect != null)
            {
                sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab.zName);
                goto exit_rename_table;
            }
#endif

#if !SQLITE_OMIT_AUTHORIZATION
/* Invoke the authorization callback. */
            if (sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0))
            {
                goto exit_rename_table;
            }
#endif

            if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
            {
                goto exit_rename_table;
            }
#if !SQLITE_OMIT_VIRTUALTABLE
            if (IsVirtual(pTab))
            {
                pVTab = sqlite3GetVTable(db, pTab);
                if (pVTab.pVtab.pModule.xRename == null)
                {
                    pVTab = null;
                }
            }
#endif

            /* Begin a transaction and code the VerifyCookie for database iDb.
            ** Then modify the schema cookie (since the ALTER TABLE modifies the
            ** schema). Open a statement transaction if the table is a virtual
            ** table.
            */
            v = sqlite3GetVdbe(pParse);
            if (v == null)
            {
                goto exit_rename_table;
            }
            sqlite3BeginWriteOperation(pParse, pVTab != null ? 1 : 0, iDb);
            sqlite3ChangeCookie(pParse, iDb);

            /* If this is a virtual table, invoke the xRename() function if
            ** one is defined. The xRename() callback will modify the names
            ** of any resources used by the v-table implementation (including other
            ** SQLite tables) that are identified by the name of the virtual table.
            */
#if  !SQLITE_OMIT_VIRTUALTABLE
            if (pVTab != null)
            {
                int i = ++pParse.nMem;
                sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
                sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0, pVTab, P4_VTAB);
                sqlite3MayAbort(pParse);
            }
#endif

            /* figure out how many UTF-8 characters are in zName */
            zTabName = pTab.zName;
            nTabName = sqlite3Utf8CharLen(zTabName, -1);

#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
            if ((db.flags & SQLITE_ForeignKeys) != 0)
            {
                /* If foreign-key support is enabled, rewrite the CREATE TABLE
                ** statements corresponding to all child tables of foreign key constraints
                ** for which the renamed table is the parent table.  */
                if ((zWhere = whereForeignKeys(pParse, pTab)) != null)
                {
                    sqlite3NestedParse(pParse,
                                       "UPDATE \"%w\".%s SET " +
                                       "sql = sqlite_rename_parent(sql, %Q, %Q) " +
                                       "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
                    sqlite3DbFree(db, ref zWhere);
                }
            }
#endif

            /* Modify the sqlite_master table to use the new table name. */
            sqlite3NestedParse(pParse,
                               "UPDATE %Q.%s SET " +
#if SQLITE_OMIT_TRIGGER
                               "sql = sqlite_rename_table(sql, %Q), " +
#else
                               "sql = CASE " +
                               "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" +
                               "ELSE sqlite_rename_table(sql, %Q) END, " +
#endif
                               "tbl_name = %Q, " +
                               "name = CASE " +
                               "WHEN type='table' THEN %Q " +
                               "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " +
                               "'sqlite_autoindex_' || %Q || substr(name,%d+18) " +
                               "ELSE name END " +
                               "WHERE tbl_name=%Q AND " +
                               "(type='table' OR type='index' OR type='trigger');",
                               zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
#if !SQLITE_OMIT_TRIGGER
                               zName,
#endif
                               zName, nTabName, zTabName
                               );

#if !SQLITE_OMIT_AUTOINCREMENT
            /* If the sqlite_sequence table exists in this database, then update
            ** it with the new table name.
            */
            if (sqlite3FindTable(db, "sqlite_sequence", zDb) != null)
            {
                sqlite3NestedParse(pParse,
                                   "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
                                   zDb, zName, pTab.zName
                                   );
            }
#endif

#if !SQLITE_OMIT_TRIGGER
            /* If there are TEMP triggers on this table, modify the sqlite_temp_master
            ** table. Don't do this if the table being ALTERed is itself located in
            ** the temp database.
            */
            if ((zWhere = whereTempTriggers(pParse, pTab)) != "")
            {
                sqlite3NestedParse(pParse,
                                   "UPDATE sqlite_temp_master SET " +
                                   "sql = sqlite_rename_trigger(sql, %Q), " +
                                   "tbl_name = %Q " +
                                   "WHERE %s;", zName, zName, zWhere);
                sqlite3DbFree(db, ref zWhere);
            }
#endif

#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
            if ((db.flags & SQLITE_ForeignKeys) != 0)
            {
                FKey p;
                for (p = sqlite3FkReferences(pTab); p != null; p = p.pNextTo)
                {
                    Table pFrom = p.pFrom;
                    if (pFrom != pTab)
                    {
                        reloadTableSchema(pParse, p.pFrom, pFrom.zName);
                    }
                }
            }
#endif

            /* Drop and reload the internal table schema. */
            reloadTableSchema(pParse, pTab, zName);

exit_rename_table:
            sqlite3SrcListDelete(db, ref pSrc);
            sqlite3DbFree(db, ref zName);
            db.flags = savedDbFlags;
        }
Example #9
0
        /*
        ** Generate an expression tree to implement the WHERE, ORDER BY,
        ** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
        **
        **     DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
        **                            \__________________________/
        **                               pLimitWhere (pInClause)
        */
        Expr sqlite3LimitWhere(
            Parse pParse,               /* The parser context */
            SrcList pSrc,               /* the FROM clause -- which tables to scan */
            Expr pWhere,                /* The WHERE clause.  May be null */
            ExprList pOrderBy,          /* The ORDER BY clause.  May be null */
            Expr pLimit,                /* The LIMIT clause.  May be null */
            Expr pOffset,               /* The OFFSET clause.  May be null */
            char zStmtType              /* Either DELETE or UPDATE.  For error messages. */
            )
        {
            Expr pWhereRowid = null;    /* WHERE rowid .. */
            Expr pInClause = null;      /* WHERE rowid IN ( select ) */
            Expr pSelectRowid = null;   /* SELECT rowid ... */
            ExprList pEList = null;     /* Expression list contaning only pSelectRowid */
            SrcList pSelectSrc = null;  /* SELECT rowid FROM x ... (dup of pSrc) */
            Select pSelect = null;      /* Complete SELECT tree */

            /* Check that there isn't an ORDER BY without a LIMIT clause.
            */
            if( pOrderBy!=null && (pLimit == null) ) {
            sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
            pParse.parseError = 1;
            goto limit_where_cleanup_2;
            }

            /* We only need to generate a select expression if there
            ** is a limit/offset term to enforce.
            */
            if ( pLimit == null )
            {
            /* if pLimit is null, pOffset will always be null as well. */
            Debug.Assert( pOffset == null );
            return pWhere;
            }

            /* Generate a select expression tree to enforce the limit/offset
            ** term for the DELETE or UPDATE statement.  For example:
            **   DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
            ** becomes:
            **   DELETE FROM table_a WHERE rowid IN (
            **     SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
            **   );
            */

            pSelectRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
            if( pSelectRowid == null ) goto limit_where_cleanup_2;
            pEList = sqlite3ExprListAppend( pParse, null, pSelectRowid);
            if( pEList == null ) goto limit_where_cleanup_2;

            /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
            ** and the SELECT subtree. */
            pSelectSrc = sqlite3SrcListDup(pParse.db, pSrc,0);
            if( pSelectSrc == null ) {
            sqlite3ExprListDelete(pParse.db, pEList);
            goto limit_where_cleanup_2;
            }

            /* generate the SELECT expression tree. */
            pSelect = sqlite3SelectNew( pParse, pEList, pSelectSrc, pWhere, null, null,
            pOrderBy, 0, pLimit, pOffset );
            if( pSelect == null ) return null;

            /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
            pWhereRowid = sqlite3PExpr( pParse, TK_ROW, null, null, null );
            if( pWhereRowid == null ) goto limit_where_cleanup_1;
            pInClause = sqlite3PExpr( pParse, TK_IN, pWhereRowid, null, null );
            if( pInClause == null ) goto limit_where_cleanup_1;

            pInClause->x.pSelect = pSelect;
            pInClause->flags |= EP_xIsSelect;
            sqlite3ExprSetHeight(pParse, pInClause);
            return pInClause;

            /* something went wrong. clean up anything allocated. */
            limit_where_cleanup_1:
            sqlite3SelectDelete(pParse.db, pSelect);
            return null;

            limit_where_cleanup_2:
            sqlite3ExprDelete(pParse.db, ref pWhere);
            sqlite3ExprListDelete(pParse.db, pOrderBy);
            sqlite3ExprDelete(pParse.db, ref pLimit);
            sqlite3ExprDelete(pParse.db, ref pOffset);
            return null;
        }
Example #10
0
 static bool TableAndColumnIndex(SrcList src, int n, string colName, ref int tableOut, ref int colIdOut)
 {
     for (int i = 0; i < n; i++)
     {
         int colId = ColumnIndex(src.Ids[i].Table, colName); // Index of column matching zCol
         if (colId >= 0)
         {
             tableOut = i;
             colIdOut = colId;
             return true;
         }
     }
     return false;
 }
Example #11
0
        public Expr LimitWhere(Parse parse, SrcList src, Expr where_, ExprList orderBy, Expr limit, Expr offset, char stmtType)
        {
            // Check that there isn't an ORDER BY without a LIMIT clause.
            if (orderBy != null && (limit == null))
            {
                parse.ErrorMsg("ORDER BY without LIMIT on %s", stmtType);
                goto limit_where_cleanup_2;
            }

            // We only need to generate a select expression if there is a limit/offset term to enforce.
            if (limit == null)
            {
                Debug.Assert(offset == null); // if pLimit is null, pOffset will always be null as well.
                return where_;
            }

            // Generate a select expression tree to enforce the limit/offset term for the DELETE or UPDATE statement.  For example:
            //   DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
            // becomes:
            //   DELETE FROM table_a WHERE rowid IN ( 
            //     SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
            //   );
            Expr selectRowid = Expr.PExpr_(parse, TK.ROW, null, null, null); // SELECT rowid ...
            if (selectRowid == null) goto limit_where_cleanup_2;
            ExprList elist = ExprList.Append(parse, null, selectRowid); // Expression list contaning only pSelectRowid
            if (elist == null) goto limit_where_cleanup_2;

            // duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree and the SELECT subtree.
            SrcList selectSrc = SrcList.Dup(parse.Ctx, src, 0); // SELECT rowid FROM x ... (dup of pSrc)
            if (selectSrc == null)
            {
                ExprList.Delete(parse.Ctx, elist);
                goto limit_where_cleanup_2;
            }

            // generate the SELECT expression tree.
            Select select = Select.New(parse, elist, selectSrc, where_, null, null, orderBy, 0, limit, offset); // Complete SELECT tree
            if (select == null) return null;

            // now generate the new WHERE rowid IN clause for the DELETE/UDPATE
            Expr whereRowid = Expr.PExpr_(parse, TK.ROW, null, null, null); // WHERE rowid ..
            if (whereRowid == null) goto limit_where_cleanup_1;
            Expr inClause = Expr.PExpr_(parse, TK.IN, whereRowid, null, null); // WHERE rowid IN ( select )
            if (inClause == null) goto limit_where_cleanup_1;

            inClause.x.Select = select;
            inClause.Flags |= EP.xIsSelect;
            Expr.SetHeight(parse, inClause);
            return inClause;

        // something went wrong. clean up anything allocated.
        limit_where_cleanup_1:
            Select.Delete(parse.Ctx, select);
            return null;

        limit_where_cleanup_2:
            Expr.Delete(parse.Ctx, ref where_);
            ExprList.Delete(parse.Ctx, orderBy);
            Expr.Delete(parse.Ctx, ref limit);
            Expr.Delete(parse.Ctx, ref offset);
            return null;
        }
Example #12
0
        /*
        ** This is called by the parser when it sees a CREATE TRIGGER statement
        ** up to the point of the BEGIN before the trigger actions.  A Trigger
        ** structure is generated based on the information available and stored
        ** in pParse.pNewTrigger.  After the trigger actions have been parsed, the
        ** sqlite3FinishTrigger() function is called to complete the trigger
        ** construction process.
        */
        static void sqlite3BeginTrigger(
            Parse pParse,       /* The parse context of the CREATE TRIGGER statement */
            Token pName1,       /* The name of the trigger */
            Token pName2,       /* The name of the trigger */
            int tr_tm,          /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
            int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
            IdList pColumns,    /* column list if this is an UPDATE OF trigger */
            SrcList pTableName, /* The name of the table/view the trigger applies to */
            Expr pWhen,         /* WHEN clause */
            int isTemp,         /* True if the TEMPORARY keyword is present */
            int noErr           /* Suppress errors if the trigger already exists */
            )
        {
            Trigger pTrigger = null;       /* The new trigger */
            Table   pTab;                  /* Table that the trigger fires off of */
            string  zName = null;          /* Name of the trigger */
            sqlite3 db    = pParse.db;     /* The database connection */
            int     iDb;                   /* The database to store the trigger in */
            Token   pName = null;          /* The unqualified db name */
            DbFixer sFix  = new DbFixer(); /* State vector for the DB fixer */
            int     iTabDb;                /* Index of the database holding pTab */

            Debug.Assert(pName1 != null);  /* pName1.z might be NULL, but not pName1 itself */
            Debug.Assert(pName2 != null);
            Debug.Assert(op == TK_INSERT || op == TK_UPDATE || op == TK_DELETE);
            Debug.Assert(op > 0 && op < 0xff);
            if (isTemp != 0)
            {
                /* If TEMP was specified, then the trigger name may not be qualified. */
                if (pName2.n > 0)
                {
                    sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
                    goto trigger_cleanup;
                }
                iDb   = 1;
                pName = pName1;
            }
            else
            {
                /* Figure out the db that the the trigger will be created in */
                iDb = sqlite3TwoPartName(pParse, pName1, pName2, ref pName);
                if (iDb < 0)
                {
                    goto trigger_cleanup;
                }
            }

            /* If the trigger name was unqualified, and the table is a temp table,
            ** then set iDb to 1 to create the trigger in the temporary database.
            ** If sqlite3SrcListLookup() returns 0, indicating the table does not
            ** exist, the error is caught by the block below.
            */
            if (pTableName == null /*|| db.mallocFailed != 0 */)
            {
                goto trigger_cleanup;
            }
            pTab = sqlite3SrcListLookup(pParse, pTableName);
            if (pName2.n == 0 && pTab != null && pTab.pSchema == db.aDb[1].pSchema)
            {
                iDb = 1;
            }

            /* Ensure the table name matches database name and that the table exists */
//      if ( db.mallocFailed != 0 ) goto trigger_cleanup;
            Debug.Assert(pTableName.nSrc == 1);
            if (sqlite3FixInit(sFix, pParse, iDb, "trigger", pName) != 0 &&
                sqlite3FixSrcList(sFix, pTableName) != 0)
            {
                goto trigger_cleanup;
            }
            pTab = sqlite3SrcListLookup(pParse, pTableName);
            if (pTab == null)
            {
                /* The table does not exist. */
                if (db.init.iDb == 1)
                {
                    /* Ticket #3810.
                    ** Normally, whenever a table is dropped, all associated triggers are
                    ** dropped too.  But if a TEMP trigger is created on a non-TEMP table
                    ** and the table is dropped by a different database connection, the
                    ** trigger is not visible to the database connection that does the
                    ** drop so the trigger cannot be dropped.  This results in an
                    ** "orphaned trigger" - a trigger whose associated table is missing.
                    */
                    db.init.orphanTrigger = 1;
                }
                goto trigger_cleanup;
            }
            if (IsVirtual(pTab))
            {
                sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
                goto trigger_cleanup;
            }

            /* Check that the trigger name is not reserved and that no trigger of the
            ** specified name exists */
            zName = sqlite3NameFromToken(db, pName);
            if (zName == null || SQLITE_OK != sqlite3CheckObjectName(pParse, zName))
            {
                goto trigger_cleanup;
            }
            if (sqlite3HashFind((db.aDb[iDb].pSchema.trigHash),
                                zName, sqlite3Strlen30(zName)) != null)
            {
                if (noErr == 0)
                {
                    sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
                }
                goto trigger_cleanup;
            }

            /* Do not create a trigger on a system table */
            if (sqlite3StrNICmp(pTab.zName, "sqlite_", 7) == 0)
            {
                sqlite3ErrorMsg(pParse, "cannot create trigger on system table");
                pParse.nErr++;
                goto trigger_cleanup;
            }

            /* INSTEAD of triggers are only for views and views only support INSTEAD
            ** of triggers.
            */
            if (pTab.pSelect != null && tr_tm != TK_INSTEAD)
            {
                sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
                                (tr_tm == TK_BEFORE) ? "BEFORE" : "AFTER", pTableName, 0);
                goto trigger_cleanup;
            }
            if (pTab.pSelect == null && tr_tm == TK_INSTEAD)
            {
                sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" +
                                " trigger on table: %S", pTableName, 0);
                goto trigger_cleanup;
            }
            iTabDb = sqlite3SchemaToIndex(db, pTab.pSchema);

#if !SQLITE_OMIT_AUTHORIZATION
            {
                int    code    = SQLITE_CREATE_TRIGGER;
                string zDb     = db.aDb[iTabDb].zName;
                string zDbTrig = isTemp ? db.aDb[1].zName : zDb;
                if (iTabDb == 1 || isTemp)
                {
                    code = SQLITE_CREATE_TEMP_TRIGGER;
                }
                if (sqlite3AuthCheck(pParse, code, zName, pTab.zName, zDbTrig))
                {
                    goto trigger_cleanup;
                }
                if (sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb), 0, zDb))
                {
                    goto trigger_cleanup;
                }
            }
#endif

            /* INSTEAD OF triggers can only appear on views and BEFORE triggers
            ** cannot appear on views.  So we might as well translate every
            ** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
            ** elsewhere.
            */
            if (tr_tm == TK_INSTEAD)
            {
                tr_tm = TK_BEFORE;
            }

            /* Build the Trigger object */
            pTrigger = new Trigger();// (Trigger*)sqlite3DbMallocZero( db, sizeof(Trigger ))
            if (pTrigger == null)
            {
                goto trigger_cleanup;
            }
            pTrigger.name       = zName;
            pTrigger.table      = pTableName.a[0].zName;// sqlite3DbStrDup( db, pTableName.a[0].zName );
            pTrigger.pSchema    = db.aDb[iDb].pSchema;
            pTrigger.pTabSchema = pTab.pSchema;
            pTrigger.op         = (u8)op;
            pTrigger.tr_tm      = tr_tm == TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
            pTrigger.pWhen      = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
            pTrigger.pColumns   = sqlite3IdListDup(db, pColumns);
            Debug.Assert(pParse.pNewTrigger == null);
            pParse.pNewTrigger = pTrigger;

trigger_cleanup:
            //sqlite3DbFree( db, ref zName );
            sqlite3SrcListDelete(db, ref pTableName);
            sqlite3IdListDelete(db, ref pColumns);
            sqlite3ExprDelete(db, ref pWhen);
            if (pParse.pNewTrigger == null)
            {
                sqlite3DeleteTrigger(db, ref pTrigger);
            }
            else
            {
                Debug.Assert(pParse.pNewTrigger == pTrigger);
            }
        }
Example #13
0
        /*
        ** Generate code for a DELETE FROM statement.
        **
        **     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
        **                 \________/       \________________/
        **                  pTabList              pWhere
        */
        static void sqlite3DeleteFrom(
            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 */
            string      zDb;           /* Name of database holding pTab */
            int         end, addr = 0; /* 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 VdbeCursor number for pTab */
            sqlite3     db;            /* Main database structure */
            AuthContext sContext;      /* Authorization context */
            NameContext sNC;           /* Name context to resolve expressions in */
            int         iDb;           /* Database number */
            int         memCnt = -1;   /* Memory cell used for change counting */
            int         rcauth;        /* Value returned by authorization callback */

#if !SQLITE_OMIT_TRIGGER
            bool    isView;               /* True if attempting to delete from a view */
            Trigger pTrigger;             /* List of table triggers, if required */
#endif
            sContext = new AuthContext(); //memset(&sContext, 0, sizeof(sContext));

            db = pParse.db;
            if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */)
            {
                goto delete_from_cleanup;
            }
            Debug.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 = sqlite3SrcListLookup(pParse, pTabList);
            if (pTab == null)
            {
                goto delete_from_cleanup;
            }

            /* Figure out if we have any triggers and if the table being
            ** deleted from is a view
            */
#if !SQLITE_OMIT_TRIGGER
            int iDummy = 0;
            pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, null, ref iDummy);
            isView   = pTab.pSelect != null;
#else
            const Trigger pTrigger = null;
            bool          isView   = false;
#endif
#if SQLITE_OMIT_VIEW
//# undef isView
            isView = false;
#endif

            /* If pTab is really a view, make sure it has been initialized.
             */
            if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
            {
                goto delete_from_cleanup;
            }

            if (sqlite3IsReadOnly(pParse, pTab, (pTrigger != null ? 1 : 0)))
            {
                goto delete_from_cleanup;
            }
            iDb = sqlite3SchemaToIndex(db, pTab.pSchema);
            Debug.Assert(iDb < db.nDb);
            zDb = db.aDb[iDb].zName;
#if !SQLITE_OMIT_AUTHORIZATION
            rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
#else
            rcauth = SQLITE_OK;
#endif
            Debug.Assert(rcauth == SQLITE_OK || rcauth == SQLITE_DENY || rcauth == SQLITE_IGNORE);
            if (rcauth == SQLITE_DENY)
            {
                goto delete_from_cleanup;
            }
            Debug.Assert(!isView || pTrigger != null);

            /* Assign  cursor number to the table and all its indices.
             */
            Debug.Assert(pTabList.nSrc == 1);
            iCur = pTabList.a[0].iCursor = pParse.nTab++;
            for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
            {
                pParse.nTab++;
            }

#if !SQLITE_OMIT_AUTHORIZATION
/* Start the view context
 */
            if (isView)
            {
                sqlite3AuthContextPush(pParse, sContext, pTab.zName);
            }
#endif

            /* Begin generating code.
             */
            v = sqlite3GetVdbe(pParse);
            if (v == null)
            {
                goto delete_from_cleanup;
            }
            if (pParse.nested == 0)
            {
                sqlite3VdbeCountChanges(v);
            }
            sqlite3BeginWriteOperation(pParse, 1, iDb);

            /* If we are trying to delete from a view, realize that view into
            ** a ephemeral table.
            */
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
            if (isView)
            {
                sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
            }
#endif

            /* Resolve the column names in the WHERE clause.
             */
            sNC          = new NameContext();// memset( &sNC, 0, sizeof( sNC ) );
            sNC.pParse   = pParse;
            sNC.pSrcList = pTabList;
            if (sqlite3ResolveExprNames(sNC, ref pWhere) != 0)
            {
                goto delete_from_cleanup;
            }


            /* Initialize the counter of the number of rows deleted, if
            ** we are counting rows.
            */
            if ((db.flags & SQLITE_CountRows) != 0)
            {
                memCnt = ++pParse.nMem;
                sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
            }

#if !SQLITE_OMIT_TRUNCATE_OPTIMIZATION
            /* Special case: A DELETE without a WHERE clause deletes everything.
            ** It is easier just to erase the whole table. Prior to version 3.6.5,
            ** this optimization caused the row change count (the value returned by
            ** API function sqlite3_count_changes) to be set incorrectly.  */
            if (rcauth == SQLITE_OK && pWhere == null && null == pTrigger && !IsVirtual(pTab) &&
                0 == sqlite3FkRequired(pParse, pTab, null, 0)
                )
            {
                Debug.Assert(!isView);
                sqlite3VdbeAddOp4(v, OP_Clear, pTab.tnum, iDb, memCnt,
                                  pTab.zName, P4_STATIC);
                for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
                {
                    Debug.Assert(pIdx.pSchema == pTab.pSchema);
                    sqlite3VdbeAddOp2(v, OP_Clear, pIdx.tnum, iDb);
                }
            }
            else
#endif //* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */

            /* The usual case: There is a WHERE clause so we have to scan through
            ** the table and pick which records to delete.
            */
            {
                int iRowSet = ++pParse.nMem; /* Register for rowset of rows to delete */
                int iRowid  = ++pParse.nMem; /* Used for storing rowid values. */
                int regRowid;                /* Actual register containing rowids */

                /* Collect rowids of every row to be deleted.
                 */
                sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
                ExprList elDummy = null;
                pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, ref elDummy, WHERE_DUPLICATES_OK);
                if (pWInfo == null)
                {
                    goto delete_from_cleanup;
                }
                regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid);
                sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
                if ((db.flags & SQLITE_CountRows) != 0)
                {
                    sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
                }

                sqlite3WhereEnd(pWInfo);

                /* 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. */
                end = sqlite3VdbeMakeLabel(v);

                /* Unless this is a view, open cursors for the table we are
                ** deleting from and all its indices. If this is a view, then the
                ** only effect this statement has is to fire the INSTEAD OF
                ** triggers.  */
                if (!isView)
                {
                    sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
                }

                addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);

                /* Delete the row */
#if !SQLITE_OMIT_VIRTUALTABLE
                if (IsVirtual(pTab))
                {
                    const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
                    sqlite3VtabMakeWritable(pParse, pTab);
                    sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
                    sqlite3MayAbort(pParse);
                }
                else
#endif
                {
                    int count = (pParse.nested == 0) ? 1 : 0; /* True to count changes */
                    sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, count, pTrigger, OE_Default);
                }

                /* End of the delete loop */
                sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
                sqlite3VdbeResolveLabel(v, end);

                /* Close the cursors open on the table and its indexes. */
                if (!isView && !IsVirtual(pTab))
                {
                    for (i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext)
                    {
                        sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx.tnum);
                    }
                    sqlite3VdbeAddOp1(v, OP_Close, iCur);
                }
            }

            /* Update the sqlite_sequence table by storing the content of the
            ** maximum rowid counter values recorded while inserting into
            ** autoincrement tables.
            */
            if (pParse.nested == 0 && pParse.pTriggerTab == null)
            {
                sqlite3AutoincrementEnd(pParse);
            }

            /* Return the number of rows that were deleted. If this routine is
            ** generating code because of a call to sqlite3NestedParse(), do not
            ** invoke the callback function.
            */

            if ((db.flags & SQLITE_CountRows) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab)
            {
                sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
                sqlite3VdbeSetNumCols(v, 1);
                sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
            }

delete_from_cleanup:
#if !SQLITE_OMIT_AUTHORIZATION
            sqlite3AuthContextPop(sContext);
#endif
            sqlite3SrcListDelete(db, ref pTabList);
            sqlite3ExprDelete(db, ref pWhere);
            return;
        }
Example #14
0
        public static void DeleteFrom(Parse parse, SrcList tabList, Expr where_)
        {
            AuthContext sContext = new AuthContext(); // Authorization context
            Context ctx = parse.Ctx; // Main database structure
            if (parse.Errs != 0 || ctx.MallocFailed)
                goto delete_from_cleanup;
            Debug.Assert(tabList.Srcs == 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.
            Table table = SrcList.Lookup(parse, tabList); // The table from which records will be deleted
            if (table == null) goto delete_from_cleanup;

            // Figure out if we have any triggers and if the table being deleted from is a view
#if !OMIT_TRIGGER
            int dummy;
            Trigger trigger = Triggers.Exist(parse, table, TK.DELETE, null, out dummy); // List of table triggers, if required
#if OMIT_VIEW
            const bool isView = false;
#else
            bool isView = (table.Select != null); // True if attempting to delete from a view
#endif
#else
            const Trigger trigger = null;
            bool isView = false;
#endif

            // If pTab is really a view, make sure it has been initialized.
            if (sqlite3ViewGetColumnNames(parse, table) != null || IsReadOnly(parse, table, (trigger != null)))
                goto delete_from_cleanup;
            int db = sqlite3SchemaToIndex(ctx, table.Schema); // Database number
            Debug.Assert(db < ctx.DBs.length);
            string dbName = ctx.DBs[db].Name; // Name of database holding pTab
            ARC rcauth = Auth.Check(parse, AUTH.DELETE, table.Name, 0, dbName); // Value returned by authorization callback
            Debug.Assert(rcauth == ARC.OK || rcauth == ARC.DENY || rcauth == ARC.IGNORE);
            if (rcauth == ARC.DENY)
                goto delete_from_cleanup;
            Debug.Assert(!isView || trigger != null);

            // Assign cursor number to the table and all its indices.
            Debug.Assert(tabList.Srcs == 1);
            int curId = tabList.Ids[0].Cursor = parse.Tabs++; // VDBE VdbeCursor number for pTab
            Index idx; // For looping over indices of the table
            for (idx = table.Index; idx != null; idx = idx.Next)
                parse.Tabs++;

            // Start the view context
            if (isView)
                Auth.ContextPush(parse, sContext, table.Name);

            // Begin generating code.
            Vdbe v = parse.GetVdbe(); // The virtual database engine 
            if (v == null)
                goto delete_from_cleanup;
            if (parse.Nested == 0) v.CountChanges();
            parse.BeginWriteOperation(1, db);

            // If we are trying to delete from a view, realize that view into a ephemeral table.
#if !OMIT_VIEW && !OMIT_TRIGGER
            if (isView)
                MaterializeView(parse, table, where_, curId);
#endif
            // Resolve the column names in the WHERE clause.
            NameContext sNC = new NameContext(); // Name context to resolve expressions in
            sNC.Parse = parse;
            sNC.SrcList = tabList;
            if (sqlite3ResolveExprNames(sNC, ref where_) != 0)
                goto delete_from_cleanup;

            // Initialize the counter of the number of rows deleted, if we are counting rows.
            int memCnt = -1; // Memory cell used for change counting
            if ((ctx.Flags & Context.FLAG.CountRows) != 0)
            {
                memCnt = ++parse.Mems;
                v.AddOp2(OP.Integer, 0, memCnt);
            }

#if !OMIT_TRUNCATE_OPTIMIZATION
            // Special case: A DELETE without a WHERE clause deletes everything. It is easier just to erase the whole table. Prior to version 3.6.5,
            // this optimization caused the row change count (the value returned by API function sqlite3_count_changes) to be set incorrectly.
            if (rcauth == ARC.OK && where_ == null && trigger == null && !IsVirtual(table) && !FKey.FkRequired(parse, table, null, 0))
            {
                Debug.Assert(!isView);
                v.AddOp4(OP.Clear, table.Id, db, memCnt, table.Name, Vdbe.P4T.STATIC);
                for (idx = table.Index; idx != null; idx = idx.Next)
                {
                    Debug.Assert(idx.Schema == table.Schema);
                    v.AddOp2(OP.Clear, idx.Id, db);
                }
            }
            else
#endif
            // The usual case: There is a WHERE clause so we have to scan through the table and pick which records to delete.
            {
                int rowSet = ++parse.Mems; // Register for rowset of rows to delete
                int rowid = ++parse.Mems; // Used for storing rowid values.

                // Collect rowids of every row to be deleted.
                v.AddOp2(OP.Null, 0, rowSet);
                ExprList dummy = null;
                WhereInfo winfo = Where.Begin(parse, tabList, where_, ref dummy, WHERE_DUPLICATES_OK, 0); // Information about the WHERE clause
                if (winfo == null) goto delete_from_cleanup;
                int regRowid = Expr.CodeGetColumn(parse, table, -1, curId, rowid); // Actual register containing rowids
                v.AddOp2(OP.RowSetAdd, rowSet, regRowid);
                if ((ctx.Flags & Context.FLAG.CountRows) != 0)
                    v.AddOp2(OP.AddImm, memCnt, 1);
                Where.End(winfo);

                // 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.
                int end = v.MakeLabel();

                // Unless this is a view, open cursors for the table we are deleting from and all its indices. If this is a view, then the
                // only effect this statement has is to fire the INSTEAD OF triggers.
                if (!isView)
                    sqlite3OpenTableAndIndices(parse, table, curId, OP.OpenWrite);
                int addr = v.AddOp3(OP.RowSetRead, rowSet, end, rowid);

                // Delete the row
#if !OMIT_VIRTUALTABLE
                if (IsVirtual(table))
                {
                    VTable vtable = VTable.GetVTable(ctx, table);
                    VTable.MakeWritable(parse, table);
                    v.AddOp4(OP.VUpdate, 0, 1, rowid, vtable, Vdbe.P4T.VTAB);
                    v.ChangeP5(OE.Abort);
                    sqlite3MayAbort(parse);
                }
                else
#endif
                {
                    int count = (parse.Nested == 0; // True to count changes
                    GenerateRowDelete(parse, table, curId, rowid, count, trigger, OE.Default);
                }

                // End of the delete loop
                v.AddOp2(OP.Goto, 0, addr);
                v.ResolveLabel(end);

                // Close the cursors open on the table and its indexes.
                if (!isView && !IsVirtual(table))
                {
                    for (int i = 1, idx = table.Index; idx != null; i++, idx = idx.Next)
                        v.AddOp2(OP.Close, curId + i, idx.Id);
                    v.AddOp1(OP.Close, curId);
                }
            }

            // Update the sqlite_sequence table by storing the content of the maximum rowid counter values recorded while inserting into
		    // autoincrement tables.
            if (parse.Nested == 0 && parse.TriggerTab == null)
                sqlite3AutoincrementEnd(parse);

            // Return the number of rows that were deleted. If this routine is generating code because of a call to sqlite3NestedParse(), do not
		    // invoke the callback function.
            if ((ctx.Flags & Context.FLAG.CountRows) != 0 && parse.Nested == 0 && parse.TriggerTab == null)
            {
                v.AddOp2(OP.ResultRow, memCnt, 1);
                v.SetNumCols(1);
                v.SetColName(0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
            }

        delete_from_cleanup:
            Auth.ContextPop(sContext);
            SrcList.Delete(ctx, ref tabList);
            Expr.Delete(ctx, ref where_);
            return;
        }
Example #15
0
/*
** Generate an expression tree to implement the WHERE, ORDER BY,
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
**
**     DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
**                            \__________________________/
**                               pLimitWhere (pInClause)
*/
        Expr sqlite3LimitWhere(
            Parse pParse,      /* The parser context */
            SrcList pSrc,      /* the FROM clause -- which tables to scan */
            Expr pWhere,       /* The WHERE clause.  May be null */
            ExprList pOrderBy, /* The ORDER BY clause.  May be null */
            Expr pLimit,       /* The LIMIT clause.  May be null */
            Expr pOffset,      /* The OFFSET clause.  May be null */
            char zStmtType     /* Either DELETE or UPDATE.  For error messages. */
            )
        {
            Expr     pWhereRowid  = null; /* WHERE rowid .. */
            Expr     pInClause    = null; /* WHERE rowid IN ( select ) */
            Expr     pSelectRowid = null; /* SELECT rowid ... */
            ExprList pEList       = null; /* Expression list contaning only pSelectRowid */
            SrcList  pSelectSrc   = null; /* SELECT rowid FROM x ... (dup of pSrc) */
            Select   pSelect      = null; /* Complete SELECT tree */

/* Check that there isn't an ORDER BY without a LIMIT clause.
 */

            if (pOrderBy != null && (pLimit == null))
            {
                sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
                pParse.parseError = 1;
                goto limit_where_cleanup_2;
            }

/* We only need to generate a select expression if there
** is a limit/offset term to enforce.
*/
            if (pLimit == null)
            {
/* if pLimit is null, pOffset will always be null as well. */
                Debug.Assert(pOffset == null);
                return(pWhere);
            }

/* Generate a select expression tree to enforce the limit/offset
** term for the DELETE or UPDATE statement.  For example:
**   DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
** becomes:
**   DELETE FROM table_a WHERE rowid IN (
**     SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
**   );
*/

            pSelectRowid = sqlite3PExpr(pParse, TK_ROW, null, null, null);
            if (pSelectRowid == null)
            {
                goto limit_where_cleanup_2;
            }
            pEList = sqlite3ExprListAppend(pParse, null, pSelectRowid);
            if (pEList == null)
            {
                goto limit_where_cleanup_2;
            }

/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
            pSelectSrc = sqlite3SrcListDup(pParse.db, pSrc, 0);
            if (pSelectSrc == null)
            {
                sqlite3ExprListDelete(pParse.db, pEList);
                goto limit_where_cleanup_2;
            }

/* generate the SELECT expression tree. */
            pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, null, null,
                                       pOrderBy, 0, pLimit, pOffset);
            if (pSelect == null)
            {
                return(null);
            }

/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
            pWhereRowid = sqlite3PExpr(pParse, TK_ROW, null, null, null);
            if (pWhereRowid == null)
            {
                goto limit_where_cleanup_1;
            }
            pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, null, null);
            if (pInClause == null)
            {
                goto limit_where_cleanup_1;
            }

            pInClause->x.pSelect = pSelect;
            pInClause->flags    |= EP_xIsSelect;
            sqlite3ExprSetHeight(pParse, pInClause);
            return(pInClause);

/* something went wrong. clean up anything allocated. */
limit_where_cleanup_1:
            sqlite3SelectDelete(pParse.db, pSelect);
            return(null);

limit_where_cleanup_2:
            sqlite3ExprDelete(pParse.db, ref pWhere);
            sqlite3ExprListDelete(pParse.db, pOrderBy);
            sqlite3ExprDelete(pParse.db, ref pLimit);
            sqlite3ExprDelete(pParse.db, ref pOffset);
            return(null);
        }
Example #16
0
 static SrcList va_arg(object[] ap, SrcList sysType)
 {
     return((SrcList)ap[vaNEXT++]);
 }
Example #17
0
/*
** This function is called by the parser after the table-name in
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
** pSrc is the full-name of the table being altered.
**
** This routine makes a (partial) copy of the Table structure
** for the table being altered and sets Parse.pNewTable to point
** to it. Routines called by the parser as the column definition
** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
** the copy. The copy of the Table structure is deleted by tokenize.c
** after parsing is finished.
**
** Routine sqlite3AlterFinishAddColumn() will be called to complete
** coding the "ALTER TABLE ... ADD" statement.
*/
        static void sqlite3AlterBeginAddColumn(Parse pParse, SrcList pSrc)
        {
            Table   pNew;
            Table   pTab;
            Vdbe    v;
            int     iDb;
            int     i;
            int     nAlloc;
            sqlite3 db = pParse.db;

            /* Look up the table being altered. */
            Debug.Assert(pParse.pNewTable == null);
            Debug.Assert(sqlite3BtreeHoldsAllMutexes(db));
            //	  if ( db.mallocFailed != 0 ) goto exit_begin_add_column;
            pTab = sqlite3LocateTable(pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase);
            if (pTab == null)
            {
                goto exit_begin_add_column;
            }

            if (IsVirtual(pTab))
            {
                sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
                goto exit_begin_add_column;
            }

            /* Make sure this is not an attempt to ALTER a view. */
            if (pTab.pSelect != null)
            {
                sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
                goto exit_begin_add_column;
            }
            if (SQLITE_OK != isSystemTable(pParse, pTab.zName))
            {
                goto exit_begin_add_column;
            }

            Debug.Assert(pTab.addColOffset > 0);
            iDb = sqlite3SchemaToIndex(db, pTab.pSchema);

            /* Put a copy of the Table struct in Parse.pNewTable for the
            ** sqlite3AddColumn() function and friends to modify.  But modify
            ** the name by adding an "sqlite_altertab_" prefix.  By adding this
            ** prefix, we insure that the name will not collide with an existing
            ** table because user table are not allowed to have the "sqlite_"
            ** prefix on their name.
            */
            pNew = new Table();// (Table*)sqlite3DbMallocZero( db, sizeof(Table))
            if (pNew == null)
            {
                goto exit_begin_add_column;
            }
            pParse.pNewTable = pNew;
            pNew.nRef        = 1;
            pNew.nCol        = pTab.nCol;
            Debug.Assert(pNew.nCol > 0);
            nAlloc = (((pNew.nCol - 1) / 8) * 8) + 8;
            Debug.Assert(nAlloc >= pNew.nCol && nAlloc % 8 == 0 && nAlloc - pNew.nCol < 8);
            pNew.aCol  = new Column[nAlloc];// (Column*)sqlite3DbMallocZero( db, sizeof(Column) * nAlloc );
            pNew.zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab.zName);
            if (pNew.aCol == null || pNew.zName == null)
            {
                //		db.mallocFailed = 1;
                goto exit_begin_add_column;
            }
            // memcpy( pNew.aCol, pTab.aCol, sizeof(Column) * pNew.nCol );
            for (i = 0; i < pNew.nCol; i++)
            {
                Column pCol = pTab.aCol[i].Copy();
                // sqlite3DbStrDup( db, pCol.zName );
                pCol.zColl   = null;
                pCol.zType   = null;
                pCol.pDflt   = null;
                pCol.zDflt   = null;
                pNew.aCol[i] = pCol;
            }
            pNew.pSchema      = db.aDb[iDb].pSchema;
            pNew.addColOffset = pTab.addColOffset;
            pNew.nRef         = 1;

            /* Begin a transaction and increment the schema cookie.  */
            sqlite3BeginWriteOperation(pParse, 0, iDb);
            v = sqlite3GetVdbe(pParse);
            if (v == null)
            {
                goto exit_begin_add_column;
            }
            sqlite3ChangeCookie(pParse, iDb);

exit_begin_add_column:
            sqlite3SrcListDelete(db, ref pSrc);
            return;
        }
Example #18
0
    /*
    ** This function is called to drop a trigger from the database schema.
    **
    ** This may be called directly from the parser and therefore identifies
    ** the trigger by name.  The sqlite3DropTriggerPtr() routine does the
    ** same job as this routine except it takes a pointer to the trigger
    ** instead of the trigger name.
    **/
    static void sqlite3DropTrigger( Parse pParse, SrcList pName, int noErr )
    {
      Trigger pTrigger = null;
      int i;
      string zDb;
      string zName;
      int nName;
      sqlite3 db = pParse.db;

      //      if ( db.mallocFailed != 0 ) goto drop_trigger_cleanup;
      if ( SQLITE_OK != sqlite3ReadSchema( pParse ) )
      {
        goto drop_trigger_cleanup;
      }

      Debug.Assert( pName.nSrc == 1 );
      zDb = pName.a[0].zDatabase;
      zName = pName.a[0].zName;
      nName = sqlite3Strlen30( zName );
      Debug.Assert( zDb != null || sqlite3BtreeHoldsAllMutexes( db ) );
      for ( i = OMIT_TEMPDB; i < db.nDb; i++ )
      {
        int j = ( i < 2 ) ? i ^ 1 : i;  /* Search TEMP before MAIN */
        if ( zDb != null && !db.aDb[j].zName.Equals( zDb ,StringComparison.InvariantCultureIgnoreCase )  )
          continue;
        Debug.Assert( sqlite3SchemaMutexHeld( db, j, null ) );
        pTrigger = sqlite3HashFind( ( db.aDb[j].pSchema.trigHash ), zName, nName, (Trigger)null );
        if ( pTrigger != null )
          break;
      }
      if ( pTrigger == null )
      {
        if ( noErr == 0 )
        {
          sqlite3ErrorMsg( pParse, "no such trigger: %S", pName, 0 );
        }
        else
        {
          sqlite3CodeVerifyNamedSchema( pParse, zDb );
        }
        pParse.checkSchema = 1;
        goto drop_trigger_cleanup;
      }
      sqlite3DropTriggerPtr( pParse, pTrigger );

drop_trigger_cleanup:
      sqlite3SrcListDelete( db, ref pName );
    }
Example #19
0
        /*
        ** Process an UPDATE statement.
        **
        **   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
        **          \_______/ \________/     \______/       \________________/
        *            onError   pTabList      pChanges             pWhere
        */

        private static void sqlite3Update(
            Parse pParse,             /* The parser context */
            SrcList pTabList,         /* The table in which we should change things */
            ExprList pChanges,        /* Things to be changed */
            Expr pWhere,              /* The WHERE clause.  May be null */
            int onError               /* How to handle constraint errors */
            )
        {
            int       i, j;                         /* Loop counters */
            Table     pTab;                         /* The table to be updated */
            int       addr = 0;                     /* VDBE instruction address of the start of the loop */
            WhereInfo pWInfo;                       /* Information about the WHERE clause */
            Vdbe      v;                            /* The virtual database engine */
            Index     pIdx;                         /* For looping over indices */
            int       nIdx;                         /* Number of indices that need updating */
            int       iCur;                         /* VDBE Cursor number of pTab */
            sqlite3   db;                           /* The database structure */

            int[] aRegIdx = null;                   /* One register assigned to each index to be updated */
            int[] aXRef   = null;                   /* aXRef[i] is the index in pChanges.a[] of the
                                                    ** an expression for the i-th column of the table.
                                                    ** aXRef[i]==-1 if the i-th column is not changed. */
            bool        chngRowid;                  /* True if the record number is being changed */
            Expr        pRowidExpr = null;          /* Expression defining the new record number */
            bool        openAll    = false;         /* True if all indices need to be opened */
            AuthContext sContext;                   /* The authorization context */
            NameContext sNC;                        /* The name-context to resolve expressions in */
            int         iDb;                        /* Database containing the table being updated */
            bool        okOnePass;                  /* True for one-pass algorithm without the FIFO */
            bool        hasFK;                      /* True if foreign key processing is required */

#if !SQLITE_OMIT_TRIGGER
            bool    isView;                    /* True when updating a view (INSTEAD OF trigger) */
            Trigger pTrigger;                  /* List of triggers on pTab, if required */
            int     tmask = 0;                 /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
#endif
            int newmask;                       /* Mask of NEW.* columns accessed by BEFORE triggers */

            /* Register Allocations */
            int regRowCount = 0;                     /* A count of rows changed */
            int regOldRowid;                         /* The old rowid */
            int regNewRowid;                         /* The new rowid */
            int regNew;
            int regOld    = 0;
            int regRowSet = 0;                       /* Rowset of rows to be updated */

            sContext = new AuthContext();            //memset( &sContext, 0, sizeof( sContext ) );
            db       = pParse.db;
            if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */)
            {
                goto update_cleanup;
            }
            Debug.Assert(pTabList.nSrc == 1);

            /* Locate the table which we want to update.
             */
            pTab = sqlite3SrcListLookup(pParse, pTabList);
            if (pTab == null)
            {
                goto update_cleanup;
            }
            iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);

            /* Figure out if we have any triggers and if the table being
            ** updated is a view.
            */
#if !SQLITE_OMIT_TRIGGER
            pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, out tmask);
            isView   = pTab.pSelect != null;
            Debug.Assert(pTrigger != null || tmask == 0);
#else
            const Trigger pTrigger = null; //# define pTrigger 0
            const int     tmask    = 0;    //# define tmask 0
#endif
#if SQLITE_OMIT_TRIGGER || SQLITE_OMIT_VIEW
//    # undef isView
            const bool isView = false; //# define isView 0
#endif

            if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
            {
                goto update_cleanup;
            }
            if (sqlite3IsReadOnly(pParse, pTab, tmask))
            {
                goto update_cleanup;
            }
            aXRef = new int[pTab.nCol];            // sqlite3DbMallocRaw(db, sizeof(int) * pTab.nCol);
            //if ( aXRef == null ) goto update_cleanup;
            for (i = 0; i < pTab.nCol; i++)
            {
                aXRef[i] = -1;
            }

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

            /* Initialize the name-context */
            sNC          = new NameContext();   // memset(&sNC, 0, sNC).Length;
            sNC.pParse   = pParse;
            sNC.pSrcList = pTabList;

            /* Resolve the column names in all the expressions of the
            ** of the UPDATE statement.  Also find the column index
            ** for each column to be updated in the pChanges array.  For each
            ** column to be updated, make sure we have authorization to change
            ** that column.
            */
            chngRowid = false;
            for (i = 0; i < pChanges.nExpr; i++)
            {
                if (sqlite3ResolveExprNames(sNC, ref pChanges.a[i].pExpr) != 0)
                {
                    goto update_cleanup;
                }
                for (j = 0; j < pTab.nCol; j++)
                {
                    if (pTab.aCol[j].zName.Equals(pChanges.a[i].zName, StringComparison.OrdinalIgnoreCase))
                    {
                        if (j == pTab.iPKey)
                        {
                            chngRowid  = true;
                            pRowidExpr = pChanges.a[i].pExpr;
                        }
                        aXRef[j] = i;
                        break;
                    }
                }
                if (j >= pTab.nCol)
                {
                    if (sqlite3IsRowid(pChanges.a[i].zName))
                    {
                        chngRowid  = true;
                        pRowidExpr = pChanges.a[i].pExpr;
                    }
                    else
                    {
                        sqlite3ErrorMsg(pParse, "no such column: %s", pChanges.a[i].zName);
                        pParse.checkSchema = 1;
                        goto update_cleanup;
                    }
                }
#if !SQLITE_OMIT_AUTHORIZATION
                {
                    int rc;
                    rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab.zName,
                                          pTab.aCol[j].zName, db.aDb[iDb].zName);
                    if (rc == SQLITE_DENY)
                    {
                        goto update_cleanup;
                    }
                    else if (rc == SQLITE_IGNORE)
                    {
                        aXRef[j] = -1;
                    }
                }
#endif
            }

            hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngRowid ? 1 : 0) != 0;

            /* Allocate memory for the array aRegIdx[].  There is one entry in the
            ** array for each index associated with table being updated.  Fill in
            ** the value with a register number for indices that are to be used
            ** and with zero for unused indices.
            */
            for (nIdx = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, nIdx++)
            {
            }
            if (nIdx > 0)
            {
                aRegIdx = new int[nIdx];                 // sqlite3DbMallocRaw(db, Index*.Length * nIdx);
                if (aRegIdx == null)
                {
                    goto update_cleanup;
                }
            }
            for (j = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, j++)
            {
                int reg;
                if (hasFK || chngRowid)
                {
                    reg = ++pParse.nMem;
                }
                else
                {
                    reg = 0;
                    for (i = 0; i < pIdx.nColumn; i++)
                    {
                        if (aXRef[pIdx.aiColumn[i]] >= 0)
                        {
                            reg = ++pParse.nMem;
                            break;
                        }
                    }
                }
                aRegIdx[j] = reg;
            }

            /* Begin generating code. */
            v = sqlite3GetVdbe(pParse);
            if (v == null)
            {
                goto update_cleanup;
            }
            if (pParse.nested == 0)
            {
                sqlite3VdbeCountChanges(v);
            }
            sqlite3BeginWriteOperation(pParse, 1, iDb);

#if !SQLITE_OMIT_VIRTUALTABLE
            /* Virtual tables must be handled separately */
            if (IsVirtual(pTab))
            {
                updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
                                   pWhere, onError);
                pWhere   = null;
                pTabList = null;
                goto update_cleanup;
            }
#endif

            /* Allocate required registers. */
            regOldRowid = regNewRowid = ++pParse.nMem;
            if (pTrigger != null || hasFK)
            {
                regOld       = pParse.nMem + 1;
                pParse.nMem += pTab.nCol;
            }
            if (chngRowid || pTrigger != null || hasFK)
            {
                regNewRowid = ++pParse.nMem;
            }
            regNew       = pParse.nMem + 1;
            pParse.nMem += pTab.nCol;

            /* Start the view context. */
            if (isView)
            {
                sqlite3AuthContextPush(pParse, sContext, pTab.zName);
            }

            /* If we are trying to update a view, realize that view into
            ** a ephemeral table.
            */
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
            if (isView)
            {
                sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
            }
#endif

            /* Resolve the column names in all the expressions in the
            ** WHERE clause.
            */
            if (sqlite3ResolveExprNames(sNC, ref pWhere) != 0)
            {
                goto update_cleanup;
            }

            /* Begin the database scan
             */
            sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
            ExprList NullOrderby = null;
            pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, ref NullOrderby, WHERE_ONEPASS_DESIRED);
            if (pWInfo == null)
            {
                goto update_cleanup;
            }
            okOnePass = pWInfo.okOnePass != 0;

            /* Remember the rowid of every item to be updated.
             */
            sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
            if (!okOnePass)
            {
                regRowSet = ++pParse.nMem;
                sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
            }

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

            /* Initialize the count of updated rows
             */
            if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
            {
                regRowCount = ++pParse.nMem;
                sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
            }

            if (!isView)
            {
                /*
                ** Open every index that needs updating.  Note that if any
                ** index could potentially invoke a REPLACE conflict resolution
                ** action, then we need to open all indices because we might need
                ** to be deleting some records.
                */
                if (!okOnePass)
                {
                    sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
                }
                if (onError == OE_Replace)
                {
                    openAll = true;
                }
                else
                {
                    openAll = false;
                    for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
                    {
                        if (pIdx.onError == OE_Replace)
                        {
                            openAll = true;
                            break;
                        }
                    }
                }
                for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
                {
                    if (openAll || aRegIdx[i] > 0)
                    {
                        KeyInfo pKey = sqlite3IndexKeyinfo(pParse, pIdx);
                        sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur + i + 1, pIdx.tnum, iDb,
                                          pKey, P4_KEYINFO_HANDOFF);
                        Debug.Assert(pParse.nTab > iCur + i + 1);
                    }
                }
            }

            /* Top of the update loop */
            if (okOnePass)
            {
                int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid);
                addr = sqlite3VdbeAddOp0(v, OP_Goto);
                sqlite3VdbeJumpHere(v, a1);
            }
            else
            {
                addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
            }

            /* Make cursor iCur point to the record that is being updated. If
            ** this record does not exist for some reason (deleted by a trigger,
            ** for example, then jump to the next iteration of the RowSet loop.  */
            sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);

            /* If the record number will change, set register regNewRowid to
            ** contain the new value. If the record number is not being modified,
            ** then regNewRowid is the same register as regOldRowid, which is
            ** already populated.  */
            Debug.Assert(chngRowid || pTrigger != null || hasFK || regOldRowid == regNewRowid);
            if (chngRowid)
            {
                sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
                sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
            }

            /* If there are triggers on this table, populate an array of registers
            ** with the required old.* column data.  */
            if (hasFK || pTrigger != null)
            {
                u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
                oldmask |= sqlite3TriggerColmask(pParse,
                                                 pTrigger, pChanges, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onError
                                                 );
                for (i = 0; i < pTab.nCol; i++)
                {
                    if (aXRef[i] < 0 || oldmask == 0xffffffff || (i < 32 && 0 != (oldmask & (1 << i))))
                    {
                        sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld + i);
                    }
                    else
                    {
                        sqlite3VdbeAddOp2(v, OP_Null, 0, regOld + i);
                    }
                }
                if (chngRowid == false)
                {
                    sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
                }
            }

            /* Populate the array of registers beginning at regNew with the new
            ** row data. This array is used to check constaints, create the new
            ** table and index records, and as the values for any new.* references
            ** made by triggers.
            **
            ** If there are one or more BEFORE triggers, then do not populate the
            ** registers associated with columns that are (a) not modified by
            ** this UPDATE statement and (b) not accessed by new.* references. The
            ** values for registers not modified by the UPDATE must be reloaded from
            ** the database after the BEFORE triggers are fired anyway (as the trigger
            ** may have modified them). So not loading those that are not going to
            ** be used eliminates some redundant opcodes.
            */
            newmask = (int)sqlite3TriggerColmask(
                pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
                );
            for (i = 0; i < pTab.nCol; i++)
            {
                if (i == pTab.iPKey)
                {
                    sqlite3VdbeAddOp2(v, OP_Null, 0, regNew + i);
                }
                else
                {
                    j = aXRef[i];
                    if (j >= 0)
                    {
                        sqlite3ExprCode(pParse, pChanges.a[j].pExpr, regNew + i);
                    }
                    else if (0 == (tmask & TRIGGER_BEFORE) || i > 31 || (newmask & (1 << i)) != 0)
                    {
                        /* This branch loads the value of a column that will not be changed
                        ** into a register. This is done if there are no BEFORE triggers, or
                        ** if there are one or more BEFORE triggers that use this value via
                        ** a new.* reference in a trigger program.
                        */
                        testcase(i == 31);
                        testcase(i == 32);
                        sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
                        sqlite3ColumnDefault(v, pTab, i, regNew + i);
                    }
                }
            }

            /* Fire any BEFORE UPDATE triggers. This happens before constraints are
            ** verified. One could argue that this is wrong.
            */
            if ((tmask & TRIGGER_BEFORE) != 0)
            {
                sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab.nCol);
                sqlite3TableAffinityStr(v, pTab);
                sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
                                      TRIGGER_BEFORE, pTab, regOldRowid, onError, addr);

                /* The row-trigger may have deleted the row being updated. In this
                ** case, jump to the next row. No updates or AFTER triggers are
                ** required. This behaviour - what happens when the row being updated
                ** is deleted or renamed by a BEFORE trigger - is left undefined in the
                ** documentation.
                */
                sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);

                /* If it did not delete it, the row-trigger may still have modified
                ** some of the columns of the row being updated. Load the values for
                ** all columns not modified by the update statement into their
                ** registers in case this has happened.
                */
                for (i = 0; i < pTab.nCol; i++)
                {
                    if (aXRef[i] < 0 && i != pTab.iPKey)
                    {
                        sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
                        sqlite3ColumnDefault(v, pTab, i, regNew + i);
                    }
                }
            }

            if (!isView)
            {
                int j1;                                       /* Address of jump instruction */

                /* Do constraint checks. */
                int iDummy;
                sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
                                                aRegIdx, (chngRowid ? regOldRowid : 0), true, onError, addr, out iDummy);

                /* Do FK constraint checks. */
                if (hasFK)
                {
                    sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
                }

                /* Delete the index entries associated with the current record.  */
                j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
                sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);

                /* If changing the record number, delete the old record.  */
                if (hasFK || chngRowid)
                {
                    sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
                }
                sqlite3VdbeJumpHere(v, j1);

                if (hasFK)
                {
                    sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
                }

                /* Insert the new index entries and the new record. */
                sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, true, false, false);

                /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
                ** handle rows (possibly in other tables) that refer via a foreign key
                ** to the row just updated. */
                if (hasFK)
                {
                    sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
                }
            }

            /* Increment the row counter
             */
            if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
            {
                sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
            }

            sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
                                  TRIGGER_AFTER, pTab, regOldRowid, onError, addr);

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

            /* Close all tables */
            for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
            {
                if (openAll || aRegIdx[i] > 0)
                {
                    sqlite3VdbeAddOp2(v, OP_Close, iCur + i + 1, 0);
                }
            }
            sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);

            /* Update the sqlite_sequence table by storing the content of the
            ** maximum rowid counter values recorded while inserting into
            ** autoincrement tables.
            */
            if (pParse.nested == 0 && pParse.pTriggerTab == null)
            {
                sqlite3AutoincrementEnd(pParse);
            }

            /*
            ** Return the number of rows that were changed. If this routine is
            ** generating code because of a call to sqlite3NestedParse(), do not
            ** invoke the callback function.
            */
            if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab && 0 == pParse.nested)
            {
                sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
                sqlite3VdbeSetNumCols(v, 1);
                sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
            }

update_cleanup:
#if !SQLITE_OMIT_AUTHORIZATION
            sqlite3AuthContextPop(sContext);
#endif
            sqlite3DbFree(db, ref aRegIdx);
            sqlite3DbFree(db, ref aXRef);
            sqlite3SrcListDelete(db, ref pTabList);
            sqlite3ExprListDelete(db, ref pChanges);
            sqlite3ExprDelete(db, ref pWhere);
            return;
        }
Example #20
0
    /*
    ** Process an UPDATE statement.
    **
    **   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
    **          \_______/ \________/     \______/       \________________/
    *            onError   pTabList      pChanges             pWhere
    */
    static void sqlite3Update(
    Parse pParse,         /* The parser context */
    SrcList pTabList,     /* The table in which we should change things */
    ExprList pChanges,    /* Things to be changed */
    Expr pWhere,          /* The WHERE clause.  May be null */
    int onError           /* How to handle constraint errors */
    )
    {
      int i, j;                   /* Loop counters */
      Table pTab;                 /* The table to be updated */
      int addr = 0;               /* VDBE instruction address of the start of the loop */
      WhereInfo pWInfo;           /* Information about the WHERE clause */
      Vdbe v;                     /* The virtual database engine */
      Index pIdx;                 /* For looping over indices */
      int nIdx;                   /* Number of indices that need updating */
      int iCur;                   /* VDBE Cursor number of pTab */
      sqlite3 db;                 /* The database structure */
      int[] aRegIdx = null;       /* One register assigned to each index to be updated */
      int[] aXRef = null;         /* aXRef[i] is the index in pChanges.a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
      bool chngRowid;             /* True if the record number is being changed */
      Expr pRowidExpr = null;     /* Expression defining the new record number */
      bool openAll = false;       /* True if all indices need to be opened */
      AuthContext sContext;       /* The authorization context */
      NameContext sNC;            /* The name-context to resolve expressions in */
      int iDb;                    /* Database containing the table being updated */
      int j1;                     /* Addresses of jump instructions */
      u8 okOnePass;               /* True for one-pass algorithm without the FIFO */

#if !SQLITE_OMIT_TRIGGER
      bool isView = false;         /* Trying to update a view */
      Trigger pTrigger;            /* List of triggers on pTab, if required */
#endif
      int iBeginAfterTrigger = 0;  /* Address of after trigger program */
      int iEndAfterTrigger = 0;    /* Exit of after trigger program */
      int iBeginBeforeTrigger = 0; /* Address of before trigger program */
      int iEndBeforeTrigger = 0;   /* Exit of before trigger program */
      u32 old_col_mask = 0;        /* Mask of OLD.* columns in use */
      u32 new_col_mask = 0;        /* Mask of NEW.* columns in use */

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

      /* Register Allocations */
      int regRowCount = 0;         /* A count of rows changed */
      int regOldRowid;             /* The old rowid */
      int regNewRowid;             /* The new rowid */
      int regData;                 /* New data for the row */
      int regRowSet = 0;           /* Rowset of rows to be updated */

      sContext = new AuthContext(); //memset( &sContext, 0, sizeof( sContext ) );
      db = pParse.db;
      if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
      {
        goto update_cleanup;
      }
      Debug.Assert( pTabList.nSrc == 1 );

      /* Locate the table which we want to update.
      */
      pTab = sqlite3SrcListLookup( pParse, pTabList );
      if ( pTab == null ) goto update_cleanup;
      iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );

      /* Figure out if we have any triggers and if the table being
      ** updated is a view
      */
#if !SQLITE_OMIT_TRIGGER
      int iDummy = 0;
      pTrigger = sqlite3TriggersExist( pParse, pTab, TK_UPDATE, pChanges, ref iDummy );
      isView = pTab.pSelect != null;
#else
const Trigger pTrigger = null;
#if !SQLITE_OMIT_VIEW
const bool isView = false;
#endif
#endif
#if SQLITE_OMIT_VIEW
//    # undef isView
const bool isView = false;
#endif

      if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 )
      {
        goto update_cleanup;
      }
      if ( sqlite3IsReadOnly( pParse, pTab, ( pTrigger != null ? 1 : 0 ) ) )
      {
        goto update_cleanup;
      }
      aXRef = new int[pTab.nCol];// sqlite3DbMallocRaw(db, sizeof(int) * pTab.nCol);
      //if ( aXRef == null ) goto update_cleanup;
      for ( i = 0 ; i < pTab.nCol ; i++ ) aXRef[i] = -1;

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

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

      /* Initialize the name-context */
      sNC = new NameContext();// memset(&sNC, 0, sNC).Length;
      sNC.pParse = pParse;
      sNC.pSrcList = pTabList;

      /* Resolve the column names in all the expressions of the
      ** of the UPDATE statement.  Also find the column index
      ** for each column to be updated in the pChanges array.  For each
      ** column to be updated, make sure we have authorization to change
      ** that column.
      */
      chngRowid = false;
      for ( i = 0 ; i < pChanges.nExpr ; i++ )
      {
        if ( sqlite3ResolveExprNames( sNC, ref pChanges.a[i].pExpr ) != 0 )
        {
          goto update_cleanup;
        }
        for ( j = 0 ; j < pTab.nCol ; j++ )
        {
          if ( sqlite3StrICmp( pTab.aCol[j].zName, pChanges.a[i].zName ) == 0 )
          {
            if ( j == pTab.iPKey )
            {
              chngRowid = true;
              pRowidExpr = pChanges.a[i].pExpr;
            }
            aXRef[j] = i;
            break;
          }
        }
        if ( j >= pTab.nCol )
        {
          if ( sqlite3IsRowid( pChanges.a[i].zName ) )
          {
            chngRowid = true;
            pRowidExpr = pChanges.a[i].pExpr;
          }
          else
          {
            sqlite3ErrorMsg( pParse, "no such column: %s", pChanges.a[i].zName );
            goto update_cleanup;
          }
        }
#if !SQLITE_OMIT_AUTHORIZATION
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab.zName,
pTab.aCol[j].zName, db.aDb[iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
aXRef[j] = -1;
}
}
#endif
      }

      /* Allocate memory for the array aRegIdx[].  There is one entry in the
      ** array for each index associated with table being updated.  Fill in
      ** the value with a register number for indices that are to be used
      ** and with zero for unused indices.
      */
      for ( nIdx = 0, pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext, nIdx++ ) { }
      if ( nIdx > 0 )
      {
        aRegIdx = new int[nIdx]; // sqlite3DbMallocRaw(db, Index*.Length * nIdx);
        if ( aRegIdx == null ) goto update_cleanup;
      }
      for ( j = 0, pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext, j++ )
      {
        int reg;
        if ( chngRowid )
        {
          reg = ++pParse.nMem;
        }
        else
        {
          reg = 0;
          for ( i = 0 ; i < pIdx.nColumn ; i++ )
          {
            if ( aXRef[pIdx.aiColumn[i]] >= 0 )
            {
              reg = ++pParse.nMem;
              break;
            }
          }
        }
        aRegIdx[j] = reg;
      }

      /* Allocate a block of register used to store the change record
      ** sent to sqlite3GenerateConstraintChecks().  There are either
      ** one or two registers for holding the rowid.  One rowid register
      ** is used if chngRowid is false and two are used if chngRowid is
      ** true.  Following these are pTab.nCol register holding column
      ** data.
      */
      regOldRowid = regNewRowid = pParse.nMem + 1;
      pParse.nMem += pTab.nCol + 1;
      if ( chngRowid )
      {
        regNewRowid++;
        pParse.nMem++;
      }
      regData = regNewRowid + 1;


      /* Begin generating code.
      */
      v = sqlite3GetVdbe( pParse );
      if ( v == null ) goto update_cleanup;
      if ( pParse.nested == 0 ) sqlite3VdbeCountChanges( v );
      sqlite3BeginWriteOperation( pParse, 1, iDb );

#if !SQLITE_OMIT_VIRTUALTABLE
/* Virtual tables must be handled separately */
if ( IsVirtual( pTab ) )
{
updateVirtualTable( pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, pWhere );
pWhere = null;
pTabList = null;
goto update_cleanup;
}
#endif

      /* Start the view context
*/
#if !SQLITE_OMIT_AUTHORIZATION
if( isView ){
sqlite3AuthContextPush(pParse, sContext, pTab.zName);
}
#endif
      /* Generate the code for triggers.
*/
      if ( pTrigger != null )
      {
        int iGoto;

        /* Create pseudo-tables for NEW and OLD
        */
        sqlite3VdbeAddOp3( v, OP_OpenPseudo, oldIdx, 0, pTab.nCol );
        sqlite3VdbeAddOp3( v, OP_OpenPseudo, newIdx, 0, pTab.nCol );

        iGoto = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 );
        addr = sqlite3VdbeMakeLabel( v );
        iBeginBeforeTrigger = sqlite3VdbeCurrentAddr( v );
        if ( sqlite3CodeRowTrigger( pParse, pTrigger, TK_UPDATE, pChanges,
        TRIGGER_BEFORE, pTab, newIdx, oldIdx, onError, addr,
        ref old_col_mask, ref new_col_mask ) != 0 )
        {
          goto update_cleanup;
        }
        iEndBeforeTrigger = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 );
        iBeginAfterTrigger = sqlite3VdbeCurrentAddr( v );
#if !SQLITE_OMIT_TRIGGER
        if ( sqlite3CodeRowTrigger( pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab,
        newIdx, oldIdx, onError, addr, ref old_col_mask, ref new_col_mask ) != 0 )
        {
          goto update_cleanup;
        }
#endif
        iEndAfterTrigger = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 );
        sqlite3VdbeJumpHere( v, iGoto );
      }

      /* If we are trying to update a view, realize that view into
      ** a ephemeral table.
      */
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
      if ( isView )
      {
        sqlite3MaterializeView( pParse, pTab, pWhere, iCur );
      }
#endif

      /* Resolve the column names in all the expressions in the
** WHERE clause.
*/
      if ( sqlite3ResolveExprNames( sNC, ref pWhere ) != 0 )
      {
        goto update_cleanup;
      }

      /* Begin the database scan
      */
      sqlite3VdbeAddOp2( v, OP_Null, 0, regOldRowid );
      ExprList NullOrderby = null;
      pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref NullOrderby, WHERE_ONEPASS_DESIRED );
      if ( pWInfo == null ) goto update_cleanup;
      okOnePass = pWInfo.okOnePass;

      /* Remember the rowid of every item to be updated.
      */
      sqlite3VdbeAddOp2( v, OP_Rowid, iCur, regOldRowid );
      if ( 0 == okOnePass )
      {
        regRowSet = ++pParse.nMem;
        sqlite3VdbeAddOp2( v, OP_RowSetAdd, regRowSet, regOldRowid );
      }

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

      /* Initialize the count of updated rows
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 && pParse.trigStack == null )
      {
        regRowCount = ++pParse.nMem;
        sqlite3VdbeAddOp2( v, OP_Integer, 0, regRowCount );
      }

      if ( !isView )
      {
        /*
        ** Open every index that needs updating.  Note that if any
        ** index could potentially invoke a REPLACE conflict resolution
        ** action, then we need to open all indices because we might need
        ** to be deleting some records.
        */
        if ( 0 == okOnePass ) sqlite3OpenTable( pParse, iCur, iDb, pTab, OP_OpenWrite );
        if ( onError == OE_Replace )
        {
          openAll = true;
        }
        else
        {
          openAll = false;
          for ( pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext )
          {
            if ( pIdx.onError == OE_Replace )
            {
              openAll = true;
              break;
            }
          }
        }
        for ( i = 0, pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext, i++ )
        {
          if ( openAll || aRegIdx[i] > 0 )
          {
            KeyInfo pKey = sqlite3IndexKeyinfo( pParse, pIdx );
            sqlite3VdbeAddOp4( v, OP_OpenWrite, iCur + i + 1, pIdx.tnum, iDb,
            pKey, P4_KEYINFO_HANDOFF );
            Debug.Assert( pParse.nTab > iCur + i + 1 );
          }
        }
      }

      /* Jump back to this point if a trigger encounters an IGNORE constraint. */
      if ( pTrigger != null )
      {
        sqlite3VdbeResolveLabel( v, addr );
      }

      /* Top of the update loop */
      if ( okOnePass != 0 )
      {
        int a1 = sqlite3VdbeAddOp1( v, OP_NotNull, regOldRowid );
        addr = sqlite3VdbeAddOp0( v, OP_Goto );
        sqlite3VdbeJumpHere( v, a1 );
      }
      else
      {
        addr = sqlite3VdbeAddOp3( v, OP_RowSetRead, regRowSet, 0, regOldRowid );
      }

      if ( pTrigger != null )
      {
        int regRowid;
        int regRow;
        int regCols;

        /* Make cursor iCur point to the record that is being updated.
        */
        sqlite3VdbeAddOp3( v, OP_NotExists, iCur, addr, regOldRowid );

        /* Generate the OLD table
        */
        regRowid = sqlite3GetTempReg( pParse );
        regRow = sqlite3GetTempReg( pParse );
        sqlite3VdbeAddOp2( v, OP_Rowid, iCur, regRowid );
        if ( old_col_mask == 0 )
        {
          sqlite3VdbeAddOp2( v, OP_Null, 0, regRow );
        }
        else
        {
          sqlite3VdbeAddOp2( v, OP_RowData, iCur, regRow );
        }
        sqlite3VdbeAddOp3( v, OP_Insert, oldIdx, regRow, regRowid );

        /* Generate the NEW table
        */
        if ( chngRowid )
        {
          sqlite3ExprCodeAndCache( pParse, pRowidExpr, regRowid );
          sqlite3VdbeAddOp1( v, OP_MustBeInt, regRowid );
        }
        else
        {
          sqlite3VdbeAddOp2( v, OP_Rowid, iCur, regRowid );
        }
        regCols = sqlite3GetTempRange( pParse, pTab.nCol );
        for ( i = 0 ; i < pTab.nCol ; i++ )
        {
          if ( i == pTab.iPKey )
          {
            sqlite3VdbeAddOp2( v, OP_Null, 0, regCols + i );
            continue;
          }
          j = aXRef[i];
          if ( ( i < 32 && ( new_col_mask & ( (u32)1 << i ) ) != 0 ) || new_col_mask == 0xffffffff )
          {
            if ( j < 0 )
            {
              sqlite3VdbeAddOp3( v, OP_Column, iCur, i, regCols + i );
              sqlite3ColumnDefault( v, pTab, i, -1 );
            }
            else
            {
              sqlite3ExprCodeAndCache( pParse, pChanges.a[j].pExpr, regCols + i );
            }
          }
          else
          {
            sqlite3VdbeAddOp2( v, OP_Null, 0, regCols + i );
          }
        }
        sqlite3VdbeAddOp3( v, OP_MakeRecord, regCols, pTab.nCol, regRow );
        if ( !isView )
        {
          sqlite3TableAffinityStr( v, pTab );
          sqlite3ExprCacheAffinityChange( pParse, regCols, pTab.nCol );
        }
        sqlite3ReleaseTempRange( pParse, regCols, pTab.nCol );
        /* if( pParse.nErr ) goto update_cleanup; */
        sqlite3VdbeAddOp3( v, OP_Insert, newIdx, regRow, regRowid );
        sqlite3ReleaseTempReg( pParse, regRowid );
        sqlite3ReleaseTempReg( pParse, regRow );

        sqlite3VdbeAddOp2( v, OP_Goto, 0, iBeginBeforeTrigger );
        sqlite3VdbeJumpHere( v, iEndBeforeTrigger );
      }

      if ( !isView )
      {

        /* Loop over every record that needs updating.  We have to load
        ** the old data for each record to be updated because some columns
        ** might not change and we will need to copy the old value.
        ** Also, the old data is needed to delete the old index entries.
        ** So make the cursor point at the old record.
        */
        sqlite3VdbeAddOp3( v, OP_NotExists, iCur, addr, regOldRowid );

        /* If the record number will change, push the record number as it
        ** will be after the update. (The old record number is currently
        ** on top of the stack.)
        */
        if ( chngRowid )
        {
          sqlite3ExprCode( pParse, pRowidExpr, regNewRowid );
          sqlite3VdbeAddOp1( v, OP_MustBeInt, regNewRowid );
        }

        /* Compute new data for this record.
        */
        for ( i = 0 ; i < pTab.nCol ; i++ )
        {
          if ( i == pTab.iPKey )
          {
            sqlite3VdbeAddOp2( v, OP_Null, 0, regData + i );
            continue;
          }
          j = aXRef[i];
          if ( j < 0 )
          {
            sqlite3VdbeAddOp3( v, OP_Column, iCur, i, regData + i );
            sqlite3ColumnDefault( v, pTab, i, regData + i );
          }
          else
          {
            sqlite3ExprCode( pParse, pChanges.a[j].pExpr, regData + i );
          }
        }

        /* Do constraint checks
        */
        iDummy = 0;
        sqlite3GenerateConstraintChecks( pParse, pTab, iCur, regNewRowid,
           aRegIdx, chngRowid, true,
           onError, addr, ref iDummy );

        /* Delete the old indices for the current record.
        */
        j1 = sqlite3VdbeAddOp3( v, OP_NotExists, iCur, 0, regOldRowid );
        sqlite3GenerateRowIndexDelete( pParse, pTab, iCur, aRegIdx );

        /* If changing the record number, delete the old record.
        */
        if ( chngRowid )
        {
          sqlite3VdbeAddOp2( v, OP_Delete, iCur, 0 );
        }
        sqlite3VdbeJumpHere( v, j1 );

        /* Create the new index entries and the new record.
        */
        sqlite3CompleteInsertion( pParse, pTab, iCur, regNewRowid,
        aRegIdx, true, -1, false, false );
      }

      /* Increment the row counter
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 && pParse.trigStack == null )
      {
        sqlite3VdbeAddOp2( v, OP_AddImm, regRowCount, 1 );
      }

      /* If there are triggers, close all the cursors after each iteration
      ** through the loop.  The fire the after triggers.
      */
      if ( pTrigger != null )
      {
        sqlite3VdbeAddOp2( v, OP_Goto, 0, iBeginAfterTrigger );
        sqlite3VdbeJumpHere( v, iEndAfterTrigger );
      }

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

      /* Close all tables */
      for ( i = 0, pIdx = pTab.pIndex ; pIdx != null ; pIdx = pIdx.pNext, i++ )
      {
        if ( openAll || aRegIdx[i] > 0 )
        {
          sqlite3VdbeAddOp2( v, OP_Close, iCur + i + 1, 0 );
        }
      }
      sqlite3VdbeAddOp2( v, OP_Close, iCur, 0 );
      if ( pTrigger != null )
      {
        sqlite3VdbeAddOp2( v, OP_Close, newIdx, 0 );
        sqlite3VdbeAddOp2( v, OP_Close, oldIdx, 0 );
      }

      /* Update the sqlite_sequence table by storing the content of the
      ** maximum rowid counter values recorded while inserting into
      ** autoincrement tables.
      */
      if ( pParse.nested == 0 && pParse.trigStack == null )
      {
        sqlite3AutoincrementEnd( pParse );
      }

      /*
      ** Return the number of rows that were changed. If this routine is
      ** generating code because of a call to sqlite3NestedParse(), do not
      ** invoke the callback function.
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 && pParse.trigStack == null && pParse.nested == 0 )
      {
        sqlite3VdbeAddOp2( v, OP_ResultRow, regRowCount, 1 );
        sqlite3VdbeSetNumCols( v, 1 );
        sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC );
      }

update_cleanup:
#if !SQLITE_OMIT_AUTHORIZATION
sqlite3AuthContextPop(sContext);
#endif
      //sqlite3DbFree( db, ref  aRegIdx );
      //sqlite3DbFree( db, ref  aXRef );
      sqlite3SrcListDelete( db, ref pTabList );
      sqlite3ExprListDelete( db, ref pChanges );
      sqlite3ExprDelete( db, ref pWhere );
      return;
    }
Example #21
0
        static WRC LookupName(Parse parse, string dbName, string tableName, string colName, NameContext nc, Expr expr)
        {
            int     cnt       = 0;            // Number of matching column names
            int     cntTab    = 0;            // Number of matching table names
            int     subquerys = 0;            // How many levels of subquery
            Context ctx       = parse.Ctx;    // The database connection

            SrcList.SrcListItem item;         // Use for looping over pSrcList items
            SrcList.SrcListItem match = null; // The matching pSrcList item
            NameContext         topNC = nc;   // First namecontext in the list
            Schema schema = null;             // Schema of the expression
            bool   isTrigger = false;
            int    i, j;

            Debug.Assert(nc != null);      // the name context cannot be NULL.
            Debug.Assert(colName != null); // The Z in X.Y.Z cannot be NULL
            Debug.Assert(!E.ExprHasAnyProperty(expr, EP.TokenOnly | EP.Reduced));

            // Initialize the node to no-match
            expr.TableId = -1;
            expr.Table   = null;
            E.ExprSetIrreducible(expr);

            // Translate the schema name in zDb into a pointer to the corresponding schema.  If not found, pSchema will remain NULL and nothing will match
            // resulting in an appropriate error message toward the end of this routine
            if (dbName != null)
            {
                for (i = 0; i < ctx.DBs.length; i++)
                {
                    Debug.Assert(ctx.DBs[i].Name != null);
                    if (string.Compare(ctx.DBs[i].Name, dbName) == 0)
                    {
                        schema = ctx.DBs[i].Schema;
                        break;
                    }
                }
            }

            // Start at the inner-most context and move outward until a match is found
            while (nc != null && cnt == 0)
            {
                ExprList list;
                SrcList  srcList = nc.SrcList;
                if (srcList != null)
                {
                    for (i = 0; i < srcList.Srcs; i++)
                    {
                        item = srcList.Ids[i];
                        Table table = item.Table;
                        Debug.Assert(table != null && table.Name != null);
                        Debug.Assert(table.Cols.length > 0);
                        if (item.Select != null && (item.Select.SelFlags & SF.NestedFrom) != 0)
                        {
                            bool hit = false;
                            list = item.Select.EList;
                            for (j = 0; j < list.Exprs; j++)
                            {
                                if (Walker.MatchSpanName(list.Ids[j].Span, colName, tableName, dbName))
                                {
                                    cnt++;
                                    cntTab        = 2;
                                    match         = item;
                                    expr.ColumnId = j;
                                    hit           = true;
                                }
                            }
                            if (hit || table == null)
                            {
                                continue;
                            }
                        }
                        if (dbName != null && table.Schema != schema)
                        {
                            continue;
                        }
                        if (tableName != null)
                        {
                            string tableName2 = (item.Alias != null ? item.Alias : table.Name);
                            Debug.Assert(tableName2 != null);
                            if (!string.Equals(tableName2, tableName, StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }
                        }
                        if (cntTab++ == 0)
                        {
                            match = item;
                        }
                        Column col;
                        for (j = 0; j < table.Cols.length; j++)
                        {
                            col = table.Cols[j];
                            if (string.Equals(col.Name, colName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                // If there has been exactly one prior match and this match is for the right-hand table of a NATURAL JOIN or is in a
                                // USING clause, then skip this match.
                                if (cnt == 1)
                                {
                                    if ((item.Jointype & JT.NATURAL) != 0)
                                    {
                                        continue;
                                    }
                                    if (NameInUsingClause(item.Using, colName))
                                    {
                                        continue;
                                    }
                                }
                                cnt++;
                                match = item;
                                // Substitute the rowid (column -1) for the INTEGER PRIMARY KEY
                                expr.ColumnId = (j == table.PKey ? -1 : (short)j);
                                break;
                            }
                        }
                    }
                    if (match != null)
                    {
                        expr.TableId = match.Cursor;
                        expr.Table   = match.Table;
                        schema       = expr.Table.Schema;
                    }
                }

#if !OMIT_TRIGGER
                // If we have not already resolved the name, then maybe it is a new.* or old.* trigger argument reference
                if (dbName == null && tableName != null && cnt == 0 && parse.TriggerTab != null)
                {
                    TK    op    = parse.TriggerOp;
                    Table table = null;
                    Debug.Assert(op == TK.DELETE || op == TK.UPDATE || op == TK.INSERT);
                    if (op != TK.DELETE && string.Equals("new", tableName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        expr.TableId = 1;
                        table        = parse.TriggerTab;
                    }
                    else if (op != TK.INSERT && string.Equals("old", tableName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        expr.TableId = 0;
                        table        = parse.TriggerTab;
                    }
                    if (table != null)
                    {
                        int colId;
                        schema = table.Schema;
                        cntTab++;
                        for (colId = 0; colId < table.Cols.length; colId++)
                        {
                            Column col = table.Cols[colId];
                            if (string.Equals(col.Name, colName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                if (colId == table.PKey)
                                {
                                    colId = -1;
                                }
                                break;
                            }
                        }
                        if (colId >= table.Cols.length && Expr.IsRowid(colName))
                        {
                            colId = -1; // IMP: R-44911-55124
                        }
                        if (colId < table.Cols.length)
                        {
                            cnt++;
                            if (colId < 0)
                            {
                                expr.Aff = AFF.INTEGER;
                            }
                            else if (expr.TableId == 0)
                            {
                                C.ASSERTCOVERAGE(colId == 31);
                                C.ASSERTCOVERAGE(colId == 32);
                                parse.Oldmask |= (colId >= 32 ? 0xffffffff : (((uint)1) << colId));
                            }
                            else
                            {
                                C.ASSERTCOVERAGE(colId == 31);
                                C.ASSERTCOVERAGE(colId == 32);
                                parse.Newmask |= (colId >= 32 ? 0xffffffff : (((uint)1) << colId));
                            }
                            expr.ColumnId = (short)colId;
                            expr.Table    = table;
                            isTrigger     = true;
                        }
                    }
                }
#endif

                // Perhaps the name is a reference to the ROWID
                if (cnt == 0 && cntTab == 1 && Expr.IsRowid(colName))
                {
                    cnt           = 1;
                    expr.ColumnId = -1; // IMP: R-44911-55124
                    expr.Aff      = AFF.INTEGER;
                }

                // If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z might refer to an result-set alias.  This happens, for example, when
                // we are resolving names in the WHERE clause of the following command:
                //
                //     SELECT a+b AS x FROM table WHERE x<10;
                //
                // In cases like this, replace pExpr with a copy of the expression that forms the result set entry ("a+b" in the example) and return immediately.
                // Note that the expression in the result set should have already been resolved by the time the WHERE clause is resolved.
                if (cnt == 0 && (list = nc.EList) != null && tableName == null)
                {
                    for (j = 0; j < list.Exprs; j++)
                    {
                        string asName = list.Ids[j].Name;
                        if (asName != null && string.Equals(asName, colName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            Debug.Assert(expr.Left == null && expr.Right == null);
                            Debug.Assert(expr.x.List == null);
                            Debug.Assert(expr.x.Select == null);
                            Expr orig = list.Ids[j].Expr;
                            if ((nc.NCFlags & NC.AllowAgg) == 0 && E.ExprHasProperty(orig, EP.Agg))
                            {
                                parse.ErrorMsg("misuse of aliased aggregate %s", asName);
                                return(WRC.Abort);
                            }
                            ResolveAlias(parse, list, j, expr, "", subquerys);
                            cnt   = 1;
                            match = null;
                            Debug.Assert(tableName == null && dbName == null);
                            goto lookupname_end;
                        }
                    }
                }

                // Advance to the next name context.  The loop will exit when either we have a match (cnt>0) or when we run out of name contexts.
                if (cnt == 0)
                {
                    nc = nc.Next;
                    subquerys++;
                }
            }

            // If X and Y are NULL (in other words if only the column name Z is supplied) and the value of Z is enclosed in double-quotes, then
            // Z is a string literal if it doesn't match any column names.  In that case, we need to return right away and not make any changes to
            // pExpr.
            //
            // Because no reference was made to outer contexts, the pNC->nRef fields are not changed in any context.
            if (cnt == 0 && tableName == null && E.ExprHasProperty(expr, EP.DblQuoted))
            {
                expr.OP    = TK.STRING;
                expr.Table = null;
                return(WRC.Prune);
            }

            // cnt==0 means there was not match.  cnt>1 means there were two or more matches.  Either way, we have an error.
            if (cnt != 1)
            {
                string err = (cnt == 0 ? "no such column" : "ambiguous column name");
                if (dbName != null)
                {
                    parse.ErrorMsg("%s: %s.%s.%s", err, dbName, tableName, colName);
                }
                else if (tableName != null)
                {
                    parse.ErrorMsg("%s: %s.%s", err, tableName, colName);
                }
                else
                {
                    parse.ErrorMsg("%s: %s", err, colName);
                }
                parse.CheckSchema = 1;
                topNC.Errs++;
            }

            // If a column from a table in pSrcList is referenced, then record this fact in the pSrcList.a[].colUsed bitmask.  Column 0 causes
            // bit 0 to be set.  Column 1 sets bit 1.  And so forth.  If the column number is greater than the number of bits in the bitmask
            // then set the high-order bit of the bitmask.
            if (expr.ColumnId >= 0 && match != null)
            {
                int n = expr.ColumnId;
                C.ASSERTCOVERAGE(n == BMS - 1);
                if (n >= BMS)
                {
                    n = BMS - 1;
                }
                Debug.Assert(match.Cursor == expr.TableId);
                match.ColUsed |= ((Bitmask)1) << n;
            }

            // Clean up and return
            Expr.Delete(ctx, ref expr.Left);
            expr.Left = null;
            Expr.Delete(ctx, ref expr.Right);
            expr.Right = null;
            expr.OP    = (isTrigger ? TK.TRIGGER : TK.COLUMN);
lookupname_end:
            if (cnt == 1)
            {
                Debug.Assert(nc != null);
                Auth.Read(parse, expr, schema, nc.SrcList);
                // Increment the nRef value on all name contexts from TopNC up to the point where the name matched.
                for (; ;)
                {
                    Debug.Assert(topNC != null);
                    topNC.Refs++;
                    if (topNC == nc)
                    {
                        break;
                    }
                    topNC = topNC.Next;
                }
                return(WRC.Prune);
            }
            return(WRC.Abort);
        }
Example #22
0
        /*
        ** Generate code for a DELETE FROM statement.
        **
        **     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
        **                 \________/       \________________/
        **                  pTabList              pWhere
        */
        static void sqlite3DeleteFrom(
            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 */
              string zDb;            /* Name of database holding pTab */
              int end, addr = 0;     /* 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 VdbeCursor number for pTab */
              sqlite3 db;            /* Main database structure */
              AuthContext sContext;  /* Authorization context */
              NameContext sNC;       /* Name context to resolve expressions in */
              int iDb;               /* Database number */
              int memCnt = -1;        /* Memory cell used for change counting */
              int rcauth;            /* Value returned by authorization callback */

            #if !SQLITE_OMIT_TRIGGER
              bool isView;                 /* True if attempting to delete from a view */
              Trigger pTrigger;            /* List of table triggers, if required */
            #endif
              sContext = new AuthContext();//memset(&sContext, 0, sizeof(sContext));

              db = pParse.db;
              if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
              {
            goto delete_from_cleanup;
              }
              Debug.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 = sqlite3SrcListLookup( pParse, pTabList );
              if ( pTab == null )
            goto delete_from_cleanup;

              /* Figure out if we have any triggers and if the table being
              ** deleted from is a view
              */
            #if !SQLITE_OMIT_TRIGGER
              int iDummy = 0;
              pTrigger = sqlite3TriggersExist( pParse, pTab, TK_DELETE, null, ref iDummy );
              isView = pTab.pSelect != null;
            #else
              const Trigger pTrigger = null;
              bool isView = false;
            #endif
            #if SQLITE_OMIT_VIEW
            //# undef isView
            isView = false;
            #endif

              /* If pTab is really a view, make sure it has been initialized.
            */
              if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 )
              {
            goto delete_from_cleanup;
              }

              if ( sqlite3IsReadOnly( pParse, pTab, ( pTrigger != null ? 1 : 0 ) ) )
              {
            goto delete_from_cleanup;
              }
              iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
              Debug.Assert( iDb < db.nDb );
              zDb = db.aDb[iDb].zName;
            #if !SQLITE_OMIT_AUTHORIZATION
            rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
            #else
              rcauth = SQLITE_OK;
            #endif
              Debug.Assert( rcauth == SQLITE_OK || rcauth == SQLITE_DENY || rcauth == SQLITE_IGNORE );
              if ( rcauth == SQLITE_DENY )
              {
            goto delete_from_cleanup;
              }
              Debug.Assert( !isView || pTrigger != null );

              /* Assign  cursor number to the table and all its indices.
              */
              Debug.Assert( pTabList.nSrc == 1 );
              iCur = pTabList.a[0].iCursor = pParse.nTab++;
              for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
              {
            pParse.nTab++;
              }

            #if !SQLITE_OMIT_AUTHORIZATION
            /* Start the view context
            */
            if( isView ){
            sqlite3AuthContextPush(pParse, sContext, pTab.zName);
            }
            #endif
              /* Begin generating code.
            */
              v = sqlite3GetVdbe( pParse );
              if ( v == null )
              {
            goto delete_from_cleanup;
              }
              if ( pParse.nested == 0 )
            sqlite3VdbeCountChanges( v );
              sqlite3BeginWriteOperation( pParse, 1, iDb );

              /* If we are trying to delete from a view, realize that view into
              ** a ephemeral table.
              */
            #if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
              if ( isView )
              {
            sqlite3MaterializeView( pParse, pTab, pWhere, iCur );
              }
            #endif
              /* Resolve the column names in the WHERE clause.
              */
              sNC = new NameContext();// memset( &sNC, 0, sizeof( sNC ) );
              sNC.pParse = pParse;
              sNC.pSrcList = pTabList;
              if ( sqlite3ResolveExprNames( sNC, ref pWhere ) != 0 )
              {
            goto delete_from_cleanup;
              }

              /* Initialize the counter of the number of rows deleted, if
            ** we are counting rows.
            */
              if ( ( db.flags & SQLITE_CountRows ) != 0 )
              {
            memCnt = ++pParse.nMem;
            sqlite3VdbeAddOp2( v, OP_Integer, 0, memCnt );
              }

            #if !SQLITE_OMIT_TRUNCATE_OPTIMIZATION
              /* Special case: A DELETE without a WHERE clause deletes everything.
              ** It is easier just to erase the whole table. Prior to version 3.6.5,
              ** this optimization caused the row change count (the value returned by
              ** API function sqlite3_count_changes) to be set incorrectly.  */
              if ( rcauth == SQLITE_OK && pWhere == null && null == pTrigger && !IsVirtual( pTab )
            && 0 == sqlite3FkRequired( pParse, pTab, null, 0 )
            )
              {
            Debug.Assert( !isView );
            sqlite3VdbeAddOp4( v, OP_Clear, pTab.tnum, iDb, memCnt,
              pTab.zName, P4_STATIC );
            for ( pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext )
            {
              Debug.Assert( pIdx.pSchema == pTab.pSchema );
              sqlite3VdbeAddOp2( v, OP_Clear, pIdx.tnum, iDb );
            }
              }
              else
            #endif //* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
              /* The usual case: There is a WHERE clause so we have to scan through
            ** the table and pick which records to delete.
            */
              {
            int iRowSet = ++pParse.nMem;    /* Register for rowset of rows to delete */
            int iRowid = ++pParse.nMem;     /* Used for storing rowid values. */
            int regRowid;                   /* Actual register containing rowids */

            /* Collect rowids of every row to be deleted.
            */
            sqlite3VdbeAddOp2( v, OP_Null, 0, iRowSet );
            ExprList elDummy = null;
            pWInfo = sqlite3WhereBegin( pParse, pTabList, pWhere, ref elDummy, WHERE_DUPLICATES_OK );
            if ( pWInfo == null )
              goto delete_from_cleanup;
            regRowid = sqlite3ExprCodeGetColumn( pParse, pTab, -1, iCur, iRowid );
            sqlite3VdbeAddOp2( v, OP_RowSetAdd, iRowSet, regRowid );
            if ( ( db.flags & SQLITE_CountRows ) != 0 )
            {
              sqlite3VdbeAddOp2( v, OP_AddImm, memCnt, 1 );
            }

            sqlite3WhereEnd( pWInfo );

            /* 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. */
            end = sqlite3VdbeMakeLabel( v );

            /* Unless this is a view, open cursors for the table we are
            ** deleting from and all its indices. If this is a view, then the
            ** only effect this statement has is to fire the INSTEAD OF
            ** triggers.  */
            if ( !isView )
            {
              sqlite3OpenTableAndIndices( pParse, pTab, iCur, OP_OpenWrite );
            }

            addr = sqlite3VdbeAddOp3( v, OP_RowSetRead, iRowSet, end, iRowid );

            /* Delete the row */
            #if !SQLITE_OMIT_VIRTUALTABLE
            if( IsVirtual(pTab) ){
            const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
            sqlite3VtabMakeWritable(pParse, pTab);
            sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB);
            sqlite3MayAbort(pParse);
            }else
            #endif
            {
              int count = ( pParse.nested == 0 ) ? 1 : 0;    /* True to count changes */
              sqlite3GenerateRowDelete( pParse, pTab, iCur, iRowid, count, pTrigger, OE_Default );
            }

            /* End of the delete loop */
            sqlite3VdbeAddOp2( v, OP_Goto, 0, addr );
            sqlite3VdbeResolveLabel( v, end );

            /* Close the cursors open on the table and its indexes. */
            if ( !isView && !IsVirtual( pTab ) )
            {
              for ( i = 1, pIdx = pTab.pIndex; pIdx != null; i++, pIdx = pIdx.pNext )
              {
            sqlite3VdbeAddOp2( v, OP_Close, iCur + i, pIdx.tnum );
              }
              sqlite3VdbeAddOp1( v, OP_Close, iCur );
            }
              }

              /* Update the sqlite_sequence table by storing the content of the
              ** maximum rowid counter values recorded while inserting into
              ** autoincrement tables.
              */
              if ( pParse.nested == 0 && pParse.pTriggerTab == null )
              {
            sqlite3AutoincrementEnd( pParse );
              }

              /* Return the number of rows that were deleted. If this routine is
              ** generating code because of a call to sqlite3NestedParse(), do not
              ** invoke the callback function.
              */

              if ( ( db.flags & SQLITE_CountRows ) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab )
              {
            sqlite3VdbeAddOp2( v, OP_ResultRow, memCnt, 1 );
            sqlite3VdbeSetNumCols( v, 1 );
            sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC );
              }

            delete_from_cleanup:
            #if !SQLITE_OMIT_AUTHORIZATION
            sqlite3AuthContextPop(sContext);
            #endif
              sqlite3SrcListDelete( db, ref pTabList );
              sqlite3ExprDelete( db, ref pWhere );
              return;
        }
Example #23
0
        static void GenerateColumnTypes(Parse parse, SrcList tabList, ExprList list)
        {
#if !OMIT_DECLTYPE
            Vdbe v = parse.V;
            NameContext sNC = new NameContext();
            sNC.SrcList = tabList;
            sNC.Parse = parse;
            for (int i = 0; i < list.Exprs; i++)
            {
                Expr p = list.Ids[i].Expr;
                string typeName;
#if ENABLE_COLUMN_METADATA
                string origDbName = null;
                string origTableName = null;
                string origColumnName = null;
                typeName = ColumnType(sNC, p, ref origDbName, ref origTableName, ref origColumnName);

                // The vdbe must make its own copy of the column-type and other column specific strings, in case the schema is reset before this
                // virtual machine is deleted.
                v.SetColName(i, COLNAME_DATABASE, origDbName, C.DESTRUCTOR_TRANSIENT);
                v.SetColName(i, COLNAME_TABLE, origTableName, C.DESTRUCTOR_TRANSIENT);
                v.SetColName(i, COLNAME_COLUMN, origColumnName, C.DESTRUCTOR_TRANSIENT);
#else
                string dummy1 = null;
                typeName = ColumnType(sNC, p, ref dummy1, ref dummy1, ref dummy1);
#endif
                v.SetColName(i, COLNAME_DECLTYPE, typeName, C.DESTRUCTOR_TRANSIENT);
            }
#endif
        }
Example #24
0
    /*
    ** If cursors, triggers, views and subqueries are all omitted from
    ** the build, then none of the following routines, except for
    ** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
    ** called with a NULL argument.
    */
#if !SQLITE_OMIT_VIEW || !SQLITE_OMIT_TRIGGER  || !SQLITE_OMIT_SUBQUERY
    static SrcList sqlite3SrcListDup( sqlite3 db, SrcList p, int flags )
    {
      SrcList pNew;
      int i;
      int nByte;
      if ( p == null )
        return null;
      //nByte = sizeof(*p) + (p.nSrc>0 ? sizeof(p.a[0]) * (p.nSrc-1) : 0);
      pNew = new SrcList();//sqlite3DbMallocRaw(db, nByte );
      if ( p.nSrc > 0 )
        pNew.a = new SrcList_item[p.nSrc];
      if ( pNew == null )
        return null;
      pNew.nSrc = pNew.nAlloc = p.nSrc;
      for ( i = 0; i < p.nSrc; i++ )
      {
        pNew.a[i] = new SrcList_item();
        SrcList_item pNewItem = pNew.a[i];
        SrcList_item pOldItem = p.a[i];
        Table pTab;
        pNewItem.zDatabase = pOldItem.zDatabase;// sqlite3DbStrDup(db, pOldItem.zDatabase);
        pNewItem.zName = pOldItem.zName;// sqlite3DbStrDup(db, pOldItem.zName);
        pNewItem.zAlias = pOldItem.zAlias;// sqlite3DbStrDup(db, pOldItem.zAlias);
        pNewItem.jointype = pOldItem.jointype;
        pNewItem.iCursor = pOldItem.iCursor;
        pNewItem.isPopulated = pOldItem.isPopulated;
        pNewItem.zIndex = pOldItem.zIndex;// sqlite3DbStrDup( db, pOldItem.zIndex );
        pNewItem.notIndexed = pOldItem.notIndexed;
        pNewItem.pIndex = pOldItem.pIndex;
        pTab = pNewItem.pTab = pOldItem.pTab;
        if ( pTab != null )
        {
          pTab.nRef++;
        }
        pNewItem.pSelect = sqlite3SelectDup( db, pOldItem.pSelect, flags );
        pNewItem.pOn = sqlite3ExprDup( db, pOldItem.pOn, flags );
        pNewItem.pUsing = sqlite3IdListDup( db, pOldItem.pUsing );
        pNewItem.colUsed = pOldItem.colUsed;
      }
      return pNew;
    }
Example #25
0
    /*
    ** Generate code that will tell the VDBE the declaration types of columns
    ** in the result set.
    */
    static void generateColumnTypes(
    Parse pParse,      /* Parser context */
    SrcList pTabList,  /* List of tables */
    ExprList pEList    /* Expressions defining the result set */
    )
    {
#if !SQLITE_OMIT_DECLTYPE
      Vdbe v = pParse.pVdbe;
      int i;
      NameContext sNC = new NameContext();
      sNC.pSrcList = pTabList;
      sNC.pParse = pParse;
      for ( i = 0; i < pEList.nExpr; i++ )
      {
        Expr p = pEList.a[i].pExpr;
        string zType;
#if SQLITE_ENABLE_COLUMN_METADATA
        string zOrigDb = null;
        string zOrigTab = null;
        string zOrigCol = null;
        zType = columnType( sNC, p, ref zOrigDb, ref zOrigTab, ref zOrigCol );

        /* The vdbe must make its own copy of the column-type and other
        ** column specific strings, in case the schema is reset before this
        ** virtual machine is deleted.
        */
        sqlite3VdbeSetColName( v, i, COLNAME_DATABASE, zOrigDb, SQLITE_TRANSIENT );
        sqlite3VdbeSetColName( v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT );
        sqlite3VdbeSetColName( v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT );
#else
        string sDummy = null;
        zType = columnType( sNC, p, ref sDummy, ref sDummy, ref sDummy );
#endif
        sqlite3VdbeSetColName( v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT );
      }
#endif //* SQLITE_OMIT_DECLTYPE */
    }
Example #26
0
        static void AddWhereTerm(Parse parse, SrcList src, int leftId, int colLeftId, int rightId, int colRightId, bool isOuterJoin, ref Expr where_)
        {
            Context ctx = parse.Ctx;
            Debug.Assert(leftId < rightId);
            Debug.Assert(src.Srcs > rightId);
            Debug.Assert(src.Ids[leftId].Table != null);
            Debug.Assert(src.Ids[rightId].Table != null);

            Expr e1 = Walker.CreateColumnExpr(ctx, src, leftId, colLeftId);
            Expr e2 = Walker.CreateColumnExpr(ctx, src, rightId, colRightId);

            Expr eq = Expr.PExpr_(parse, TK.EQ, e1, e2, null);
            if (eq != null && isOuterJoin)
            {
                E.ExprSetProperty(eq, EP.FromJoin);
                Debug.Assert(!E.ExprHasAnyProperty(eq, EP.TokenOnly | EP.Reduced));
                E.ExprSetIrreducible(eq);
                eq.RightJoinTable = (short)e2.TableId;
            }
            where_ = Expr.And(ctx, where_, eq);
        }
Example #27
0
    /*
    ** Search the first N tables in pSrc, from left to right, looking for a
    ** table that has a column named zCol.  
    **
    ** When found, set *piTab and *piCol to the table index and column index
    ** of the matching column and return TRUE.
    **
    ** If not found, return FALSE.
    */
    static int tableAndColumnIndex(
    SrcList pSrc,        /* Array of tables to search */
    int N,               /* Number of tables in pSrc.a[] to search */
    string zCol,         /* Name of the column we are looking for */
    ref int piTab,       /* Write index of pSrc.a[] here */
    ref int piCol        /* Write index of pSrc.a[*piTab].pTab.aCol[] here */
    )
    {
      int i;               /* For looping over tables in pSrc */
      int iCol;            /* Index of column matching zCol */

      Debug.Assert( ( piTab == 0 ) == ( piCol == 0 ) );  /* Both or neither are NULL */
      for ( i = 0; i < N; i++ )
      {
        iCol = columnIndex( pSrc.a[i].pTab, zCol );
        if ( iCol >= 0 )
        {
          //if( piTab )
          {
            piTab = i;
            piCol = iCol;
          }
          return 1;
        }
      }
      return 0;
    }
Example #28
0
    /*
    ** This function is called to generate code that runs when table pTab is
    ** being dropped from the database. The SrcList passed as the second argument
    ** to this function contains a single entry guaranteed to resolve to
    ** table pTab.
    **
    ** Normally, no code is required. However, if either
    **
    **   (a) The table is the parent table of a FK constraint, or
    **   (b) The table is the child table of a deferred FK constraint and it is
    **       determined at runtime that there are outstanding deferred FK 
    **       constraint violations in the database,
    **
    ** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
    ** the table from the database. Triggers are disabled while running this
    ** DELETE, but foreign key actions are not.
    */
    static void sqlite3FkDropTable( Parse pParse, SrcList pName, Table pTab )
    {
      sqlite3 db = pParse.db;
      if ( ( db.flags & SQLITE_ForeignKeys ) != 0 && !IsVirtual( pTab ) && null == pTab.pSelect )
      {
        int iSkip = 0;
        Vdbe v = sqlite3GetVdbe( pParse );

        Debug.Assert( v != null );                  /* VDBE has already been allocated */
        if ( sqlite3FkReferences( pTab ) == null )
        {
          /* Search for a deferred foreign key constraint for which this table
          ** is the child table. If one cannot be found, return without 
          ** generating any VDBE code. If one can be found, then jump over
          ** the entire DELETE if there are no outstanding deferred constraints
          ** when this statement is run.  */
          FKey p;
          for ( p = pTab.pFKey; p != null; p = p.pNextFrom )
          {
            if ( p.isDeferred != 0 )
              break;
          }
          if ( null == p )
            return;
          iSkip = sqlite3VdbeMakeLabel( v );
          sqlite3VdbeAddOp2( v, OP_FkIfZero, 1, iSkip );
        }

        pParse.disableTriggers = 1;
        sqlite3DeleteFrom( pParse, sqlite3SrcListDup( db, pName, 0 ), null );
        pParse.disableTriggers = 0;

        /* If the DELETE has generated immediate foreign key constraint 
        ** violations, halt the VDBE and return an error at this point, before
        ** any modifications to the schema are made. This is because statement
        ** transactions are not able to rollback schema changes.  */
        sqlite3VdbeAddOp2( v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr( v ) + 2 );
        sqlite3HaltConstraint(
            pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
        );

        if ( iSkip != 0 )
        {
          sqlite3VdbeResolveLabel( v, iSkip );
        }
      }
    }
Example #29
0
        static WRC ResolveExprStep(Walker walker, Expr expr)
        {
            NameContext nc = walker.u.NC;

            Debug.Assert(nc != null);
            Parse parse = nc.Parse;

            Debug.Assert(parse == walker.Parse);

            if (E.ExprHasAnyProperty(expr, EP.Resolved))
            {
                return(WRC.Prune);
            }
            E.ExprSetProperty(expr, EP.Resolved);
#if !NDEBUG
            if (nc.SrcList != null && nc.SrcList.Allocs > 0)
            {
                SrcList srcList = nc.SrcList;
                for (int i = 0; i < nc.SrcList.Srcs; i++)
                {
                    Debug.Assert(srcList.Ids[i].Cursor >= 0 && srcList.Ids[i].Cursor < parse.Tabs);
                }
            }
#endif
            switch (expr.OP)
            {
#if ENABLE_UPDATE_DELETE_LIMIT && !OMIT_SUBQUERY
            // The special operator TK_ROW means use the rowid for the first column in the FROM clause.  This is used by the LIMIT and ORDER BY
            // clause processing on UPDATE and DELETE statements.
            case TK.ROW:
            {
                SrcList srcList = nc.SrcList;
                Debug.Assert(srcList != null && srcList.Srcs == 1);
                SrcList.SrcListItem item = srcList.Ids[0];
                expr.OP       = TK.COLUMN;
                expr.Table    = item.Table;
                expr.TableId  = item.Cursor;
                expr.ColumnId = -1;
                expr.Aff      = AFF.INTEGER;
                break;
            }
#endif

            case TK.ID:      // A lone identifier is the name of a column.
            {
                return(LookupName(parse, null, null, expr.u.Token, nc, expr));
            }

            case TK.DOT:     // A table name and column name: ID.ID Or a database, table and column: ID.ID.ID
            {
                string columnName;
                string tableName;
                string dbName;
                // if (srcList == nullptr) break;
                Expr right = expr.Right;
                if (right.OP == TK.ID)
                {
                    dbName     = null;
                    tableName  = expr.Left.u.Token;
                    columnName = right.u.Token;
                }
                else
                {
                    Debug.Assert(right.OP == TK.DOT);
                    dbName     = expr.Left.u.Token;
                    tableName  = right.Left.u.Token;
                    columnName = right.Right.u.Token;
                }
                return(LookupName(parse, dbName, tableName, columnName, nc, expr));
            }

            case TK.CONST_FUNC:
            case TK.FUNCTION:                                              // Resolve function names
            {
                ExprList   list         = expr.x.List;                     // The argument list
                int        n            = (list != null ? list.Exprs : 0); // Number of arguments
                bool       noSuchFunc   = false;                           // True if no such function exists
                bool       wrongNumArgs = false;                           // True if wrong number of arguments
                bool       isAgg        = false;                           // True if is an aggregate function
                TEXTENCODE encode       = E.CTXENCODE(parse.Ctx);          // The database encoding

                C.ASSERTCOVERAGE(expr.OP == TK.CONST_FUNC);
                Debug.Assert(!E.ExprHasProperty(expr, EP.xIsSelect));
                string  id       = expr.u.Token;                                                     // The function name.
                int     idLength = id.Length;                                                        // Number of characters in function name
                FuncDef def      = Callback.FindFunction(parse.Ctx, id, idLength, n, encode, false); // Information about the function
                if (def == null)
                {
                    def = Callback.FindFunction(parse.Ctx, id, idLength, -2, encode, false);
                    if (def == null)
                    {
                        noSuchFunc = true;
                    }
                    else
                    {
                        wrongNumArgs = true;
                    }
                }
                else
                {
                    isAgg = (def.Func == null);
                }
#if !OMIT_AUTHORIZATION
                if (def != null)
                {
                    ARC auth = Auth.Check(parse, AUTH.FUNCTION, null, def.Name, null);         // Authorization to use the function
                    if (auth != ARC.OK)
                    {
                        if (auth == ARC.DENY)
                        {
                            parse.ErrorMsg("not authorized to use function: %s", def.Name);
                            nc.Errs++;
                        }
                        expr.OP = TK.NULL;
                        return(WRC.Prune);
                    }
                }
#endif
                if (isAgg && (nc.NCFlags & NC.AllowAgg) == 0)
                {
                    parse.ErrorMsg("misuse of aggregate function %.*s()", idLength, id);
                    nc.Errs++;
                    isAgg = false;
                }
                else if (noSuchFunc && !ctx.Init.Busy)
                {
                    parse.ErrorMsg("no such function: %.*s", idLength, id);
                    nc.Errs++;
                }
                else if (wrongNumArgs)
                {
                    parse.ErrorMsg("wrong number of arguments to function %.*s()", idLength, id);
                    nc.Errs++;
                }
                if (isAgg)
                {
                    nc.NCFlags &= ~NC.AllowAgg;
                }
                walker.WalkExprList(list);
                if (isAgg)
                {
                    NameContext nc2 = nc;
                    expr.OP  = TK.AGG_FUNCTION;
                    expr.OP2 = 0;
                    while (nc2 != null && !expr.FunctionUsesThisSrc(nc2.SrcList))
                    {
                        expr.OP2++;
                        nc2 = nc2.Next;
                    }
                    if (nc2 != null)
                    {
                        nc2.NCFlags |= NC.HasAgg;
                    }
                    nc.NCFlags |= NC.AllowAgg;
                }
                // FIX ME:  Compute pExpr->affinity based on the expected return type of the function
                return(WRC.Prune);
            }

#if !OMIT_SUBQUERY
            case TK.SELECT:
            case TK.EXISTS:
            {
                C.ASSERTCOVERAGE(expr.OP == TK.EXISTS);
                goto case TK.IN;
            }
#endif
            case TK.IN:
            {
                C.ASSERTCOVERAGE(expr.OP == TK.IN);
                if (E.ExprHasProperty(expr, EP.xIsSelect))
                {
                    int refs = nc.Refs;
#if !OMIT_CHECK
                    if ((nc.NCFlags & NC.IsCheck) != 0)
                    {
                        parse.ErrorMsg("subqueries prohibited in CHECK constraints");
                    }
#endif
                    walker.WalkSelect(expr.x.Select);
                    Debug.Assert(nc.Refs >= refs);
                    if (refs != nc.Refs)
                    {
                        E.ExprSetProperty(expr, EP.VarSelect);
                    }
                }
                break;
            }

#if !OMIT_CHECK
            case TK.VARIABLE:
            {
                if ((nc.NCFlags & NC.IsCheck) != 0)
                {
                    parse.ErrorMsg("parameters prohibited in CHECK constraints");
                }

                break;
            }
#endif
            }
            return(parse.Errs != 0 || parse.Ctx.MallocFailed ? WRC.Abort : WRC.Continue);
        }
Example #30
0
        static void GenerateColumnNames(Parse parse, SrcList tabList, ExprList list)
        {
#if !OMIT_EXPLAIN
            // If this is an EXPLAIN, skip this step
            if (parse.Explain != 0)
                return;
#endif
            Vdbe v = parse.V;
            Context ctx = parse.Ctx;
            if (parse.ColNamesSet != 0 || C._NEVER(v == null) || ctx.MallocFailed) return;
            parse.ColNamesSet = 1;
            bool fullNames = ((ctx.Flags & Context.FLAG.FullColNames) != 0);
            bool shortNames = ((ctx.Flags & Context.FLAG.ShortColNames) != 0);
            v.SetNumCols(list.Exprs);
            for (int i = 0; i < list.Exprs; i++)
            {
                Expr p = list.Ids[i].Expr;
                if (C._NEVER(p == null)) continue;
                if (list.Ids[i].Name != null)
                {
                    string name = list.Ids[i].Name;
                    v.SetColName(i, COLNAME_NAME, name, C.DESTRUCTOR_TRANSIENT);
                }
                else if ((p.OP == TK.COLUMN || p.OP == TK.AGG_COLUMN) && tabList != null)
                {
                    int colId = p.ColumnIdx;
                    int j;
                    for (j = 0; C._ALWAYS(j < tabList.Srcs); j++)
                        if (tabList.Ids[j].Cursor == p.TableId) break;
                    Debug.Assert(j < tabList.Srcs);
                    Table table = tabList.Ids[j].Table;
                    if (colId < 0) colId = table.PKey;
                    Debug.Assert(colId == -1 || (colId >= 0 && colId < table.Cols.length));
                    string colName = (colId < 0 ? "rowid" : table.Cols[colId].Name);
                    if (!shortNames && !fullNames)
                        v.SetColName(i, COLNAME_NAME, list.Ids[i].Span, C.DESTRUCTOR_DYNAMIC);
                    else if (fullNames)
                    {
                        string name = C._mtagprintf(ctx, "%s.%s", table.Name, colName);
                        v.SetColName(i, COLNAME_NAME, name, C.DESTRUCTOR_DYNAMIC);
                    }
                    else
                        v.SetColName(i, COLNAME_NAME, colName, C.DESTRUCTOR_TRANSIENT);
                }
                else
                    v.SetColName(i, COLNAME_NAME, list.Ids[i].Span, C.DESTRUCTOR_TRANSIENT);
            }
            GenerateColumnTypes(parse, tabList, list);
        }
Example #31
0
 static void sqlite3Insert( Parse pParse, SrcList pTabList, int null_3, Select pSelect, IdList pColumn, int onError )
 {
   sqlite3Insert( pParse, pTabList, null, pSelect, pColumn, onError );
 }
Example #32
0
    /*
    ** Generate code that will tell the VDBE the names of columns
    ** in the result set.  This information is used to provide the
    ** azCol[] values in the callback.
    */
    static void generateColumnNames(
    Parse pParse,      /* Parser context */
    SrcList pTabList,  /* List of tables */
    ExprList pEList    /* Expressions defining the result set */
    )
    {
      Vdbe v = pParse.pVdbe;
      int i, j;
      sqlite3 db = pParse.db;
      bool fullNames;
      bool shortNames;

#if !SQLITE_OMIT_EXPLAIN
      /* If this is an EXPLAIN, skip this step */
      if ( pParse.explain != 0 )
      {
        return;
      }
#endif

      if ( pParse.colNamesSet != 0 || NEVER( v == null ) /*|| db.mallocFailed != 0 */ )
        return;
      pParse.colNamesSet = 1;
      fullNames = ( db.flags & SQLITE_FullColNames ) != 0;
      shortNames = ( db.flags & SQLITE_ShortColNames ) != 0;
      sqlite3VdbeSetNumCols( v, pEList.nExpr );
      for ( i = 0; i < pEList.nExpr; i++ )
      {
        Expr p;
        p = pEList.a[i].pExpr;
        if ( NEVER( p == null ) )
          continue;
        if ( pEList.a[i].zName != null )
        {
          string zName = pEList.a[i].zName;
          sqlite3VdbeSetColName( v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT );
        }
        else if ( ( p.op == TK_COLUMN || p.op == TK_AGG_COLUMN ) && pTabList != null )
        {
          Table pTab;
          string zCol;
          int iCol = p.iColumn;
          for ( j = 0; ALWAYS( j < pTabList.nSrc ); j++ )
          {
            if ( pTabList.a[j].iCursor == p.iTable )
              break;
          }
          Debug.Assert( j < pTabList.nSrc );
          pTab = pTabList.a[j].pTab;
          if ( iCol < 0 )
            iCol = pTab.iPKey;
          Debug.Assert( iCol == -1 || ( iCol >= 0 && iCol < pTab.nCol ) );
          if ( iCol < 0 )
          {
            zCol = "rowid";
          }
          else
          {
            zCol = pTab.aCol[iCol].zName;
          }
          if ( !shortNames && !fullNames )
          {
            sqlite3VdbeSetColName( v, i, COLNAME_NAME,
            pEList.a[i].zSpan, SQLITE_DYNAMIC );//sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
          }
          else if ( fullNames )
          {
            string zName;
            zName = sqlite3MPrintf( db, "%s.%s", pTab.zName, zCol );
            sqlite3VdbeSetColName( v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC );
          }
          else
          {
            sqlite3VdbeSetColName( v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT );
          }
        }
        else
        {
          sqlite3VdbeSetColName( v, i, COLNAME_NAME,
          pEList.a[i].zSpan, SQLITE_DYNAMIC );//sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
        }
      }
      generateColumnTypes( pParse, pTabList, pEList );
    }
Example #33
0
 static void sqlite3Insert( Parse pParse, SrcList pTabList, ExprList pList, int null_4, IdList pColumn, int onError )
 {
   sqlite3Insert( pParse, pTabList, pList, null, pColumn, onError );
 }
Example #34
0
    /*
    ** This function is used to add terms implied by JOIN syntax to the
    ** WHERE clause expression of a SELECT statement. The new term, which
    ** is ANDed with the existing WHERE clause, is of the form:
    **
    **    (vtab1.col1 = tab2.col2)
    **
    ** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the 
    ** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is
    ** column iColRight of tab2.
    */
    static void addWhereTerm(
    Parse pParse,                   /* Parsing context */
    SrcList pSrc,                   /* List of tables in FROM clause */
    int iLeft,                      /* Index of first table to join in pSrc */
    int iColLeft,                   /* Index of column in first table */
    int iRight,                     /* Index of second table in pSrc */
    int iColRight,                  /* Index of column in second table */
    int isOuterJoin,                /* True if this is an OUTER join */
    ref Expr ppWhere                /* IN/OUT: The WHERE clause to add to */
    )
    {
      sqlite3 db = pParse.db;
      Expr pE1;
      Expr pE2;
      Expr pEq;

      Debug.Assert( iLeft < iRight );
      Debug.Assert( pSrc.nSrc > iRight );
      Debug.Assert( pSrc.a[iLeft].pTab != null );
      Debug.Assert( pSrc.a[iRight].pTab != null );

      pE1 = sqlite3CreateColumnExpr( db, pSrc, iLeft, iColLeft );
      pE2 = sqlite3CreateColumnExpr( db, pSrc, iRight, iColRight );

      pEq = sqlite3PExpr( pParse, TK_EQ, pE1, pE2, 0 );
      if ( pEq != null && isOuterJoin != 0 )
      {
        ExprSetProperty( pEq, EP_FromJoin );
        Debug.Assert( !ExprHasAnyProperty( pEq, EP_TokenOnly | EP_Reduced ) );
        ExprSetIrreducible( pEq );
        pEq.iRightJoinTable = (i16)pE2.iTable;
      }
      ppWhere = sqlite3ExprAnd( db, ppWhere, pEq );
    }
Example #35
0
    static void sqlite3Insert(
    Parse pParse,        /* Parser context */
    SrcList pTabList,    /* Name of table into which we are inserting */
    ExprList pList,      /* List of values to be inserted */
    Select pSelect,      /* A SELECT statement to use as the data source */
    IdList pColumn,      /* Column names corresponding to IDLIST. */
    int onError        /* How to handle constraint errors */
    )
    {
      sqlite3 db;           /* The main database structure */
      Table pTab;           /* The table to insert into.  aka TABLE */
      string zTab;          /* Name of the table into which we are inserting */
      string zDb;           /* Name of the database holding this table */
      int i = 0;
      int j = 0;
      int idx = 0;            /* Loop counters */
      Vdbe v;               /* Generate code into this virtual machine */
      Index pIdx;           /* For looping over indices of the table */
      int nColumn;          /* Number of columns in the data */
      int nHidden = 0;      /* Number of hidden columns if TABLE is virtual */
      int baseCur = 0;      /* VDBE VdbeCursor number for pTab */
      int keyColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
      int endOfLoop = 0;      /* Label for the end of the insertion loop */
      bool useTempTable = false; /* Store SELECT results in intermediate table */
      int srcTab = 0;       /* Data comes from this temporary cursor if >=0 */
      int addrInsTop = 0;   /* Jump to label "D" */
      int addrCont = 0;     /* Top of insert loop. Label "C" in templates 3 and 4 */
      int addrSelect = 0;   /* Address of coroutine that implements the SELECT */
      SelectDest dest;      /* Destination for SELECT on rhs of INSERT */
      int iDb;              /* Index of database holding TABLE */
      Db pDb;               /* The database containing table being inserted into */
      bool appendFlag = false;   /* True if the insert is likely to be an append */

      /* Register allocations */
      int regFromSelect = 0;  /* Base register for data coming from SELECT */
      int regAutoinc = 0;   /* Register holding the AUTOINCREMENT counter */
      int regRowCount = 0;  /* Memory cell used for the row counter */
      int regIns;           /* Block of regs holding rowid+data being inserted */
      int regRowid;         /* registers holding insert rowid */
      int regData;          /* register holding first column to insert */
      int regEof = 0;       /* Register recording end of SELECT data */
      int[] aRegIdx = null; /* One register allocated to each index */


#if !SQLITE_OMIT_TRIGGER
      bool isView = false;        /* True if attempting to insert into a view */
      Trigger pTrigger;           /* List of triggers on pTab, if required */
      int tmask = 0;              /* Mask of trigger times */
#endif

      db = pParse.db;
      dest = new SelectDest();// memset( &dest, 0, sizeof( dest ) );

      if ( pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
      {
        goto insert_cleanup;
      }

      /* Locate the table into which we will be inserting new information.
      */
      Debug.Assert( pTabList.nSrc == 1 );
      zTab = pTabList.a[0].zName;
      if ( NEVER( zTab == null ) )
        goto insert_cleanup;
      pTab = sqlite3SrcListLookup( pParse, pTabList );
      if ( pTab == null )
      {
        goto insert_cleanup;
      }
      iDb = sqlite3SchemaToIndex( db, pTab.pSchema );
      Debug.Assert( iDb < db.nDb );
      pDb = db.aDb[iDb];
      zDb = pDb.zName;
#if NO_SQLITE_OMIT_AUTHORIZATION //#if !SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab.zName, 0, zDb) ){
goto insert_cleanup;
}
#endif
      /* Figure out if we have any triggers and if the table being
** inserted into is a view
*/
#if !SQLITE_OMIT_TRIGGER
      pTrigger = sqlite3TriggersExist( pParse, pTab, TK_INSERT, null, out tmask );
      isView = pTab.pSelect != null;
#else
      Trigger pTrigger = null;  //# define pTrigger 0
      int tmask = 0;            //# define tmask 0
      bool isView = false;
#endif
#if  SQLITE_OMIT_VIEW
//# undef isView
isView = false;
#endif
#if !SQLITE_OMIT_TRIGGER
      Debug.Assert( ( pTrigger != null && tmask != 0 ) || ( pTrigger == null && tmask == 0 ) );
#endif

#if !SQLITE_OMIT_VIEW
      /* If pTab is really a view, make sure it has been initialized.
      ** ViewGetColumnNames() is a no-op if pTab is not a view (or virtual
      ** module table).
      */
      if ( sqlite3ViewGetColumnNames( pParse, pTab ) != -0 )
      {
        goto insert_cleanup;
      }
#endif

      /* Ensure that:
      *  (a) the table is not read-only, 
      *  (b) that if it is a view then ON INSERT triggers exist
      */
      if ( sqlite3IsReadOnly( pParse, pTab, tmask ) )
      {
        goto insert_cleanup;
      }

      /* Allocate a VDBE
      */
      v = sqlite3GetVdbe( pParse );
      if ( v == null )
        goto insert_cleanup;
      if ( pParse.nested == 0 )
        sqlite3VdbeCountChanges( v );
      sqlite3BeginWriteOperation( pParse, ( pSelect != null || pTrigger != null ) ? 1 : 0, iDb );

#if !SQLITE_OMIT_XFER_OPT
      /* If the statement is of the form
**
**       INSERT INTO <table1> SELECT * FROM <table2>;
**
** Then special optimizations can be applied that make the transfer
** very fast and which reduce fragmentation of indices.
**
** This is the 2nd template.
*/
      if ( pColumn == null && xferOptimization( pParse, pTab, pSelect, onError, iDb ) != 0 )
      {
        Debug.Assert( null == pTrigger );
        Debug.Assert( pList == null );
        goto insert_end;
      }
#endif // * SQLITE_OMIT_XFER_OPT */

      /* If this is an AUTOINCREMENT table, look up the sequence number in the
** sqlite_sequence table and store it in memory cell regAutoinc.
*/
      regAutoinc = autoIncBegin( pParse, iDb, pTab );

      /* Figure out how many columns of data are supplied.  If the data
      ** is coming from a SELECT statement, then generate a co-routine that
      ** produces a single row of the SELECT on each invocation.  The
      ** co-routine is the common header to the 3rd and 4th templates.
      */
      if ( pSelect != null )
      {
        /* Data is coming from a SELECT.  Generate code to implement that SELECT
        ** as a co-routine.  The code is common to both the 3rd and 4th
        ** templates:
        **
        **         EOF <- 0
        **         X <- A
        **         goto B
        **      A: setup for the SELECT
        **         loop over the tables in the SELECT
        **           load value into register R..R+n
        **           yield X
        **         end loop
        **         cleanup after the SELECT
        **         EOF <- 1
        **         yield X
        **         halt-error
        **
        ** On each invocation of the co-routine, it puts a single row of the
        ** SELECT result into registers dest.iMem...dest.iMem+dest.nMem-1.
        ** (These output registers are allocated by sqlite3Select().)  When
        ** the SELECT completes, it sets the EOF flag stored in regEof.
        */
        int rc = 0, j1;

        regEof = ++pParse.nMem;
        sqlite3VdbeAddOp2( v, OP_Integer, 0, regEof );      /* EOF <- 0 */
#if SQLITE_DEBUG
        VdbeComment( v, "SELECT eof flag" );
#endif
        sqlite3SelectDestInit( dest, SRT_Coroutine, ++pParse.nMem );
        addrSelect = sqlite3VdbeCurrentAddr( v ) + 2;
        sqlite3VdbeAddOp2( v, OP_Integer, addrSelect - 1, dest.iParm );
        j1 = sqlite3VdbeAddOp2( v, OP_Goto, 0, 0 );
#if SQLITE_DEBUG
        VdbeComment( v, "Jump over SELECT coroutine" );
#endif
        /* Resolve the expressions in the SELECT statement and execute it. */
        rc = sqlite3Select( pParse, pSelect, ref dest );
        Debug.Assert( pParse.nErr == 0 || rc != 0 );
        if ( rc != 0 || NEVER( pParse.nErr != 0 ) /*|| db.mallocFailed != 0 */ )
        {
          goto insert_cleanup;
        }
        sqlite3VdbeAddOp2( v, OP_Integer, 1, regEof );         /* EOF <- 1 */
        sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm );   /* yield X */
        sqlite3VdbeAddOp2( v, OP_Halt, SQLITE_INTERNAL, OE_Abort );
#if SQLITE_DEBUG
        VdbeComment( v, "End of SELECT coroutine" );
#endif
        sqlite3VdbeJumpHere( v, j1 );                          /* label B: */

        regFromSelect = dest.iMem;
        Debug.Assert( pSelect.pEList != null );
        nColumn = pSelect.pEList.nExpr;
        Debug.Assert( dest.nMem == nColumn );

        /* Set useTempTable to TRUE if the result of the SELECT statement
        ** should be written into a temporary table (template 4).  Set to
        ** FALSE if each* row of the SELECT can be written directly into
        ** the destination table (template 3).
        **
        ** A temp table must be used if the table being updated is also one
        ** of the tables being read by the SELECT statement.  Also use a
        ** temp table in the case of row triggers.
        */
        if ( pTrigger != null || readsTable( pParse, addrSelect, iDb, pTab ) )
        {
          useTempTable = true;
        }

        if ( useTempTable )
        {
          /* Invoke the coroutine to extract information from the SELECT
          ** and add it to a transient table srcTab.  The code generated
          ** here is from the 4th template:
          **
          **      B: open temp table
          **      L: yield X
          **         if EOF goto M
          **         insert row from R..R+n into temp table
          **         goto L
          **      M: ...
          */
          int regRec;      /* Register to hold packed record */
          int regTempRowid;    /* Register to hold temp table ROWID */
          int addrTop;     /* Label "L" */
          int addrIf;      /* Address of jump to M */

          srcTab = pParse.nTab++;
          regRec = sqlite3GetTempReg( pParse );
          regTempRowid = sqlite3GetTempReg( pParse );
          sqlite3VdbeAddOp2( v, OP_OpenEphemeral, srcTab, nColumn );
          addrTop = sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm );
          addrIf = sqlite3VdbeAddOp1( v, OP_If, regEof );
          sqlite3VdbeAddOp3( v, OP_MakeRecord, regFromSelect, nColumn, regRec );
          sqlite3VdbeAddOp2( v, OP_NewRowid, srcTab, regTempRowid );
          sqlite3VdbeAddOp3( v, OP_Insert, srcTab, regRec, regTempRowid );
          sqlite3VdbeAddOp2( v, OP_Goto, 0, addrTop );
          sqlite3VdbeJumpHere( v, addrIf );
          sqlite3ReleaseTempReg( pParse, regRec );
          sqlite3ReleaseTempReg( pParse, regTempRowid );
        }
      }
      else
      {
        /* This is the case if the data for the INSERT is coming from a VALUES
        ** clause
        */
        NameContext sNC;
        sNC = new NameContext();// memset( &sNC, 0, sNC ).Length;
        sNC.pParse = pParse;
        srcTab = -1;
        Debug.Assert( !useTempTable );
        nColumn = pList != null ? pList.nExpr : 0;
        for ( i = 0; i < nColumn; i++ )
        {
          if ( sqlite3ResolveExprNames( sNC, ref pList.a[i].pExpr ) != 0 )
          {
            goto insert_cleanup;
          }
        }
      }

      /* Make sure the number of columns in the source data matches the number
      ** of columns to be inserted into the table.
      */
      if ( IsVirtual( pTab ) )
      {
        for ( i = 0; i < pTab.nCol; i++ )
        {
          nHidden += ( IsHiddenColumn( pTab.aCol[i] ) ? 1 : 0 );
        }
      }
      if ( pColumn == null && nColumn != 0 && nColumn != ( pTab.nCol - nHidden ) )
      {
        sqlite3ErrorMsg( pParse,
        "table %S has %d columns but %d values were supplied",
        pTabList, 0, pTab.nCol - nHidden, nColumn );
        goto insert_cleanup;
      }
      if ( pColumn != null && nColumn != pColumn.nId )
      {
        sqlite3ErrorMsg( pParse, "%d values for %d columns", nColumn, pColumn.nId );
        goto insert_cleanup;
      }

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

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

      /* Initialize the count of rows to be inserted
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 )
      {
        regRowCount = ++pParse.nMem;
        sqlite3VdbeAddOp2( v, OP_Integer, 0, regRowCount );
      }

      /* If this is not a view, open the table and and all indices */
      if ( !isView )
      {
        int nIdx;

        baseCur = pParse.nTab;
        nIdx = sqlite3OpenTableAndIndices( pParse, pTab, baseCur, OP_OpenWrite );
        aRegIdx = new int[nIdx + 1];// sqlite3DbMallocRaw( db, sizeof( int ) * ( nIdx + 1 ) );
        if ( aRegIdx == null )
        {
          goto insert_cleanup;
        }
        for ( i = 0; i < nIdx; i++ )
        {
          aRegIdx[i] = ++pParse.nMem;
        }
      }

      /* This is the top of the main insertion loop */
      if ( useTempTable )
      {
        /* This block codes the top of loop only.  The complete loop is the
        ** following pseudocode (template 4):
        **
        **         rewind temp table
        **      C: loop over rows of intermediate table
        **           transfer values form intermediate table into <table>
        **         end loop
        **      D: ...
        */
        addrInsTop = sqlite3VdbeAddOp1( v, OP_Rewind, srcTab );
        addrCont = sqlite3VdbeCurrentAddr( v );
      }
      else if ( pSelect != null )
      {
        /* This block codes the top of loop only.  The complete loop is the
        ** following pseudocode (template 3):
        **
        **      C: yield X
        **         if EOF goto D
        **         insert the select result into <table> from R..R+n
        **         goto C
        **      D: ...
        */
        addrCont = sqlite3VdbeAddOp1( v, OP_Yield, dest.iParm );
        addrInsTop = sqlite3VdbeAddOp1( v, OP_If, regEof );
      }

      /* Allocate registers for holding the rowid of the new row,
      ** the content of the new row, and the assemblied row record.
      */
      regRowid = regIns = pParse.nMem + 1;
      pParse.nMem += pTab.nCol + 1;
      if ( IsVirtual( pTab ) )
      {
        regRowid++;
        pParse.nMem++;
      }
      regData = regRowid + 1;

      /* Run the BEFORE and INSTEAD OF triggers, if there are any
      */
      endOfLoop = sqlite3VdbeMakeLabel( v );
#if !SQLITE_OMIT_TRIGGER
      if ( ( tmask & TRIGGER_BEFORE ) != 0 )
      {
        int regCols = sqlite3GetTempRange( pParse, pTab.nCol + 1 );

        /* build the NEW.* reference row.  Note that if there is an INTEGER
        ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
        ** translated into a unique ID for the row.  But on a BEFORE trigger,
        ** we do not know what the unique ID will be (because the insert has
        ** not happened yet) so we substitute a rowid of -1
        */
        if ( keyColumn < 0 )
        {
          sqlite3VdbeAddOp2( v, OP_Integer, -1, regCols );
        }
        else
        {
          int j1;
          if ( useTempTable )
          {
            sqlite3VdbeAddOp3( v, OP_Column, srcTab, keyColumn, regCols );
          }
          else
          {
            Debug.Assert( pSelect == null );  /* Otherwise useTempTable is true */
            sqlite3ExprCode( pParse, pList.a[keyColumn].pExpr, regCols );
          }
          j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regCols );
          sqlite3VdbeAddOp2( v, OP_Integer, -1, regCols );
          sqlite3VdbeJumpHere( v, j1 );
          sqlite3VdbeAddOp1( v, OP_MustBeInt, regCols );
        }
        /* Cannot have triggers on a virtual table. If it were possible,
        ** this block would have to account for hidden column.
        */
        Debug.Assert( !IsVirtual( pTab ) );
        /* Create the new column data
        */
        for ( i = 0; i < pTab.nCol; i++ )
        {
          if ( pColumn == null )
          {
            j = i;
          }
          else
          {
            for ( j = 0; j < pColumn.nId; j++ )
            {
              if ( pColumn.a[j].idx == i )
                break;
            }
          }
          if ( ( !useTempTable && null == pList ) || ( pColumn != null && j >= pColumn.nId ) )
          {
            sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, regCols + i + 1 );
          }
          else if ( useTempTable )
          {
            sqlite3VdbeAddOp3( v, OP_Column, srcTab, j, regCols + i + 1 );
          }
          else
          {
            Debug.Assert( pSelect == null ); /* Otherwise useTempTable is true */
            sqlite3ExprCodeAndCache( pParse, pList.a[j].pExpr, regCols + i + 1 );
          }
        }

        /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
        ** do not attempt any conversions before assembling the record.
        ** If this is a real table, attempt conversions as required by the
        ** table column affinities.
        */
        if ( !isView )
        {
          sqlite3VdbeAddOp2( v, OP_Affinity, regCols + 1, pTab.nCol );
          sqlite3TableAffinityStr( v, pTab );
        }

        /* Fire BEFORE or INSTEAD OF triggers */
        sqlite3CodeRowTrigger( pParse, pTrigger, TK_INSERT, null, TRIGGER_BEFORE,
            pTab, regCols - pTab.nCol - 1, onError, endOfLoop );

        sqlite3ReleaseTempRange( pParse, regCols, pTab.nCol + 1 );
      }
#endif

      /* Push the record number for the new entry onto the stack.  The
** record number is a randomly generate integer created by NewRowid
** except when the table has an INTEGER PRIMARY KEY column, in which
** case the record number is the same as that column.
*/
      if ( !isView )
      {
        if ( IsVirtual( pTab ) )
        {
          /* The row that the VUpdate opcode will delete: none */
          sqlite3VdbeAddOp2( v, OP_Null, 0, regIns );
        }
        if ( keyColumn >= 0 )
        {
          if ( useTempTable )
          {
            sqlite3VdbeAddOp3( v, OP_Column, srcTab, keyColumn, regRowid );
          }
          else if ( pSelect != null )
          {
            sqlite3VdbeAddOp2( v, OP_SCopy, regFromSelect + keyColumn, regRowid );
          }
          else
          {
            VdbeOp pOp;
            sqlite3ExprCode( pParse, pList.a[keyColumn].pExpr, regRowid );
            pOp = sqlite3VdbeGetOp( v, -1 );
            if ( ALWAYS( pOp != null ) && pOp.opcode == OP_Null && !IsVirtual( pTab ) )
            {
              appendFlag = true;
              pOp.opcode = OP_NewRowid;
              pOp.p1 = baseCur;
              pOp.p2 = regRowid;
              pOp.p3 = regAutoinc;
            }
          }
          /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
          ** to generate a unique primary key value.
          */
          if ( !appendFlag )
          {
            int j1;
            if ( !IsVirtual( pTab ) )
            {
              j1 = sqlite3VdbeAddOp1( v, OP_NotNull, regRowid );
              sqlite3VdbeAddOp3( v, OP_NewRowid, baseCur, regRowid, regAutoinc );
              sqlite3VdbeJumpHere( v, j1 );
            }
            else
            {
              j1 = sqlite3VdbeCurrentAddr( v );
              sqlite3VdbeAddOp2( v, OP_IsNull, regRowid, j1 + 2 );
            }
            sqlite3VdbeAddOp1( v, OP_MustBeInt, regRowid );
          }
        }
        else if ( IsVirtual( pTab ) )
        {
          sqlite3VdbeAddOp2( v, OP_Null, 0, regRowid );
        }
        else
        {
          sqlite3VdbeAddOp3( v, OP_NewRowid, baseCur, regRowid, regAutoinc );
          appendFlag = true;
        }
        autoIncStep( pParse, regAutoinc, regRowid );

        /* Push onto the stack, data for all columns of the new entry, beginning
        ** with the first column.
        */
        nHidden = 0;
        for ( i = 0; i < pTab.nCol; i++ )
        {
          int iRegStore = regRowid + 1 + i;
          if ( i == pTab.iPKey )
          {
            /* The value of the INTEGER PRIMARY KEY column is always a NULL.
            ** Whenever this column is read, the record number will be substituted
            ** in its place.  So will fill this column with a NULL to avoid
            ** taking up data space with information that will never be used. */
            sqlite3VdbeAddOp2( v, OP_Null, 0, iRegStore );
            continue;
          }
          if ( pColumn == null )
          {
            if ( IsHiddenColumn( pTab.aCol[i] ) )
            {
              Debug.Assert( IsVirtual( pTab ) );
              j = -1;
              nHidden++;
            }
            else
            {
              j = i - nHidden;
            }
          }
          else
          {
            for ( j = 0; j < pColumn.nId; j++ )
            {
              if ( pColumn.a[j].idx == i )
                break;
            }
          }
          if ( j < 0 || nColumn == 0 || ( pColumn != null && j >= pColumn.nId ) )
          {
            sqlite3ExprCode( pParse, pTab.aCol[i].pDflt, iRegStore );
          }
          else if ( useTempTable )
          {
            sqlite3VdbeAddOp3( v, OP_Column, srcTab, j, iRegStore );
          }
          else if ( pSelect != null )
          {
            sqlite3VdbeAddOp2( v, OP_SCopy, regFromSelect + j, iRegStore );
          }
          else
          {
            sqlite3ExprCode( pParse, pList.a[j].pExpr, iRegStore );
          }
        }

        /* Generate code to check constraints and generate index keys and
        ** do the insertion.
        */
#if !SQLITE_OMIT_VIRTUALTABLE
        if ( IsVirtual( pTab ) )
        {
          VTable pVTab = sqlite3GetVTable( db, pTab );
          sqlite3VtabMakeWritable( pParse, pTab );
          sqlite3VdbeAddOp4( v, OP_VUpdate, 1, pTab.nCol + 2, regIns, pVTab, P4_VTAB );
          sqlite3VdbeChangeP5( v, (byte)( onError == OE_Default ? OE_Abort : onError ) );
          sqlite3MayAbort( pParse );
        }
        else
#endif
        {
          int isReplace = 0;    /* Set to true if constraints may cause a replace */
          sqlite3GenerateConstraintChecks( pParse, pTab, baseCur, regIns, aRegIdx,
            keyColumn >= 0 ? 1 : 0, false, onError, endOfLoop, out isReplace
          );
          sqlite3FkCheck( pParse, pTab, 0, regIns );
          sqlite3CompleteInsertion(
         pParse, pTab, baseCur, regIns, aRegIdx, false, appendFlag, isReplace == 0
          );
        }
      }

      /* Update the count of rows that are inserted
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 )
      {
        sqlite3VdbeAddOp2( v, OP_AddImm, regRowCount, 1 );
      }

#if !SQLITE_OMIT_TRIGGER
      if ( pTrigger != null )
      {
        /* Code AFTER triggers */
        sqlite3CodeRowTrigger( pParse, pTrigger, TK_INSERT, null, TRIGGER_AFTER,
            pTab, regData - 2 - pTab.nCol, onError, endOfLoop );
      }
#endif

      /* The bottom of the main insertion loop, if the data source
** is a SELECT statement.
*/
      sqlite3VdbeResolveLabel( v, endOfLoop );
      if ( useTempTable )
      {
        sqlite3VdbeAddOp2( v, OP_Next, srcTab, addrCont );
        sqlite3VdbeJumpHere( v, addrInsTop );
        sqlite3VdbeAddOp1( v, OP_Close, srcTab );
      }
      else if ( pSelect != null )
      {
        sqlite3VdbeAddOp2( v, OP_Goto, 0, addrCont );
        sqlite3VdbeJumpHere( v, addrInsTop );
      }

      if ( !IsVirtual( pTab ) && !isView )
      {
        /* Close all tables opened */
        sqlite3VdbeAddOp1( v, OP_Close, baseCur );
        for ( idx = 1, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, idx++ )
        {
          sqlite3VdbeAddOp1( v, OP_Close, idx + baseCur );
        }
      }

insert_end:
      /* Update the sqlite_sequence table by storing the content of the
      ** maximum rowid counter values recorded while inserting into
      ** autoincrement tables.
      */
      if ( pParse.nested == 0 && pParse.pTriggerTab == null )
      {
        sqlite3AutoincrementEnd( pParse );
      }

      /*
      ** Return the number of rows inserted. If this routine is
      ** generating code because of a call to sqlite3NestedParse(), do not
      ** invoke the callback function.
      */
      if ( ( db.flags & SQLITE_CountRows ) != 0 && 0 == pParse.nested && null == pParse.pTriggerTab )
      {
        sqlite3VdbeAddOp2( v, OP_ResultRow, regRowCount, 1 );
        sqlite3VdbeSetNumCols( v, 1 );
        sqlite3VdbeSetColName( v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC );
      }

insert_cleanup:
      sqlite3SrcListDelete( db, ref pTabList );
      sqlite3ExprListDelete( db, ref pList );
      sqlite3SelectDelete( db, ref pSelect );
      sqlite3IdListDelete( db, ref pColumn );
      sqlite3DbFree( db, ref aRegIdx );
    }
Example #36
0
 /*
 ** Allocate a new Select structure and return a pointer to that
 ** structure.
 */
 // OVERLOADS, so I don't need to rewrite parse.c
 static Select sqlite3SelectNew( Parse pParse, int null_2, SrcList pSrc, int null_4, int null_5, int null_6, int null_7, int isDistinct, int null_9, int null_10 )
 {
   return sqlite3SelectNew( pParse, null, pSrc, null, null, null, null, isDistinct, null, null );
 }
Example #37
0
/*
** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
** command.
*/
static void sqlite3AlterRenameTable(
Parse pParse,             /* Parser context. */
SrcList pSrc,             /* The table to rename. */
Token pName               /* The new table name. */
)
{
  int iDb;                  /* Database that contains the table */
  string zDb;               /* Name of database iDb */
  Table pTab;               /* Table being renamed */
  string zName = null;      /* NULL-terminated version of pName */
  sqlite3 db = pParse.db;   /* Database connection */
  int nTabName;             /* Number of UTF-8 characters in zTabName */
  string zTabName;          /* Original name of the table */
  Vdbe v;
#if !SQLITE_OMIT_TRIGGER
  string zWhere = "";       /* Where clause to locate temp triggers */
#endif
  VTable pVTab = null;      /* Non-zero if this is a v-tab with an xRename() */
  int savedDbFlags;         /* Saved value of db->flags */

  savedDbFlags = db.flags;

  //if ( NEVER( db.mallocFailed != 0 ) ) goto exit_rename_table;
  Debug.Assert( pSrc.nSrc == 1 );
  Debug.Assert( sqlite3BtreeHoldsAllMutexes( pParse.db ) );
  pTab = sqlite3LocateTable( pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase );
  if ( pTab == null )
    goto exit_rename_table;
  iDb = sqlite3SchemaToIndex( pParse.db, pTab.pSchema );
  zDb = db.aDb[iDb].zName;
  db.flags |= SQLITE_PreferBuiltin;

  /* Get a NULL terminated version of the new table name. */
  zName = sqlite3NameFromToken( db, pName );
  if ( zName == null )
    goto exit_rename_table;

  /* Check that a table or index named 'zName' does not already exist
  ** in database iDb. If so, this is an error.
  */
  if ( sqlite3FindTable( db, zName, zDb ) != null || sqlite3FindIndex( db, zName, zDb ) != null )
  {
    sqlite3ErrorMsg( pParse,
    "there is already another table or index with this name: %s", zName );
    goto exit_rename_table;
  }

  /* Make sure it is not a system table being altered, or a reserved name
  ** that the table is being renamed to.
  */
  if ( SQLITE_OK!=isSystemTable(pParse, pTab.zName) )
  {
    goto exit_rename_table;
  }
  if ( SQLITE_OK != sqlite3CheckObjectName( pParse, zName ) )
  {
    goto exit_rename_table;
  }

#if !SQLITE_OMIT_VIEW
  if ( pTab.pSelect != null )
  {
    sqlite3ErrorMsg( pParse, "view %s may not be altered", pTab.zName );
    goto exit_rename_table;
  }
#endif

#if !SQLITE_OMIT_AUTHORIZATION
/* Invoke the authorization callback. */
if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab.zName, 0) ){
goto exit_rename_table;
}
#endif

  if ( sqlite3ViewGetColumnNames( pParse, pTab ) != 0 )
  {
    goto exit_rename_table;
  }
#if !SQLITE_OMIT_VIRTUALTABLE
  if ( IsVirtual( pTab ) )
  {
    pVTab = sqlite3GetVTable( db, pTab );
    if ( pVTab.pVtab.pModule.xRename == null )
    {
      pVTab = null;
    }
  }
#endif
  /* Begin a transaction and code the VerifyCookie for database iDb.
** Then modify the schema cookie (since the ALTER TABLE modifies the
** schema). Open a statement transaction if the table is a virtual
** table.
*/
  v = sqlite3GetVdbe( pParse );
  if ( v == null )
  {
    goto exit_rename_table;
  }
  sqlite3BeginWriteOperation( pParse, pVTab != null ? 1 : 0, iDb );
  sqlite3ChangeCookie( pParse, iDb );

  /* If this is a virtual table, invoke the xRename() function if
  ** one is defined. The xRename() callback will modify the names
  ** of any resources used by the v-table implementation (including other
  ** SQLite tables) that are identified by the name of the virtual table.
  */
#if  !SQLITE_OMIT_VIRTUALTABLE
if ( pVTab !=null)
{
int i = ++pParse.nMem;
sqlite3VdbeAddOp4( v, OP_String8, 0, i, 0, zName, 0 );
sqlite3VdbeAddOp4( v, OP_VRename, i, 0, 0, pVTab, P4_VTAB );
sqlite3MayAbort(pParse);
}
#endif

  /* figure out how many UTF-8 characters are in zName */
  zTabName = pTab.zName;
  nTabName = sqlite3Utf8CharLen( zTabName, -1 );

#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
  if ( ( db.flags & SQLITE_ForeignKeys ) != 0 )
  {
    /* If foreign-key support is enabled, rewrite the CREATE TABLE 
    ** statements corresponding to all child tables of foreign key constraints
    ** for which the renamed table is the parent table.  */
    if ( ( zWhere = whereForeignKeys( pParse, pTab ) ) != null )
    {
      sqlite3NestedParse( pParse,
          "UPDATE \"%w\".%s SET " +
              "sql = sqlite_rename_parent(sql, %Q, %Q) " +
              "WHERE %s;", zDb, SCHEMA_TABLE( iDb ), zTabName, zName, zWhere );
      sqlite3DbFree( db, ref zWhere );
    }
  }
#endif

  /* Modify the sqlite_master table to use the new table name. */
  sqlite3NestedParse( pParse,
  "UPDATE %Q.%s SET " +
#if SQLITE_OMIT_TRIGGER
 "sql = sqlite_rename_table(sql, %Q), " +
#else
 "sql = CASE " +
  "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)" +
  "ELSE sqlite_rename_table(sql, %Q) END, " +
#endif
 "tbl_name = %Q, " +
  "name = CASE " +
  "WHEN type='table' THEN %Q " +
  "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN " +
  "'sqlite_autoindex_' || %Q || substr(name,%d+18) " +
  "ELSE name END " +
  "WHERE tbl_name=%Q AND " +
  "(type='table' OR type='index' OR type='trigger');",
  zDb, SCHEMA_TABLE( iDb ), zName, zName, zName,
#if !SQLITE_OMIT_TRIGGER
 zName,
#endif
 zName, nTabName, zTabName
  );

#if !SQLITE_OMIT_AUTOINCREMENT
  /* If the sqlite_sequence table exists in this database, then update
** it with the new table name.
*/
  if ( sqlite3FindTable( db, "sqlite_sequence", zDb ) != null )
  {
    sqlite3NestedParse( pParse,
    "UPDATE \"%w\".sqlite_sequence set name = %Q WHERE name = %Q",
    zDb, zName, pTab.zName
    );
  }
#endif

#if !SQLITE_OMIT_TRIGGER
  /* If there are TEMP triggers on this table, modify the sqlite_temp_master
** table. Don't do this if the table being ALTERed is itself located in
** the temp database.
*/
  if ( ( zWhere = whereTempTriggers( pParse, pTab ) ) != "" )
  {
    sqlite3NestedParse( pParse,
    "UPDATE sqlite_temp_master SET " +
    "sql = sqlite_rename_trigger(sql, %Q), " +
    "tbl_name = %Q " +
    "WHERE %s;", zName, zName, zWhere );
    sqlite3DbFree( db, ref zWhere );
  }
#endif

#if !(SQLITE_OMIT_FOREIGN_KEY) && !(SQLITE_OMIT_TRIGGER)
  if ( ( db.flags & SQLITE_ForeignKeys ) != 0 )
  {
    FKey p;
    for ( p = sqlite3FkReferences( pTab ); p != null; p = p.pNextTo )
    {
      Table pFrom = p.pFrom;
      if ( pFrom != pTab )
      {
        reloadTableSchema( pParse, p.pFrom, pFrom.zName );
      }
    }
  }
#endif

  /* Drop and reload the internal table schema. */
  reloadTableSchema( pParse, pTab, zName );

exit_rename_table:
  sqlite3SrcListDelete( db, ref pSrc );
  sqlite3DbFree( db, ref zName );
  db.flags = savedDbFlags;
}
Example #38
0
    /*
    ** This is called by the parser when it sees a CREATE TRIGGER statement
    ** up to the point of the BEGIN before the trigger actions.  A Trigger
    ** structure is generated based on the information available and stored
    ** in pParse.pNewTrigger.  After the trigger actions have been parsed, the
    ** sqlite3FinishTrigger() function is called to complete the trigger
    ** construction process.
    */
    static void sqlite3BeginTrigger(
    Parse pParse,      /* The parse context of the CREATE TRIGGER statement */
    Token pName1,      /* The name of the trigger */
    Token pName2,      /* The name of the trigger */
    int tr_tm,         /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
    int op,             /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
    IdList pColumns,   /* column list if this is an UPDATE OF trigger */
    SrcList pTableName,/* The name of the table/view the trigger applies to */
    Expr pWhen,        /* WHEN clause */
    int isTemp,        /* True if the TEMPORARY keyword is present */
    int noErr          /* Suppress errors if the trigger already exists */
    )
    {
      Trigger pTrigger = null;      /* The new trigger */
      Table pTab;                   /* Table that the trigger fires off of */
      string zName = null;          /* Name of the trigger */
      sqlite3 db = pParse.db;       /* The database connection */
      int iDb;                      /* The database to store the trigger in */
      Token pName = null;           /* The unqualified db name */
      DbFixer sFix = new DbFixer(); /* State vector for the DB fixer */
      int iTabDb;                   /* Index of the database holding pTab */

      Debug.Assert( pName1 != null );   /* pName1.z might be NULL, but not pName1 itself */
      Debug.Assert( pName2 != null );
      Debug.Assert( op == TK_INSERT || op == TK_UPDATE || op == TK_DELETE );
      Debug.Assert( op > 0 && op < 0xff );
      if ( isTemp != 0 )
      {
        /* If TEMP was specified, then the trigger name may not be qualified. */
        if ( pName2.n > 0 )
        {
          sqlite3ErrorMsg( pParse, "temporary trigger may not have qualified name" );
          goto trigger_cleanup;
        }
        iDb = 1;
        pName = pName1;
      }
      else
      {
        /* Figure out the db that the the trigger will be created in */
        iDb = sqlite3TwoPartName( pParse, pName1, pName2, ref pName );
        if ( iDb < 0 )
        {
          goto trigger_cleanup;
        }
      }
      if ( null == pTableName ) //|| db.mallocFailed 
      {
        goto trigger_cleanup;
      }

      /* A long-standing parser bug is that this syntax was allowed:
      **
      **    CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab ....
      **                                                 ^^^^^^^^
      **
      ** To maintain backwards compatibility, ignore the database
      ** name on pTableName if we are reparsing our of SQLITE_MASTER.
      */
      if ( db.init.busy != 0 && iDb != 1 )
      {
        //sqlite3DbFree( db, pTableName.a[0].zDatabase );
        pTableName.a[0].zDatabase = null;
      }

      /* If the trigger name was unqualified, and the table is a temp table,
      ** then set iDb to 1 to create the trigger in the temporary database.
      ** If sqlite3SrcListLookup() returns 0, indicating the table does not
      ** exist, the error is caught by the block below.
      */
      if ( pTableName == null /*|| db.mallocFailed != 0 */ )
      {
        goto trigger_cleanup;
      }
      pTab = sqlite3SrcListLookup( pParse, pTableName );
      if ( db.init.busy == 0 && pName2.n == 0 && pTab != null
            && pTab.pSchema == db.aDb[1].pSchema )
      {
        iDb = 1;
      }

      /* Ensure the table name matches database name and that the table exists */
      //      if ( db.mallocFailed != 0 ) goto trigger_cleanup;
      Debug.Assert( pTableName.nSrc == 1 );
      if ( sqlite3FixInit( sFix, pParse, iDb, "trigger", pName ) != 0 &&
      sqlite3FixSrcList( sFix, pTableName ) != 0 )
      {
        goto trigger_cleanup;
      }
      pTab = sqlite3SrcListLookup( pParse, pTableName );
      if ( pTab == null )
      {
        /* The table does not exist. */
        if ( db.init.iDb == 1 )
        {
          /* Ticket #3810.
          ** Normally, whenever a table is dropped, all associated triggers are
          ** dropped too.  But if a TEMP trigger is created on a non-TEMP table
          ** and the table is dropped by a different database connection, the
          ** trigger is not visible to the database connection that does the
          ** drop so the trigger cannot be dropped.  This results in an
          ** "orphaned trigger" - a trigger whose associated table is missing.
          */
          db.init.orphanTrigger = 1;
        }
        goto trigger_cleanup;
      }
      if ( IsVirtual( pTab ) )
      {
        sqlite3ErrorMsg( pParse, "cannot create triggers on virtual tables" );
        goto trigger_cleanup;
      }

      /* Check that the trigger name is not reserved and that no trigger of the
      ** specified name exists */
      zName = sqlite3NameFromToken( db, pName );
      if ( zName == null || SQLITE_OK != sqlite3CheckObjectName( pParse, zName ) )
      {
        goto trigger_cleanup;
      }
      Debug.Assert( sqlite3SchemaMutexHeld( db, iDb, null ) );
      if ( sqlite3HashFind( ( db.aDb[iDb].pSchema.trigHash ),
      zName, sqlite3Strlen30( zName ), (Trigger)null ) != null )
      {
        if ( noErr == 0 )
        {
          sqlite3ErrorMsg( pParse, "trigger %T already exists", pName );
        }
        else
        {
          Debug.Assert( 0==db.init.busy );
          sqlite3CodeVerifySchema( pParse, iDb );
        }
        goto trigger_cleanup;
      }

      /* Do not create a trigger on a system table */
      if ( pTab.zName.StartsWith( "sqlite_", System.StringComparison.InvariantCultureIgnoreCase ) )
      {
        sqlite3ErrorMsg( pParse, "cannot create trigger on system table" );
        pParse.nErr++;
        goto trigger_cleanup;
      }

      /* INSTEAD of triggers are only for views and views only support INSTEAD
      ** of triggers.
      */
      if ( pTab.pSelect != null && tr_tm != TK_INSTEAD )
      {
        sqlite3ErrorMsg( pParse, "cannot create %s trigger on view: %S",
        ( tr_tm == TK_BEFORE ) ? "BEFORE" : "AFTER", pTableName, 0 );
        goto trigger_cleanup;
      }
      if ( pTab.pSelect == null && tr_tm == TK_INSTEAD )
      {
        sqlite3ErrorMsg( pParse, "cannot create INSTEAD OF" +
        " trigger on table: %S", pTableName, 0 );
        goto trigger_cleanup;
      }
      iTabDb = sqlite3SchemaToIndex( db, pTab.pSchema );

#if !SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_CREATE_TRIGGER;
string zDb = db.aDb[iTabDb].zName;
string zDbTrig = isTemp ? db.aDb[1].zName : zDb;
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab.zName, zDbTrig) ){
goto trigger_cleanup;
}
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iTabDb),0,zDb)){
goto trigger_cleanup;
}
}
#endif

      /* INSTEAD OF triggers can only appear on views and BEFORE triggers
** cannot appear on views.  So we might as well translate every
** INSTEAD OF trigger into a BEFORE trigger.  It simplifies code
** elsewhere.
*/
      if ( tr_tm == TK_INSTEAD )
      {
        tr_tm = TK_BEFORE;
      }

      /* Build the Trigger object */
      pTrigger = new Trigger();// (Trigger*)sqlite3DbMallocZero( db, sizeof(Trigger ))
      if ( pTrigger == null )
        goto trigger_cleanup;
      pTrigger.zName = zName;
      pTrigger.table = pTableName.a[0].zName;// sqlite3DbStrDup( db, pTableName.a[0].zName );
      pTrigger.pSchema = db.aDb[iDb].pSchema;
      pTrigger.pTabSchema = pTab.pSchema;
      pTrigger.op = (u8)op;
      pTrigger.tr_tm = tr_tm == TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
      pTrigger.pWhen = sqlite3ExprDup( db, pWhen, EXPRDUP_REDUCE );
      pTrigger.pColumns = sqlite3IdListDup( db, pColumns );
      Debug.Assert( pParse.pNewTrigger == null );
      pParse.pNewTrigger = pTrigger;

trigger_cleanup:
      sqlite3DbFree( db, ref zName );
      sqlite3SrcListDelete( db, ref pTableName );
      sqlite3IdListDelete( db, ref pColumns );
      sqlite3ExprDelete( db, ref pWhen );
      if ( pParse.pNewTrigger == null )
      {
        sqlite3DeleteTrigger( db, ref pTrigger );
      }
      else
      {
        Debug.Assert( pParse.pNewTrigger == pTrigger );
      }
    }
Example #39
0
/*
** This function is called by the parser after the table-name in
** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
** pSrc is the full-name of the table being altered.
**
** This routine makes a (partial) copy of the Table structure
** for the table being altered and sets Parse.pNewTable to point
** to it. Routines called by the parser as the column definition
** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
** the copy. The copy of the Table structure is deleted by tokenize.c
** after parsing is finished.
**
** Routine sqlite3AlterFinishAddColumn() will be called to complete
** coding the "ALTER TABLE ... ADD" statement.
*/
static void sqlite3AlterBeginAddColumn( Parse pParse, SrcList pSrc )
{
  Table pNew;
  Table pTab;
  Vdbe v;
  int iDb;
  int i;
  int nAlloc;
  sqlite3 db = pParse.db;

  /* Look up the table being altered. */
  Debug.Assert( pParse.pNewTable == null );
  Debug.Assert( sqlite3BtreeHoldsAllMutexes( db ) );
  //      if ( db.mallocFailed != 0 ) goto exit_begin_add_column;
  pTab = sqlite3LocateTable( pParse, 0, pSrc.a[0].zName, pSrc.a[0].zDatabase );
  if ( pTab == null )
    goto exit_begin_add_column;

  if ( IsVirtual( pTab ) )
  {
    sqlite3ErrorMsg( pParse, "virtual tables may not be altered" );
    goto exit_begin_add_column;
  }

  /* Make sure this is not an attempt to ALTER a view. */
  if ( pTab.pSelect != null )
  {
    sqlite3ErrorMsg( pParse, "Cannot add a column to a view" );
    goto exit_begin_add_column;
  }
  if ( SQLITE_OK != isSystemTable( pParse, pTab.zName ) )
  {
    goto exit_begin_add_column;
  }

  Debug.Assert( pTab.addColOffset > 0 );
  iDb = sqlite3SchemaToIndex( db, pTab.pSchema );

  /* Put a copy of the Table struct in Parse.pNewTable for the
  ** sqlite3AddColumn() function and friends to modify.  But modify
  ** the name by adding an "sqlite_altertab_" prefix.  By adding this
  ** prefix, we insure that the name will not collide with an existing
  ** table because user table are not allowed to have the "sqlite_"
  ** prefix on their name.
  */
  pNew = new Table();// (Table*)sqlite3DbMallocZero( db, sizeof(Table))
  if ( pNew == null )
    goto exit_begin_add_column;
  pParse.pNewTable = pNew;
  pNew.nRef = 1;
  pNew.nCol = pTab.nCol;
  Debug.Assert( pNew.nCol > 0 );
  nAlloc = ( ( ( pNew.nCol - 1 ) / 8 ) * 8 ) + 8;
  Debug.Assert( nAlloc >= pNew.nCol && nAlloc % 8 == 0 && nAlloc - pNew.nCol < 8 );
  pNew.aCol = new Column[nAlloc];// (Column*)sqlite3DbMallocZero( db, sizeof(Column) * nAlloc );
  pNew.zName = sqlite3MPrintf( db, "sqlite_altertab_%s", pTab.zName );
  if ( pNew.aCol == null || pNew.zName == null )
  {
    //        db.mallocFailed = 1;
    goto exit_begin_add_column;
  }
  // memcpy( pNew.aCol, pTab.aCol, sizeof(Column) * pNew.nCol );
  for ( i = 0; i < pNew.nCol; i++ )
  {
    Column pCol = pTab.aCol[i].Copy();
    // sqlite3DbStrDup( db, pCol.zName );
    pCol.zColl = null;
    pCol.zType = null;
    pCol.pDflt = null;
    pCol.zDflt = null;
    pNew.aCol[i] = pCol;
  }
  pNew.pSchema = db.aDb[iDb].pSchema;
  pNew.addColOffset = pTab.addColOffset;
  pNew.nRef = 1;

  /* Begin a transaction and increment the schema cookie.  */
  sqlite3BeginWriteOperation( pParse, 0, iDb );
  v = sqlite3GetVdbe( pParse );
  if ( v == null )
    goto exit_begin_add_column;
  sqlite3ChangeCookie( pParse, iDb );

exit_begin_add_column:
  sqlite3SrcListDelete( db, ref pSrc );
  return;
}
Example #40
0
		/*
		** Process an UPDATE statement.
		**
		**   UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
		**          \_______/ \________/     \______/       \________________/
		*            onError   pTabList      pChanges             pWhere
		*/
		static void sqlite3Update(
		Parse pParse,         /* The parser context */
		SrcList pTabList,     /* The table in which we should change things */
		ExprList pChanges,    /* Things to be changed */
		Expr pWhere,          /* The WHERE clause.  May be null */
		int onError           /* How to handle constraint errors */
		)
		{
			int i, j;                   /* Loop counters */
			Table pTab;                 /* The table to be updated */
			int addr = 0;               /* VDBE instruction address of the start of the loop */
			WhereInfo pWInfo;           /* Information about the WHERE clause */
			Vdbe v;                     /* The virtual database engine */
			Index pIdx;                 /* For looping over indices */
			int nIdx;                   /* Number of indices that need updating */
			int iCur;                   /* VDBE Cursor number of pTab */
			sqlite3 db;                 /* The database structure */
			int[] aRegIdx = null;       /* One register assigned to each index to be updated */
			int[] aXRef = null;         /* aXRef[i] is the index in pChanges.a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
			bool chngRowid;             /* True if the record number is being changed */
			Expr pRowidExpr = null;     /* Expression defining the new record number */
			bool openAll = false;       /* True if all indices need to be opened */
			AuthContext sContext;       /* The authorization context */
			NameContext sNC;            /* The name-context to resolve expressions in */
			int iDb;                    /* Database containing the table being updated */
			bool okOnePass;             /* True for one-pass algorithm without the FIFO */
			bool hasFK;                 /* True if foreign key processing is required */

#if !SQLITE_OMIT_TRIGGER
			bool isView;            /* True when updating a view (INSTEAD OF trigger) */
			Trigger pTrigger;      /* List of triggers on pTab, if required */
			int tmask = 0;         /* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
#endif
			int newmask;           /* Mask of NEW.* columns accessed by BEFORE triggers */

			/* Register Allocations */
			int regRowCount = 0;         /* A count of rows changed */
			int regOldRowid;             /* The old rowid */
			int regNewRowid;             /* The new rowid */
			int regNew;
			int regOld = 0;
			int regRowSet = 0;           /* Rowset of rows to be updated */

			sContext = new AuthContext(); //memset( &sContext, 0, sizeof( sContext ) );
			db = pParse.db;
			if (pParse.nErr != 0 /*|| db.mallocFailed != 0 */ )
			{
				goto update_cleanup;
			}
			Debug.Assert(pTabList.nSrc == 1);

			/* Locate the table which we want to update.
			*/
			pTab = sqlite3SrcListLookup(pParse, pTabList);
			if (pTab == null)
				goto update_cleanup;
			iDb = sqlite3SchemaToIndex(pParse.db, pTab.pSchema);

			/* Figure out if we have any triggers and if the table being
			** updated is a view.
			*/
#if !SQLITE_OMIT_TRIGGER
			pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, out tmask);
			isView = pTab.pSelect != null;
			Debug.Assert(pTrigger != null || tmask == 0);
#else
	  const Trigger pTrigger = null;//# define pTrigger 0
	  const int tmask = 0;          //# define tmask 0
#endif
#if SQLITE_OMIT_TRIGGER || SQLITE_OMIT_VIEW
//    # undef isView
	  const bool isView = false;    //# define isView 0
#endif

			if (sqlite3ViewGetColumnNames(pParse, pTab) != 0)
			{
				goto update_cleanup;
			}
			if (sqlite3IsReadOnly(pParse, pTab, tmask))
			{
				goto update_cleanup;
			}
			aXRef = new int[pTab.nCol];// sqlite3DbMallocRaw(db, sizeof(int) * pTab.nCol);
			//if ( aXRef == null ) goto update_cleanup;
			for (i = 0; i < pTab.nCol; i++)
				aXRef[i] = -1;

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

			/* Initialize the name-context */
			sNC = new NameContext();// memset(&sNC, 0, sNC).Length;
			sNC.pParse = pParse;
			sNC.pSrcList = pTabList;

			/* Resolve the column names in all the expressions of the
			** of the UPDATE statement.  Also find the column index
			** for each column to be updated in the pChanges array.  For each
			** column to be updated, make sure we have authorization to change
			** that column.
			*/
			chngRowid = false;
			for (i = 0; i < pChanges.nExpr; i++)
			{
				if (sqlite3ResolveExprNames(sNC, ref pChanges.a[i].pExpr) != 0)
				{
					goto update_cleanup;
				}
				for (j = 0; j < pTab.nCol; j++)
				{
					if (pTab.aCol[j].zName.Equals(pChanges.a[i].zName, StringComparison.InvariantCultureIgnoreCase))
					{
						if (j == pTab.iPKey)
						{
							chngRowid = true;
							pRowidExpr = pChanges.a[i].pExpr;
						}
						aXRef[j] = i;
						break;
					}
				}
				if (j >= pTab.nCol)
				{
					if (sqlite3IsRowid(pChanges.a[i].zName))
					{
						chngRowid = true;
						pRowidExpr = pChanges.a[i].pExpr;
					}
					else
					{
						sqlite3ErrorMsg(pParse, "no such column: %s", pChanges.a[i].zName);
						pParse.checkSchema = 1;
						goto update_cleanup;
					}
				}
#if !SQLITE_OMIT_AUTHORIZATION
{
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab.zName,
pTab.aCol[j].zName, db.aDb[iDb].zName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
aXRef[j] = -1;
}
}
#endif
			}

			hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngRowid ? 1 : 0) != 0;

			/* Allocate memory for the array aRegIdx[].  There is one entry in the
			** array for each index associated with table being updated.  Fill in
			** the value with a register number for indices that are to be used
			** and with zero for unused indices.
			*/
			for (nIdx = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, nIdx++)
			{
			}
			if (nIdx > 0)
			{
				aRegIdx = new int[nIdx]; // sqlite3DbMallocRaw(db, Index*.Length * nIdx);
				if (aRegIdx == null)
					goto update_cleanup;
			}
			for (j = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, j++)
			{
				int reg;
				if (hasFK || chngRowid)
				{
					reg = ++pParse.nMem;
				}
				else
				{
					reg = 0;
					for (i = 0; i < pIdx.nColumn; i++)
					{
						if (aXRef[pIdx.aiColumn[i]] >= 0)
						{
							reg = ++pParse.nMem;
							break;
						}
					}
				}
				aRegIdx[j] = reg;
			}

			/* Begin generating code. */
			v = sqlite3GetVdbe(pParse);
			if (v == null)
				goto update_cleanup;
			if (pParse.nested == 0)
				sqlite3VdbeCountChanges(v);
			sqlite3BeginWriteOperation(pParse, 1, iDb);

#if !SQLITE_OMIT_VIRTUALTABLE
			/* Virtual tables must be handled separately */
			if (IsVirtual(pTab))
			{
				updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
								   pWhere, onError);
				pWhere = null;
				pTabList = null;
				goto update_cleanup;
			}
#endif

			/* Allocate required registers. */
			regOldRowid = regNewRowid = ++pParse.nMem;
			if (pTrigger != null || hasFK)
			{
				regOld = pParse.nMem + 1;
				pParse.nMem += pTab.nCol;
			}
			if (chngRowid || pTrigger != null || hasFK)
			{
				regNewRowid = ++pParse.nMem;
			}
			regNew = pParse.nMem + 1;
			pParse.nMem += pTab.nCol;

			/* Start the view context. */
			if (isView)
			{
				sqlite3AuthContextPush(pParse, sContext, pTab.zName);
			}

			/* If we are trying to update a view, realize that view into
			** a ephemeral table.
			*/
#if !(SQLITE_OMIT_VIEW) && !(SQLITE_OMIT_TRIGGER)
			if (isView)
			{
				sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
			}
#endif

			/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
			if (sqlite3ResolveExprNames(sNC, ref pWhere) != 0)
			{
				goto update_cleanup;
			}

			/* Begin the database scan
			*/
			sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
			ExprList NullOrderby = null;
			pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, ref NullOrderby, WHERE_ONEPASS_DESIRED);
			if (pWInfo == null)
				goto update_cleanup;
			okOnePass = pWInfo.okOnePass != 0;

			/* Remember the rowid of every item to be updated.
			*/
			sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regOldRowid);
			if (!okOnePass)
			{
				regRowSet = ++pParse.nMem;
				sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
			}

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

			/* Initialize the count of updated rows
			*/
			if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
			{
				regRowCount = ++pParse.nMem;
				sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
			}

			if (!isView)
			{
				/*
				** Open every index that needs updating.  Note that if any
				** index could potentially invoke a REPLACE conflict resolution
				** action, then we need to open all indices because we might need
				** to be deleting some records.
				*/
				if (!okOnePass)
					sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
				if (onError == OE_Replace)
				{
					openAll = true;
				}
				else
				{
					openAll = false;
					for (pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext)
					{
						if (pIdx.onError == OE_Replace)
						{
							openAll = true;
							break;
						}
					}
				}
				for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
				{
					if (openAll || aRegIdx[i] > 0)
					{
						KeyInfo pKey = sqlite3IndexKeyinfo(pParse, pIdx);
						sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur + i + 1, pIdx.tnum, iDb,
						pKey, P4_KEYINFO_HANDOFF);
						Debug.Assert(pParse.nTab > iCur + i + 1);
					}
				}
			}

			/* Top of the update loop */
			if (okOnePass)
			{
				int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid);
				addr = sqlite3VdbeAddOp0(v, OP_Goto);
				sqlite3VdbeJumpHere(v, a1);
			}
			else
			{
				addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid);
			}

			/* Make cursor iCur point to the record that is being updated. If
			** this record does not exist for some reason (deleted by a trigger,
			** for example, then jump to the next iteration of the RowSet loop.  */
			sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);

			/* If the record number will change, set register regNewRowid to
			** contain the new value. If the record number is not being modified,
			** then regNewRowid is the same register as regOldRowid, which is
			** already populated.  */
			Debug.Assert(chngRowid || pTrigger != null || hasFK || regOldRowid == regNewRowid);
			if (chngRowid)
			{
				sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
				sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid);
			}

			/* If there are triggers on this table, populate an array of registers 
			** with the required old.* column data.  */
			if (hasFK || pTrigger != null)
			{
				u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
				oldmask |= sqlite3TriggerColmask(pParse,
					pTrigger, pChanges, 0, TRIGGER_BEFORE | TRIGGER_AFTER, pTab, onError
				);
				for (i = 0; i < pTab.nCol; i++)
				{
					if (aXRef[i] < 0 || oldmask == 0xffffffff || (i < 32 && 0 != (oldmask & (1 << i))))
					{
						sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld + i);
					}
					else
					{
						sqlite3VdbeAddOp2(v, OP_Null, 0, regOld + i);
					}
				}
				if (chngRowid == false)
				{
					sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
				}
			}

			/* Populate the array of registers beginning at regNew with the new
			** row data. This array is used to check constaints, create the new
			** table and index records, and as the values for any new.* references
			** made by triggers.
			**
			** If there are one or more BEFORE triggers, then do not populate the
			** registers associated with columns that are (a) not modified by
			** this UPDATE statement and (b) not accessed by new.* references. The
			** values for registers not modified by the UPDATE must be reloaded from 
			** the database after the BEFORE triggers are fired anyway (as the trigger 
			** may have modified them). So not loading those that are not going to
			** be used eliminates some redundant opcodes.
			*/
			newmask = (int)sqlite3TriggerColmask(
				pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
			);
			for (i = 0; i < pTab.nCol; i++)
			{
				if (i == pTab.iPKey)
				{
					sqlite3VdbeAddOp2(v, OP_Null, 0, regNew + i);
				}
				else
				{
					j = aXRef[i];
					if (j >= 0)
					{
						sqlite3ExprCode(pParse, pChanges.a[j].pExpr, regNew + i);
					}
					else if (0 == (tmask & TRIGGER_BEFORE) || i > 31 || (newmask & (1 << i)) != 0)
					{
						/* This branch loads the value of a column that will not be changed 
						** into a register. This is done if there are no BEFORE triggers, or
						** if there are one or more BEFORE triggers that use this value via
						** a new.* reference in a trigger program.
						*/
						testcase(i == 31);
						testcase(i == 32);
						sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
						sqlite3ColumnDefault(v, pTab, i, regNew + i);
					}
				}
			}

			/* Fire any BEFORE UPDATE triggers. This happens before constraints are
			** verified. One could argue that this is wrong.
			*/
			if ((tmask & TRIGGER_BEFORE) != 0)
			{
				sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab.nCol);
				sqlite3TableAffinityStr(v, pTab);
				sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
					TRIGGER_BEFORE, pTab, regOldRowid, onError, addr);

				/* The row-trigger may have deleted the row being updated. In this
				** case, jump to the next row. No updates or AFTER triggers are 
				** required. This behaviour - what happens when the row being updated
				** is deleted or renamed by a BEFORE trigger - is left undefined in the
				** documentation.
				*/
				sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid);

				/* If it did not delete it, the row-trigger may still have modified 
				** some of the columns of the row being updated. Load the values for 
				** all columns not modified by the update statement into their 
				** registers in case this has happened.
				*/
				for (i = 0; i < pTab.nCol; i++)
				{
					if (aXRef[i] < 0 && i != pTab.iPKey)
					{
						sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew + i);
						sqlite3ColumnDefault(v, pTab, i, regNew + i);
					}
				}
			}

			if (!isView)
			{
				int j1;                       /* Address of jump instruction */

				/* Do constraint checks. */
				int iDummy;
				sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
					  aRegIdx, (chngRowid ? regOldRowid : 0), true, onError, addr, out iDummy);

				/* Do FK constraint checks. */
				if (hasFK)
				{
					sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
				}

				/* Delete the index entries associated with the current record.  */
				j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
				sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);

				/* If changing the record number, delete the old record.  */
				if (hasFK || chngRowid)
				{
					sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0);
				}
				sqlite3VdbeJumpHere(v, j1);

				if (hasFK)
				{
					sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
				}

				/* Insert the new index entries and the new record. */
				sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, true, false, false);

				/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
				** handle rows (possibly in other tables) that refer via a foreign key
				** to the row just updated. */
				if (hasFK)
				{
					sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
				}
			}

			/* Increment the row counter 
			*/
			if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab)
			{
				sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
			}

			sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
				TRIGGER_AFTER, pTab, regOldRowid, onError, addr);

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

			/* Close all tables */
			for (i = 0, pIdx = pTab.pIndex; pIdx != null; pIdx = pIdx.pNext, i++)
			{
				if (openAll || aRegIdx[i] > 0)
				{
					sqlite3VdbeAddOp2(v, OP_Close, iCur + i + 1, 0);
				}
			}
			sqlite3VdbeAddOp2(v, OP_Close, iCur, 0);

			/* Update the sqlite_sequence table by storing the content of the
			** maximum rowid counter values recorded while inserting into
			** autoincrement tables.
			*/
			if (pParse.nested == 0 && pParse.pTriggerTab == null)
			{
				sqlite3AutoincrementEnd(pParse);
			}

			/*
			** Return the number of rows that were changed. If this routine is 
			** generating code because of a call to sqlite3NestedParse(), do not
			** invoke the callback function.
			*/
			if ((db.flags & SQLITE_CountRows) != 0 && null == pParse.pTriggerTab && 0 == pParse.nested)
			{
				sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
				sqlite3VdbeSetNumCols(v, 1);
				sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
			}

		update_cleanup:
#if !SQLITE_OMIT_AUTHORIZATION
sqlite3AuthContextPop(sContext);
#endif
			sqlite3DbFree(db, ref aRegIdx);
			sqlite3DbFree(db, ref aXRef);
			sqlite3SrcListDelete(db, ref pTabList);
			sqlite3ExprListDelete(db, ref pChanges);
			sqlite3ExprDelete(db, ref pWhere);
			return;
		}
Example #41
0
 /*
 ** Allocate and return a pointer to an expression to load the column iCol
 ** from datasource iSrc in SrcList pSrc.
 */
 static Expr sqlite3CreateColumnExpr( sqlite3 db, SrcList pSrc, int iSrc, int iCol )
 {
   Expr p = sqlite3ExprAlloc( db, TK_COLUMN, null, 0 );
   if ( p != null )
   {
     SrcList_item pItem = pSrc.a[iSrc];
     p.pTab = pItem.pTab;
     p.iTable = pItem.iCursor;
     if ( p.pTab.iPKey == iCol )
     {
       p.iColumn = -1;
     }
     else
     {
       p.iColumn = (ynVar)iCol;
       testcase( iCol == BMS );
       testcase( iCol == BMS - 1 );
       pItem.colUsed |= ( (Bitmask)1 ) << ( iCol >= BMS ? BMS - 1 : iCol );
     }
     ExprSetProperty( p, EP_Resolved );
   }
   return p;
 }
Example #42
0
/*
** Generate code for an UPDATE of a virtual table.
**
** The strategy is that we create an ephemerial table that contains
** for each row to be changed:
**
**   (A)  The original rowid of that row.
**   (B)  The revised rowid for the row. (note1)
**   (C)  The content of every column in the row.
**
** Then we loop over this ephemeral table and for each row in
** the ephermeral table call VUpdate.
**
** When finished, drop the ephemeral table.
**
** (note1) Actually, if we know in advance that (A) is always the same
** as (B) we only store (A), then duplicate (A) when pulling
** it out of the ephemeral table before calling VUpdate.
*/
static void updateVirtualTable(
Parse pParse,       /* The parsing context */
SrcList pSrc,       /* The virtual table to be modified */
Table pTab,         /* The virtual table */
ExprList pChanges,  /* The columns to change in the UPDATE statement */
Expr pRowid,        /* Expression used to recompute the rowid */
int aXRef,          /* Mapping from columns of pTab to entries in pChanges */
Expr pWhere         /* WHERE clause of the UPDATE statement */
)
{
Vdbe v = pParse.pVdbe;  /* Virtual machine under construction */
ExprList pEList = 0;     /* The result set of the SELECT statement */
Select pSelect = 0;      /* The SELECT statement */
Expr pExpr;              /* Temporary expression */
int ephemTab;             /* Table holding the result of the SELECT */
int i;                    /* Loop counter */
int addr;                 /* Address of top of loop */
int iReg;                 /* First register in set passed to OP_VUpdate */
sqlite3 db = pParse.db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
SelectDest dest;

/* Construct the SELECT statement that will find the new values for
** all updated rows.
*/
pEList = sqlite3ExprListAppend(pParse, 0,
sqlite3CreateIdExpr(pParse, "_rowid_"));
if( pRowid ){
pEList = sqlite3ExprListAppend(pParse, pEList,
sqlite3ExprDup(db, pRowid,0), 0);
}
Debug.Assert( pTab.iPKey<0 );
for(i=0; i<pTab.nCol; i++){
if( aXRef[i]>=0 ){
pExpr = sqlite3ExprDup(db, pChanges.a[aXRef[i]].pExpr,0);
}else{
pExpr = sqlite3CreateIdExpr(pParse, pTab.aCol[i].zName);
}
pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
}
pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);

/* Create the ephemeral table into which the update results will
** be stored.
*/
Debug.Assert( v );
ephemTab = pParse.nTab++;
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab.nCol+1+(pRowid!=0));

/* fill the ephemeral table
*/
sqlite3SelectDestInit(dest, SRT_Table, ephemTab);
sqlite3Select(pParse, pSelect, ref dest);

/* Generate code to scan the ephemeral table and call VUpdate. */
iReg = ++pParse.nMem;
pParse.nMem += pTab.nCol+1;
addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0);
sqlite3VdbeAddOp3(v, OP_Column,  ephemTab, 0, iReg);
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid
1:0), iReg+1);
for(i=0; i<pTab.nCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
}
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab.nCol+2, iReg, pVTab, P4_VTAB);
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

/* Cleanup */
sqlite3SelectDelete(pSelect);
}
Example #43
0
        public static void BeginTrigger(Parse parse, Token name1, Token name2, TK trTm, TK op, IdList columns, SrcList tableName, Expr when, bool isTemp, int noErr)
        {
            Context ctx = parse.Ctx;     // The database connection

            Debug.Assert(name1 != null); // pName1.z might be NULL, but not pName1 itself
            Debug.Assert(name2 != null);
            Debug.Assert(op == TK.INSERT || op == TK.UPDATE || op == TK.DELETE);
            Debug.Assert(op > 0 && op < (TK)0xff);
            Trigger trigger = null; // The new trigger

            int   db;               // The database to store the trigger in
            Token name = null;      // The unqualified db name

            if (isTemp)
            {
                // If TEMP was specified, then the trigger name may not be qualified.
                if (name2.length > 0)
                {
                    parse.ErrorMsg("temporary trigger may not have qualified name");
                    goto trigger_cleanup;
                }
                db   = 1;
                name = name1;
            }
            else
            {
                // Figure out the db that the the trigger will be created in
                db = parse.TwoPartName(name1, name2, ref name);
                if (db < 0)
                {
                    goto trigger_cleanup;
                }
            }
            if (tableName == null || ctx.MallocFailed)
            {
                goto trigger_cleanup;
            }

            // A long-standing parser bug is that this syntax was allowed:
            //    CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab ....
            //                                                 ^^^^^^^^
            // To maintain backwards compatibility, ignore the database name on pTableName if we are reparsing our of SQLITE_MASTER.
            if (ctx.Init.Busy && db != 1)
            {
                C._tagfree(ctx, ref tableName.Ids[0].Database);
                tableName.Ids[0].Database = null;
            }

            // If the trigger name was unqualified, and the table is a temp table, then set iDb to 1 to create the trigger in the temporary database.
            // If sqlite3SrcListLookup() returns 0, indicating the table does not exist, the error is caught by the block below.
            //? if (tableName == null) goto trigger_cleanup;
            Table table = Delete.SrcListLookup(parse, tableName); // Table that the trigger fires off of

            if (ctx.Init.Busy == null && name2.length == 0 && table != null && table.Schema == ctx.DBs[1].Schema)
            {
                db = 1;
            }

            // Ensure the table name matches database name and that the table exists
            if (ctx.MallocFailed)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(tableName.Srcs == 1);
            DbFixer sFix = new DbFixer(); // State vector for the DB fixer

            if (sFix.FixInit(parse, db, "trigger", name) && sFix.FixSrcList(tableName))
            {
                goto trigger_cleanup;
            }
            table = Delete.SrcListLookup(parse, tableName);
            if (table == null)
            {
                // The table does not exist.
                if (ctx.Init.DB == 1)
                {
                    // Ticket #3810.
                    // Normally, whenever a table is dropped, all associated triggers are dropped too.  But if a TEMP trigger is created on a non-TEMP table
                    // and the table is dropped by a different database connection, the trigger is not visible to the database connection that does the
                    // drop so the trigger cannot be dropped.  This results in an "orphaned trigger" - a trigger whose associated table is missing.
                    ctx.Init.OrphanTrigger = true;
                }
                goto trigger_cleanup;
            }
            if (E.IsVirtual(table))
            {
                parse.ErrorMsg("cannot create triggers on virtual tables");
                goto trigger_cleanup;
            }

            // Check that the trigger name is not reserved and that no trigger of the specified name exists
            string nameAsString = Parse.NameFromToken(ctx, name);

            if (nameAsString == null || parse.CheckObjectName(nameAsString) != RC.OK)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
            if (ctx.DBs[db].Schema.TriggerHash.Find(nameAsString, nameAsString.Length, (Trigger)null) != null)
            {
                if (noErr == 0)
                {
                    parse.ErrorMsg("trigger %T already exists", name);
                }
                else
                {
                    Debug.Assert(!ctx.Init.Busy);
                    parse.CodeVerifySchema(db);
                }
                goto trigger_cleanup;
            }

            // Do not create a trigger on a system table
            if (table.Name.StartsWith("sqlite_", StringComparison.InvariantCultureIgnoreCase))
            {
                parse.ErrorMsg("cannot create trigger on system table");
                parse.Errs++;
                goto trigger_cleanup;
            }

            // INSTEAD of triggers are only for views and views only support INSTEAD of triggers.
            if (table.Select != null && trTm != TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create %s trigger on view: %S", (trTm == TK.BEFORE ? "BEFORE" : "AFTER"), tableName, 0);
                goto trigger_cleanup;
            }
            if (table.Select == null && trTm == TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create INSTEAD OF trigger on table: %S", tableName, 0);
                goto trigger_cleanup;
            }

#if !OMIT_AUTHORIZATION
            {
                int    tabDb      = Prepare.SchemaToIndex(ctx, table.Schema); // Index of the database holding pTab
                AUTH   code       = AUTH.CREATE_TRIGGER;
                string dbName     = ctx.DBs[tabDb].Name;
                string dbTrigName = (isTemp ? ctx.DBs[1].Name : dbName);
                if (tabDb == 1 || isTemp)
                {
                    code = AUTH.CREATE_TEMP_TRIGGER;
                }
                if (Auth.Check(parse, code, nameAsString, table.Name, dbTrigName) != 0 || Auth.Check(parse, AUTH.INSERT, E.SCHEMA_TABLE(tabDb), 0, dbName))
                {
                    goto trigger_cleanup;
                }
            }
#endif

            // INSTEAD OF triggers can only appear on views and BEFORE triggers cannot appear on views.  So we might as well translate every
            // INSTEAD OF trigger into a BEFORE trigger.  It simplifies code elsewhere.
            if (trTm == TK.INSTEAD)
            {
                trTm = TK.BEFORE;
            }

            // Build the Trigger object
            trigger = new Trigger(); //: (Trigger *)_tagalloc(db, sizeof(Trigger), true);
            if (trigger == null)
            {
                goto trigger_cleanup;
            }
            trigger.Name      = name;
            trigger.Table     = tableName.Ids[0].Name; //: _tagstrdup(ctx, tableName->Ids[0].Name);
            trigger.Schema    = ctx.DBs[db].Schema;
            trigger.TabSchema = table.Schema;
            trigger.OP        = op;
            trigger.TRtm      = (trTm == TK.BEFORE ? TRIGGER.BEFORE : TRIGGER.AFTER);
            trigger.When      = Expr.Dup(db, when, E.EXPRDUP_REDUCE);
            trigger.Columns   = Expr.IdListDup(ctx, columns);
            Debug.Assert(parse.NewTrigger == null);
            parse.NewTrigger = trigger;

trigger_cleanup:
            C._tagfree(ctx, ref name);
            Expr.SrcListDelete(ctx, ref tableName);
            Expr.IdListDelete(ctx, ref columns);
            Expr.Delete(ctx, ref when);
            if (parse.NewTrigger == null)
            {
                DeleteTrigger(ctx, ref trigger);
            }
            else
            {
                Debug.Assert(parse.NewTrigger == trigger);
            }
        }