Exemplo n.º 1
0
        public static void MaterializeView(Parse parse, Table view, Expr where_, int curId)
        {
            Context ctx = parse.Ctx;
            int db = Prepare.SchemaToIndex(ctx, view.Schema);

            where_ = Expr.Dup(ctx, where_, 0);
            SrcList from = Parse.SrcListAppend(ctx, null, null, null);

            if (from != null)
            {
                Debug.Assert(from.Srcs == 1);
                from.Ids[0].Name = view.Name;
                from.Ids[0].Database = ctx.DBs[db].Name;
                Debug.Assert(from.Ids[0].On == null);
                Debug.Assert(from.Ids[0].Using == null);
            }

            Select select = Select.New(parse, 0, from, where_, 0, 0, 0, 0, 0, 0);
            if (select != null) select.SelFlags |= SF.Materialize;

            SelectDest dest = new SelectDest();
            Select.DestInit(dest, SRT.EphemTab, curId);
            Select.Select(parse, select, dest);
            Select.Delete(ctx, select);
        }
Exemplo n.º 2
0
 /*
 ** Initialize a SelectDest structure.
 */
 static void sqlite3SelectDestInit( SelectDest pDest, int eDest, int iParm )
 {
   pDest.eDest = (u8)eDest;
   pDest.iParm = iParm;
   pDest.affinity = '\0';
   pDest.iMem = 0;
   pDest.nMem = 0;
 }
Exemplo n.º 3
0
 static void DestInit(SelectDest dest, SRT dest2, int parmId)
 {
     dest.Dest = dest2;
     dest.SDParmId = parmId;
     dest.AffSdst = '\0';
     dest.SdstId = 0;
     dest.Sdsts = 0;
 }
Exemplo n.º 4
0
        static void UpdateVirtualTable(Parse parse, SrcList src, Table table, ExprList changes, Expr rowid, int[] xrefs, Expr where_, int onError)
        {
            int        i;
            Context    ctx    = parse.Ctx; // Database connection
            VTable     vtable = VTable.GetVTable(ctx, table);
            SelectDest dest   = new SelectDest();

            // Construct the SELECT statement that will find the new values for all updated rows.
            ExprList list = ExprList.Append(parse, 0, Expr.Expr(ctx, TK.ID, "_rowid_")); // The result set of the SELECT statement

            if (rowid != null)
            {
                list = ExprList.Append(parse, list, Expr.Dup(ctx, rowid, 0));
            }
            Debug.Assert(table.PKey < 0);
            for (i = 0; i < table.Cols.length; i++)
            {
                Expr expr = (xrefs[i] >= 0 ? Expr.Dup(ctx, changes.Ids[xrefs[i]].Expr, 0) : Expr.Expr(ctx, TK.ID, table.Cols[i].Name)); // Temporary expression
                list = ExprList.Append(parse, list, expr);
            }
            Select select = Select.New(parse, list, src, where_, null, null, null, 0, null, null); // The SELECT statement

            // Create the ephemeral table into which the update results will be stored.
            Vdbe v = parse.V; // Virtual machine under construction

            Debug.Assert(v != null);
            int ephemTab = parse.Tabs++; // Table holding the result of the SELECT

            v.AddOp2(OP.OpenEphemeral, ephemTab, table.Cols.length + 1 + (rowid != null ? 1 : 0));
            v.ChangeP5(BTREE_UNORDERED);

            // fill the ephemeral table
            Select.DestInit(dest, SRT.Table, ephemTab);
            Select.Select(parse, select, ref dest);

            // Generate code to scan the ephemeral table and call VUpdate.
            int regId = ++parse.Mems;// First register in set passed to OP_VUpdate

            parse.Mems += table.Cols.length + 1;
            int addr = v.AddOp2(OP.Rewind, ephemTab, 0); // Address of top of loop

            v.AddOp3(OP.Column, ephemTab, 0, regId);
            v.AddOp3(OP.Column, ephemTab, (rowid != null ? 1 : 0), regId + 1);
            for (i = 0; i < table.nCol; i++)
            {
                v.AddOp3(OP.Column, ephemTab, i + 1 + (rowid != null ? 1 : 0), regId + 2 + i);
            }
            sqlite3VtabMakeWritable(parse, table);
            v.AddOp4(OP_VUpdate, 0, table.Cols.length + 2, regId, vtable, P4_VTAB);
            v.ChangeP5((byte)(onError == OE_Default ? OE_Abort : onError));
            parse.MayAbort();
            v.AddOp2(OP.Next, ephemTab, addr + 1);
            v.JumpHere(addr);
            v.AddOp2(OP.Close, ephemTab, 0);

            // Cleanup
            Select.Delete(ctx, ref select);
        }
Exemplo n.º 5
0
        /*
        ** Evaluate a view and store its result in an ephemeral table.  The
        ** pWhere argument is an optional WHERE clause that restricts the
        ** set of rows in the view that are to be added to the ephemeral table.
        */
        private static void sqlite3MaterializeView(
            Parse pParse, /* Parsing context */
            Table pView,  /* View definition */
            Expr pWhere,  /* Optional WHERE clause to be added */
            int iCur      /* VdbeCursor number for ephemerial table */
            )
        {
            var    dest = new SelectDest();
            Select pDup;
            var    db = pParse.db;

            pDup = sqlite3SelectDup(db, pView.pSelect, 0);
            if (pWhere != null)
            {
                SrcList pFrom;

                pWhere = sqlite3ExprDup(db, pWhere, 0);
                pFrom  = sqlite3SrcListAppend(db, null, null, null);
                //if ( pFrom != null )
                //{
                Debug.Assert(pFrom.nSrc == 1);
                pFrom.a[0].zAlias  = pView.zName; // sqlite3DbStrDup( db, pView.zName );
                pFrom.a[0].pSelect = pDup;
                Debug.Assert(pFrom.a[0].pOn == null);
                Debug.Assert(pFrom.a[0].pUsing == null);
                //}
                //else
                //{
                //  sqlite3SelectDelete( db, ref pDup );
                //}
                pDup = sqlite3SelectNew(pParse, null, pFrom, pWhere, null, null, null, 0, null, null);
            }

            sqlite3SelectDestInit(dest, SRT_EphemTab, iCur);
            sqlite3Select(pParse, pDup, ref dest);
            sqlite3SelectDelete(db, ref pDup);
        }
Exemplo n.º 6
0
    /*
    ** Alternative compound select code generator for cases when there
    ** is an ORDER BY clause.
    **
    ** We assume a query of the following form:
    **
    **      <selectA>  <operator>  <selectB>  ORDER BY <orderbylist>
    **
    ** <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT.  The idea
    ** is to code both <selectA> and <selectB> with the ORDER BY clause as
    ** co-routines.  Then run the co-routines in parallel and merge the results
    ** into the output.  In addition to the two coroutines (called selectA and
    ** selectB) there are 7 subroutines:
    **
    **    outA:    Move the output of the selectA coroutine into the output
    **             of the compound query.
    **
    **    outB:    Move the output of the selectB coroutine into the output
    **             of the compound query.  (Only generated for UNION and
    **             UNION ALL.  EXCEPT and INSERTSECT never output a row that
    **             appears only in B.)
    **
    **    AltB:    Called when there is data from both coroutines and A<B.
    **
    **    AeqB:    Called when there is data from both coroutines and A==B.
    **
    **    AgtB:    Called when there is data from both coroutines and A>B.
    **
    **    EofA:    Called when data is exhausted from selectA.
    **
    **    EofB:    Called when data is exhausted from selectB.
    **
    ** The implementation of the latter five subroutines depend on which
    ** <operator> is used:
    **
    **
    **             UNION ALL         UNION            EXCEPT          INTERSECT
    **          -------------  -----------------  --------------  -----------------
    **   AltB:   outA, nextA      outA, nextA       outA, nextA         nextA
    **
    **   AeqB:   outA, nextA         nextA             nextA         outA, nextA
    **
    **   AgtB:   outB, nextB      outB, nextB          nextB            nextB
    **
    **   EofA:   outB, nextB      outB, nextB          halt             halt
    **
    **   EofB:   outA, nextA      outA, nextA       outA, nextA         halt
    **
    ** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA
    ** causes an immediate jump to EofA and an EOF on B following nextB causes
    ** an immediate jump to EofB.  Within EofA and EofB, and EOF on entry or
    ** following nextX causes a jump to the end of the select processing.
    **
    ** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled
    ** within the output subroutine.  The regPrev register set holds the previously
    ** output value.  A comparison is made against this value and the output
    ** is skipped if the next results would be the same as the previous.
    **
    ** The implementation plan is to implement the two coroutines and seven
    ** subroutines first, then put the control logic at the bottom.  Like this:
    **
    **          goto Init
    **     coA: coroutine for left query (A)
    **     coB: coroutine for right query (B)
    **    outA: output one row of A
    **    outB: output one row of B (UNION and UNION ALL only)
    **    EofA: ...
    **    EofB: ...
    **    AltB: ...
    **    AeqB: ...
    **    AgtB: ...
    **    Init: initialize coroutine registers
    **          yield coA
    **          if eof(A) goto EofA
    **          yield coB
    **          if eof(B) goto EofB
    **    Cmpr: Compare A, B
    **          Jump AltB, AeqB, AgtB
    **     End: ...
    **
    ** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
    ** actually called using Gosub and they do not Return.  EofA and EofB loop
    ** until all data is exhausted then jump to the "end" labe.  AltB, AeqB,
    ** and AgtB jump to either L2 or to one of EofA or EofB.
    */
#if !SQLITE_OMIT_COMPOUND_SELECT
    static int multiSelectOrderBy(
    Parse pParse,         /* Parsing context */
    Select p,             /* The right-most of SELECTs to be coded */
    SelectDest pDest      /* What to do with query results */
    )
    {
      int i, j;             /* Loop counters */
      Select pPrior;        /* Another SELECT immediately to our left */
      Vdbe v;               /* Generate code to this VDBE */
      SelectDest destA = new SelectDest();     /* Destination for coroutine A */
      SelectDest destB = new SelectDest();     /* Destination for coroutine B */
      int regAddrA;         /* Address register for select-A coroutine */
      int regEofA;          /* Flag to indicate when select-A is complete */
      int regAddrB;         /* Address register for select-B coroutine */
      int regEofB;          /* Flag to indicate when select-B is complete */
      int addrSelectA;      /* Address of the select-A coroutine */
      int addrSelectB;      /* Address of the select-B coroutine */
      int regOutA;          /* Address register for the output-A subroutine */
      int regOutB;          /* Address register for the output-B subroutine */
      int addrOutA;         /* Address of the output-A subroutine */
      int addrOutB = 0;     /* Address of the output-B subroutine */
      int addrEofA;         /* Address of the select-A-exhausted subroutine */
      int addrEofB;         /* Address of the select-B-exhausted subroutine */
      int addrAltB;         /* Address of the A<B subroutine */
      int addrAeqB;         /* Address of the A==B subroutine */
      int addrAgtB;         /* Address of the A>B subroutine */
      int regLimitA;        /* Limit register for select-A */
      int regLimitB;        /* Limit register for select-A */
      int regPrev;          /* A range of registers to hold previous output */
      int savedLimit;       /* Saved value of p.iLimit */
      int savedOffset;      /* Saved value of p.iOffset */
      int labelCmpr;        /* Label for the start of the merge algorithm */
      int labelEnd;         /* Label for the end of the overall SELECT stmt */
      int j1;               /* Jump instructions that get retargetted */
      int op;               /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
      KeyInfo pKeyDup = null;      /* Comparison information for duplicate removal */
      KeyInfo pKeyMerge;    /* Comparison information for merging rows */
      sqlite3 db;           /* Database connection */
      ExprList pOrderBy;    /* The ORDER BY clause */
      int nOrderBy;         /* Number of terms in the ORDER BY clause */
      int[] aPermute;       /* Mapping from ORDER BY terms to result set columns */
#if !SQLITE_OMIT_EXPLAIN
      int iSub1 = 0;            /* EQP id of left-hand query */
      int iSub2 = 0;            /* EQP id of right-hand query */
#endif

      Debug.Assert( p.pOrderBy != null );
      Debug.Assert( pKeyDup == null ); /* "Managed" code needs this.  Ticket #3382. */
      db = pParse.db;
      v = pParse.pVdbe;
      Debug.Assert( v != null );       /* Already thrown the error if VDBE alloc failed */
      labelEnd = sqlite3VdbeMakeLabel( v );
      labelCmpr = sqlite3VdbeMakeLabel( v );


      /* Patch up the ORDER BY clause
      */
      op = p.op;
      pPrior = p.pPrior;
      Debug.Assert( pPrior.pOrderBy == null );
      pOrderBy = p.pOrderBy;
      Debug.Assert( pOrderBy != null );
      nOrderBy = pOrderBy.nExpr;

      /* For operators other than UNION ALL we have to make sure that
      ** the ORDER BY clause covers every term of the result set.  Add
      ** terms to the ORDER BY clause as necessary.
      */
      if ( op != TK_ALL )
      {
        for ( i = 1; /* db.mallocFailed == 0 && */ i <= p.pEList.nExpr; i++ )
        {
          ExprList_item pItem;
          for ( j = 0; j < nOrderBy; j++ )//, pItem++)
          {
            pItem = pOrderBy.a[j];
            Debug.Assert( pItem.iCol > 0 );
            if ( pItem.iCol == i )
              break;
          }
          if ( j == nOrderBy )
          {
            Expr pNew = sqlite3Expr( db, TK_INTEGER, null );
            //if ( pNew == null )
            //  return SQLITE_NOMEM;
            pNew.flags |= EP_IntValue;
            pNew.u.iValue = i;
            pOrderBy = sqlite3ExprListAppend( pParse, pOrderBy, pNew );
            pOrderBy.a[nOrderBy++].iCol = (u16)i;
          }
        }
      }

      /* Compute the comparison permutation and keyinfo that is used with
      ** the permutation used to determine if the next
      ** row of results comes from selectA or selectB.  Also add explicit
      ** collations to the ORDER BY clause terms so that when the subqueries
      ** to the right and the left are evaluated, they use the correct
      ** collation.
      */
      aPermute = new int[nOrderBy];// sqlite3DbMallocRaw( db, sizeof( int ) * nOrderBy );
      if ( aPermute != null )
      {
        ExprList_item pItem;
        for ( i = 0; i < nOrderBy; i++ )//, pItem++)
        {
          pItem = pOrderBy.a[i];
          Debug.Assert( pItem.iCol > 0 && pItem.iCol <= p.pEList.nExpr );
          aPermute[i] = pItem.iCol - 1;
        }
        pKeyMerge = new KeyInfo();//      sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq)+1));
        if ( pKeyMerge != null )
        {
          pKeyMerge.aColl = new CollSeq[nOrderBy];
          pKeyMerge.aSortOrder = new byte[nOrderBy];//(u8)&pKeyMerge.aColl[nOrderBy];
          pKeyMerge.nField = (u16)nOrderBy;
          pKeyMerge.enc = ENC( db );
          for ( i = 0; i < nOrderBy; i++ )
          {
            CollSeq pColl;
            Expr pTerm = pOrderBy.a[i].pExpr;
            if ( ( pTerm.flags & EP_ExpCollate ) != 0 )
            {
              pColl = pTerm.pColl;
            }
            else
            {
              pColl = multiSelectCollSeq( pParse, p, aPermute[i] );
              pTerm.flags |= EP_ExpCollate;
              pTerm.pColl = pColl;
            }
            pKeyMerge.aColl[i] = pColl;
            pKeyMerge.aSortOrder[i] = (byte)pOrderBy.a[i].sortOrder;
          }
        }
      }
      else
      {
        pKeyMerge = null;
      }

      /* Reattach the ORDER BY clause to the query.
      */
      p.pOrderBy = pOrderBy;
      pPrior.pOrderBy = sqlite3ExprListDup( pParse.db, pOrderBy, 0 );

      /* Allocate a range of temporary registers and the KeyInfo needed
      ** for the logic that removes duplicate result rows when the
      ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
      */
      if ( op == TK_ALL )
      {
        regPrev = 0;
      }
      else
      {
        int nExpr = p.pEList.nExpr;
        Debug.Assert( nOrderBy >= nExpr /*|| db.mallocFailed != 0 */ );
        regPrev = sqlite3GetTempRange( pParse, nExpr + 1 );
        sqlite3VdbeAddOp2( v, OP_Integer, 0, regPrev );
        pKeyDup = new KeyInfo();//sqlite3DbMallocZero(db,
        //sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq)+1) );
        if ( pKeyDup != null )
        {
          pKeyDup.aColl = new CollSeq[nExpr];
          pKeyDup.aSortOrder = new byte[nExpr];//(u8)&pKeyDup.aColl[nExpr];
          pKeyDup.nField = (u16)nExpr;
          pKeyDup.enc = ENC( db );
          for ( i = 0; i < nExpr; i++ )
          {
            pKeyDup.aColl[i] = multiSelectCollSeq( pParse, p, i );
            pKeyDup.aSortOrder[i] = 0;
          }
        }
      }

      /* Separate the left and the right query from one another
      */
      p.pPrior = null;
      sqlite3ResolveOrderGroupBy( pParse, p, p.pOrderBy, "ORDER" );
      if ( pPrior.pPrior == null )
      {
        sqlite3ResolveOrderGroupBy( pParse, pPrior, pPrior.pOrderBy, "ORDER" );
      }

      /* Compute the limit registers */
      computeLimitRegisters( pParse, p, labelEnd );
      if ( p.iLimit != 0 && op == TK_ALL )
      {
        regLimitA = ++pParse.nMem;
        regLimitB = ++pParse.nMem;
        sqlite3VdbeAddOp2( v, OP_Copy, ( p.iOffset != 0 ) ? p.iOffset + 1 : p.iLimit,
        regLimitA );
        sqlite3VdbeAddOp2( v, OP_Copy, regLimitA, regLimitB );
      }
      else
      {
        regLimitA = regLimitB = 0;
      }
      sqlite3ExprDelete( db, ref p.pLimit );
      p.pLimit = null;
      sqlite3ExprDelete( db, ref p.pOffset );
      p.pOffset = null;

      regAddrA = ++pParse.nMem;
      regEofA = ++pParse.nMem;
      regAddrB = ++pParse.nMem;
      regEofB = ++pParse.nMem;
      regOutA = ++pParse.nMem;
      regOutB = ++pParse.nMem;
      sqlite3SelectDestInit( destA, SRT_Coroutine, regAddrA );
      sqlite3SelectDestInit( destB, SRT_Coroutine, regAddrB );

      /* Jump past the various subroutines and coroutines to the main
      ** merge loop
      */
      j1 = sqlite3VdbeAddOp0( v, OP_Goto );
      addrSelectA = sqlite3VdbeCurrentAddr( v );


      /* Generate a coroutine to evaluate the SELECT statement to the
      ** left of the compound operator - the "A" select.
      */
      VdbeNoopComment( v, "Begin coroutine for left SELECT" );
      pPrior.iLimit = regLimitA;
      explainSetInteger( ref iSub1, pParse.iNextSelectId );
      sqlite3Select( pParse, pPrior, ref destA );
      sqlite3VdbeAddOp2( v, OP_Integer, 1, regEofA );
      sqlite3VdbeAddOp1( v, OP_Yield, regAddrA );
      VdbeNoopComment( v, "End coroutine for left SELECT" );

      /* Generate a coroutine to evaluate the SELECT statement on
      ** the right - the "B" select
      */
      addrSelectB = sqlite3VdbeCurrentAddr( v );
      VdbeNoopComment( v, "Begin coroutine for right SELECT" );
      savedLimit = p.iLimit;
      savedOffset = p.iOffset;
      p.iLimit = regLimitB;
      p.iOffset = 0;
      explainSetInteger( ref iSub2, pParse.iNextSelectId );
      sqlite3Select( pParse, p, ref destB );
      p.iLimit = savedLimit;
      p.iOffset = savedOffset;
      sqlite3VdbeAddOp2( v, OP_Integer, 1, regEofB );
      sqlite3VdbeAddOp1( v, OP_Yield, regAddrB );
      VdbeNoopComment( v, "End coroutine for right SELECT" );

      /* Generate a subroutine that outputs the current row of the A
      ** select as the next output row of the compound select.
      */
      VdbeNoopComment( v, "Output routine for A" );
      addrOutA = generateOutputSubroutine( pParse,
      p, destA, pDest, regOutA,
      regPrev, pKeyDup, P4_KEYINFO_HANDOFF, labelEnd );

      /* Generate a subroutine that outputs the current row of the B
      ** select as the next output row of the compound select.
      */
      if ( op == TK_ALL || op == TK_UNION )
      {
        VdbeNoopComment( v, "Output routine for B" );
        addrOutB = generateOutputSubroutine( pParse,
        p, destB, pDest, regOutB,
        regPrev, pKeyDup, P4_KEYINFO_STATIC, labelEnd );
      }

      /* Generate a subroutine to run when the results from select A
      ** are exhausted and only data in select B remains.
      */
      VdbeNoopComment( v, "eof-A subroutine" );
      if ( op == TK_EXCEPT || op == TK_INTERSECT )
      {
        addrEofA = sqlite3VdbeAddOp2( v, OP_Goto, 0, labelEnd );
      }
      else
      {
        addrEofA = sqlite3VdbeAddOp2( v, OP_If, regEofB, labelEnd );
        sqlite3VdbeAddOp2( v, OP_Gosub, regOutB, addrOutB );
        sqlite3VdbeAddOp1( v, OP_Yield, regAddrB );
        sqlite3VdbeAddOp2( v, OP_Goto, 0, addrEofA );
        p.nSelectRow += pPrior.nSelectRow;
      }

      /* Generate a subroutine to run when the results from select B
      ** are exhausted and only data in select A remains.
      */
      if ( op == TK_INTERSECT )
      {
        addrEofB = addrEofA;
        if ( p.nSelectRow > pPrior.nSelectRow )
          p.nSelectRow = pPrior.nSelectRow;
      }
      else
      {
        VdbeNoopComment( v, "eof-B subroutine" );
        addrEofB = sqlite3VdbeAddOp2( v, OP_If, regEofA, labelEnd );
        sqlite3VdbeAddOp2( v, OP_Gosub, regOutA, addrOutA );
        sqlite3VdbeAddOp1( v, OP_Yield, regAddrA );
        sqlite3VdbeAddOp2( v, OP_Goto, 0, addrEofB );
      }

      /* Generate code to handle the case of A<B
      */
      VdbeNoopComment( v, "A-lt-B subroutine" );
      addrAltB = sqlite3VdbeAddOp2( v, OP_Gosub, regOutA, addrOutA );
      sqlite3VdbeAddOp1( v, OP_Yield, regAddrA );
      sqlite3VdbeAddOp2( v, OP_If, regEofA, addrEofA );
      sqlite3VdbeAddOp2( v, OP_Goto, 0, labelCmpr );

      /* Generate code to handle the case of A==B
      */
      if ( op == TK_ALL )
      {
        addrAeqB = addrAltB;
      }
      else if ( op == TK_INTERSECT )
      {
        addrAeqB = addrAltB;
        addrAltB++;
      }
      else
      {
        VdbeNoopComment( v, "A-eq-B subroutine" );
        addrAeqB =
        sqlite3VdbeAddOp1( v, OP_Yield, regAddrA );
        sqlite3VdbeAddOp2( v, OP_If, regEofA, addrEofA );
        sqlite3VdbeAddOp2( v, OP_Goto, 0, labelCmpr );
      }

      /* Generate code to handle the case of A>B
      */
      VdbeNoopComment( v, "A-gt-B subroutine" );
      addrAgtB = sqlite3VdbeCurrentAddr( v );
      if ( op == TK_ALL || op == TK_UNION )
      {
        sqlite3VdbeAddOp2( v, OP_Gosub, regOutB, addrOutB );
      }
      sqlite3VdbeAddOp1( v, OP_Yield, regAddrB );
      sqlite3VdbeAddOp2( v, OP_If, regEofB, addrEofB );
      sqlite3VdbeAddOp2( v, OP_Goto, 0, labelCmpr );

      /* This code runs once to initialize everything.
      */
      sqlite3VdbeJumpHere( v, j1 );
      sqlite3VdbeAddOp2( v, OP_Integer, 0, regEofA );
      sqlite3VdbeAddOp2( v, OP_Integer, 0, regEofB );
      sqlite3VdbeAddOp2( v, OP_Gosub, regAddrA, addrSelectA );
      sqlite3VdbeAddOp2( v, OP_Gosub, regAddrB, addrSelectB );
      sqlite3VdbeAddOp2( v, OP_If, regEofA, addrEofA );
      sqlite3VdbeAddOp2( v, OP_If, regEofB, addrEofB );

      /* Implement the main merge loop
      */
      sqlite3VdbeResolveLabel( v, labelCmpr );
      sqlite3VdbeAddOp4( v, OP_Permutation, 0, 0, 0, aPermute, P4_INTARRAY );
      sqlite3VdbeAddOp4( v, OP_Compare, destA.iMem, destB.iMem, nOrderBy,
      pKeyMerge, P4_KEYINFO_HANDOFF );
      sqlite3VdbeAddOp3( v, OP_Jump, addrAltB, addrAeqB, addrAgtB );

      /* Release temporary registers
      */
      if ( regPrev != 0 )
      {
        sqlite3ReleaseTempRange( pParse, regPrev, nOrderBy + 1 );
      }

      /* Jump to the this point in order to terminate the query.
      */
      sqlite3VdbeResolveLabel( v, labelEnd );

      /* Set the number of output columns
      */
      if ( pDest.eDest == SRT_Output )
      {
        Select pFirst = pPrior;
        while ( pFirst.pPrior != null )
          pFirst = pFirst.pPrior;
        generateColumnNames( pParse, null, pFirst.pEList );
      }

      /* Reassembly the compound query so that it will be freed correctly
      ** by the calling function */
      if ( p.pPrior != null )
      {
        sqlite3SelectDelete( db, ref p.pPrior );
      }
      p.pPrior = pPrior;

      /*** TBD:  Insert subroutine calls to close cursors on incomplete
      **** subqueries ****/
      explainComposite( pParse, p.op, iSub1, iSub2, false );
      return SQLITE_OK;
    }
Exemplo n.º 7
0
    /* Forward reference */
    //static int multiSelectOrderBy(
    //  Parse* pParse,        /* Parsing context */
    //  Select* p,            /* The right-most of SELECTs to be coded */
    //  SelectDest* pDest     /* What to do with query results */
    //);

#if !SQLITE_OMIT_COMPOUND_SELECT
    /*
** This routine is called to process a compound query form from
** two or more separate queries using UNION, UNION ALL, EXCEPT, or
** INTERSECT
**
** "p" points to the right-most of the two queries.  the query on the
** left is p.pPrior.  The left query could also be a compound query
** in which case this routine will be called recursively.
**
** The results of the total query are to be written into a destination
** of type eDest with parameter iParm.
**
** Example 1:  Consider a three-way compound SQL statement.
**
**     SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
**
** This statement is parsed up as follows:
**
**     SELECT c FROM t3
**      |
**      `----.  SELECT b FROM t2
**                |
**                `-----.  SELECT a FROM t1
**
** The arrows in the diagram above represent the Select.pPrior pointer.
** So if this routine is called with p equal to the t3 query, then
** pPrior will be the t2 query.  p.op will be TK_UNION in this case.
**
** Notice that because of the way SQLite parses compound SELECTs, the
** individual selects always group from left to right.
*/
    static int multiSelect(
    Parse pParse,             /* Parsing context */
    Select p,                 /* The right-most of SELECTs to be coded */
    SelectDest pDest          /* What to do with query results */
    )
    {
      int rc = SQLITE_OK;       /* Success code from a subroutine */
      Select pPrior;            /* Another SELECT immediately to our left */
      Vdbe v;                   /* Generate code to this VDBE */
      SelectDest dest = new SelectDest(); /* Alternative data destination */
      Select pDelete = null;    /* Chain of simple selects to delete */
      sqlite3 db;               /* Database connection */
#if !SQLITE_OMIT_EXPLAIN
      int iSub1 = 0;            /* EQP id of left-hand query */
      int iSub2 = 0;            /* EQP id of right-hand query */
#endif

      /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
*/
      Debug.Assert( p != null && p.pPrior != null );  /* Calling function guarantees this much */
      db = pParse.db;
      pPrior = p.pPrior;
      Debug.Assert( pPrior.pRightmost != pPrior );
      Debug.Assert( pPrior.pRightmost == p.pRightmost );
      dest = pDest;
      if ( pPrior.pOrderBy != null )
      {
        sqlite3ErrorMsg( pParse, "ORDER BY clause should come after %s not before",
        selectOpName( p.op ) );
        rc = 1;
        goto multi_select_end;
      }
      if ( pPrior.pLimit != null )
      {
        sqlite3ErrorMsg( pParse, "LIMIT clause should come after %s not before",
        selectOpName( p.op ) );
        rc = 1;
        goto multi_select_end;
      }

      v = sqlite3GetVdbe( pParse );
      Debug.Assert( v != null );  /* The VDBE already created by calling function */

      /* Create the destination temporary table if necessary
      */
      if ( dest.eDest == SRT_EphemTab )
      {
        Debug.Assert( p.pEList != null );
        sqlite3VdbeAddOp2( v, OP_OpenEphemeral, dest.iParm, p.pEList.nExpr );
        sqlite3VdbeChangeP5( v, BTREE_UNORDERED );
        dest.eDest = SRT_Table;
      }

      /* Make sure all SELECTs in the statement have the same number of elements
      ** in their result sets.
      */
      Debug.Assert( p.pEList != null && pPrior.pEList != null );
      if ( p.pEList.nExpr != pPrior.pEList.nExpr )
      {
        sqlite3ErrorMsg( pParse, "SELECTs to the left and right of %s" +
        " do not have the same number of result columns", selectOpName( p.op ) );
        rc = 1;
        goto multi_select_end;
      }

      /* Compound SELECTs that have an ORDER BY clause are handled separately.
      */
      if ( p.pOrderBy != null )
      {
        return multiSelectOrderBy( pParse, p, pDest );
      }

      /* Generate code for the left and right SELECT statements.
      */
      switch ( p.op )
      {
        case TK_ALL:
          {
            int addr = 0;
            int nLimit = 0;
            Debug.Assert( pPrior.pLimit == null );
            pPrior.pLimit = p.pLimit;
            pPrior.pOffset = p.pOffset;
            explainSetInteger( ref iSub1, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, pPrior, ref dest );
            p.pLimit = null;
            p.pOffset = null;
            if ( rc != 0 )
            {
              goto multi_select_end;
            }
            p.pPrior = null;
            p.iLimit = pPrior.iLimit;
            p.iOffset = pPrior.iOffset;
            if ( p.iLimit != 0 )
            {
              addr = sqlite3VdbeAddOp1( v, OP_IfZero, p.iLimit );
#if SQLITE_DEBUG
              VdbeComment( v, "Jump ahead if LIMIT reached" );
#endif
            }
            explainSetInteger( ref iSub2, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, p, ref dest );
            testcase( rc != SQLITE_OK );
            pDelete = p.pPrior;
            p.pPrior = pPrior;
            p.nSelectRow += pPrior.nSelectRow;
            if ( pPrior.pLimit != null
             && sqlite3ExprIsInteger( pPrior.pLimit, ref nLimit ) != 0
             && p.nSelectRow > (double)nLimit
            )
            {
              p.nSelectRow = (double)nLimit;
            }
            if ( addr != 0 )
            {
              sqlite3VdbeJumpHere( v, addr );
            }
            break;
          }
        case TK_EXCEPT:
        case TK_UNION:
          {
            int unionTab;    /* VdbeCursor number of the temporary table holding result */
            u8 op = 0;      /* One of the SRT_ operations to apply to self */
            int priorOp;     /* The SRT_ operation to apply to prior selects */
            Expr pLimit, pOffset; /* Saved values of p.nLimit and p.nOffset */
            int addr;
            SelectDest uniondest = new SelectDest();

            testcase( p.op == TK_EXCEPT );
            testcase( p.op == TK_UNION );
            priorOp = SRT_Union;
            if ( dest.eDest == priorOp && ALWAYS( null == p.pLimit && null == p.pOffset ) )
            {
              /* We can reuse a temporary table generated by a SELECT to our
              ** right.
              */
              Debug.Assert( p.pRightmost != p );  /* Can only happen for leftward elements
** of a 3-way or more compound */
              Debug.Assert( p.pLimit == null );      /* Not allowed on leftward elements */
              Debug.Assert( p.pOffset == null );     /* Not allowed on leftward elements */
              unionTab = dest.iParm;
            }
            else
            {
              /* We will need to create our own temporary table to hold the
              ** intermediate results.
              */
              unionTab = pParse.nTab++;
              Debug.Assert( p.pOrderBy == null );
              addr = sqlite3VdbeAddOp2( v, OP_OpenEphemeral, unionTab, 0 );
              Debug.Assert( p.addrOpenEphm[0] == -1 );
              p.addrOpenEphm[0] = addr;
              p.pRightmost.selFlags |= SF_UsesEphemeral;
              Debug.Assert( p.pEList != null );
            }

            /* Code the SELECT statements to our left
            */
            Debug.Assert( pPrior.pOrderBy == null );
            sqlite3SelectDestInit( uniondest, priorOp, unionTab );
            explainSetInteger( ref iSub1, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, pPrior, ref uniondest );
            if ( rc != 0 )
            {
              goto multi_select_end;
            }

            /* Code the current SELECT statement
            */
            if ( p.op == TK_EXCEPT )
            {
              op = SRT_Except;
            }
            else
            {
              Debug.Assert( p.op == TK_UNION );
              op = SRT_Union;
            }
            p.pPrior = null;
            pLimit = p.pLimit;
            p.pLimit = null;
            pOffset = p.pOffset;
            p.pOffset = null;
            uniondest.eDest = op;
            explainSetInteger( ref iSub2, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, p, ref uniondest );
            testcase( rc != SQLITE_OK );
            /* Query flattening in sqlite3Select() might refill p.pOrderBy.
            ** Be sure to delete p.pOrderBy, therefore, to avoid a memory leak. */
            sqlite3ExprListDelete( db, ref p.pOrderBy );
            pDelete = p.pPrior;
            p.pPrior = pPrior;
            p.pOrderBy = null;
            if ( p.op == TK_UNION )
              p.nSelectRow += pPrior.nSelectRow;
            sqlite3ExprDelete( db, ref p.pLimit );
            p.pLimit = pLimit;
            p.pOffset = pOffset;
            p.iLimit = 0;
            p.iOffset = 0;

            /* Convert the data in the temporary table into whatever form
            ** it is that we currently need.
            */
            Debug.Assert( unionTab == dest.iParm || dest.eDest != priorOp );
            if ( dest.eDest != priorOp )
            {
              int iCont, iBreak, iStart;
              Debug.Assert( p.pEList != null );
              if ( dest.eDest == SRT_Output )
              {
                Select pFirst = p;
                while ( pFirst.pPrior != null )
                  pFirst = pFirst.pPrior;
                generateColumnNames( pParse, null, pFirst.pEList );
              }
              iBreak = sqlite3VdbeMakeLabel( v );
              iCont = sqlite3VdbeMakeLabel( v );
              computeLimitRegisters( pParse, p, iBreak );
              sqlite3VdbeAddOp2( v, OP_Rewind, unionTab, iBreak );
              iStart = sqlite3VdbeCurrentAddr( v );
              selectInnerLoop( pParse, p, p.pEList, unionTab, p.pEList.nExpr,
              null, -1, dest, iCont, iBreak );
              sqlite3VdbeResolveLabel( v, iCont );
              sqlite3VdbeAddOp2( v, OP_Next, unionTab, iStart );
              sqlite3VdbeResolveLabel( v, iBreak );
              sqlite3VdbeAddOp2( v, OP_Close, unionTab, 0 );
            }
            break;
          }
        default:
          Debug.Assert( p.op == TK_INTERSECT );
          {
            int tab1, tab2;
            int iCont, iBreak, iStart;
            Expr pLimit, pOffset;
            int addr;
            SelectDest intersectdest = new SelectDest();
            int r1;

            /* INTERSECT is different from the others since it requires
            ** two temporary tables.  Hence it has its own case.  Begin
            ** by allocating the tables we will need.
            */
            tab1 = pParse.nTab++;
            tab2 = pParse.nTab++;
            Debug.Assert( p.pOrderBy == null );

            addr = sqlite3VdbeAddOp2( v, OP_OpenEphemeral, tab1, 0 );
            Debug.Assert( p.addrOpenEphm[0] == -1 );
            p.addrOpenEphm[0] = addr;
            p.pRightmost.selFlags |= SF_UsesEphemeral;
            Debug.Assert( p.pEList != null );

            /* Code the SELECTs to our left into temporary table "tab1".
            */
            sqlite3SelectDestInit( intersectdest, SRT_Union, tab1 );
            explainSetInteger( ref iSub1, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, pPrior, ref intersectdest );
            if ( rc != 0 )
            {
              goto multi_select_end;
            }

            /* Code the current SELECT into temporary table "tab2"
            */
            addr = sqlite3VdbeAddOp2( v, OP_OpenEphemeral, tab2, 0 );
            Debug.Assert( p.addrOpenEphm[1] == -1 );
            p.addrOpenEphm[1] = addr;
            p.pPrior = null;
            pLimit = p.pLimit;
            p.pLimit = null;
            pOffset = p.pOffset;
            p.pOffset = null;
            intersectdest.iParm = tab2;
            explainSetInteger( ref iSub2, pParse.iNextSelectId );
            rc = sqlite3Select( pParse, p, ref intersectdest );
            testcase( rc != SQLITE_OK );
            p.pPrior = pPrior;
            if ( p.nSelectRow > pPrior.nSelectRow )
              p.nSelectRow = pPrior.nSelectRow;
            sqlite3ExprDelete( db, ref p.pLimit );
            p.pLimit = pLimit;
            p.pOffset = pOffset;

            /* Generate code to take the intersection of the two temporary
            ** tables.
            */
            Debug.Assert( p.pEList != null );
            if ( dest.eDest == SRT_Output )
            {
              Select pFirst = p;
              while ( pFirst.pPrior != null )
                pFirst = pFirst.pPrior;
              generateColumnNames( pParse, null, pFirst.pEList );
            }
            iBreak = sqlite3VdbeMakeLabel( v );
            iCont = sqlite3VdbeMakeLabel( v );
            computeLimitRegisters( pParse, p, iBreak );
            sqlite3VdbeAddOp2( v, OP_Rewind, tab1, iBreak );
            r1 = sqlite3GetTempReg( pParse );
            iStart = sqlite3VdbeAddOp2( v, OP_RowKey, tab1, r1 );
            sqlite3VdbeAddOp4Int( v, OP_NotFound, tab2, iCont, r1, 0 );
            sqlite3ReleaseTempReg( pParse, r1 );
            selectInnerLoop( pParse, p, p.pEList, tab1, p.pEList.nExpr,
            null, -1, dest, iCont, iBreak );
            sqlite3VdbeResolveLabel( v, iCont );
            sqlite3VdbeAddOp2( v, OP_Next, tab1, iStart );
            sqlite3VdbeResolveLabel( v, iBreak );
            sqlite3VdbeAddOp2( v, OP_Close, tab2, 0 );
            sqlite3VdbeAddOp2( v, OP_Close, tab1, 0 );
            break;
          }
      }

      explainComposite( pParse, p.op, iSub1, iSub2, p.op != TK_ALL );

      /* Compute collating sequences used by
      ** temporary tables needed to implement the compound select.
      ** Attach the KeyInfo structure to all temporary tables.
      **
      ** This section is run by the right-most SELECT statement only.
      ** SELECT statements to the left always skip this part.  The right-most
      ** SELECT might also skip this part if it has no ORDER BY clause and
      ** no temp tables are required.
      */
      if ( ( p.selFlags & SF_UsesEphemeral ) != 0 )
      {
        int i;                        /* Loop counter */
        KeyInfo pKeyInfo;             /* Collating sequence for the result set */
        Select pLoop;                 /* For looping through SELECT statements */
        CollSeq apColl;               /* For looping through pKeyInfo.aColl[] */
        int nCol;                     /* Number of columns in result set */

        Debug.Assert( p.pRightmost == p );
        nCol = p.pEList.nExpr;
        pKeyInfo = new KeyInfo();           //sqlite3DbMallocZero(db,
        pKeyInfo.aColl = new CollSeq[nCol]; //sizeof(*pKeyInfo)+nCol*(CollSeq*.Length + 1));
        //if ( pKeyInfo == null )
        //{
        //  rc = SQLITE_NOMEM;
        //  goto multi_select_end;
        //}

        pKeyInfo.enc = db.aDbStatic[0].pSchema.enc;// ENC( pParse.db );
        pKeyInfo.nField = (u16)nCol;

        for ( i = 0; i < nCol; i++ )
        {//, apColl++){
          apColl = multiSelectCollSeq( pParse, p, i );
          if ( null == apColl )
          {
            apColl = db.pDfltColl;
          }
          pKeyInfo.aColl[i] = apColl;
        }

        for ( pLoop = p; pLoop != null; pLoop = pLoop.pPrior )
        {
          for ( i = 0; i < 2; i++ )
          {
            int addr = pLoop.addrOpenEphm[i];
            if ( addr < 0 )
            {
              /* If [0] is unused then [1] is also unused.  So we can
              ** always safely abort as soon as the first unused slot is found */
              Debug.Assert( pLoop.addrOpenEphm[1] < 0 );
              break;
            }
            sqlite3VdbeChangeP2( v, addr, nCol );
            sqlite3VdbeChangeP4( v, addr, pKeyInfo, P4_KEYINFO );
            pLoop.addrOpenEphm[i] = -1;
          }
        }
        sqlite3DbFree( db, ref pKeyInfo );
      }

multi_select_end:
      pDest.iMem = dest.iMem;
      pDest.nMem = dest.nMem;
      sqlite3SelectDelete( db, ref pDelete );
      return rc;
    }
Exemplo n.º 8
0
    /*
** Code an output subroutine for a coroutine implementation of a
** SELECT statment.
**
** The data to be output is contained in pIn.iMem.  There are
** pIn.nMem columns to be output.  pDest is where the output should
** be sent.
**
** regReturn is the number of the register holding the subroutine
** return address.
**
** If regPrev>0 then it is the first register in a vector that
** records the previous output.  mem[regPrev] is a flag that is false
** if there has been no previous output.  If regPrev>0 then code is
** generated to suppress duplicates.  pKeyInfo is used for comparing
** keys.
**
** If the LIMIT found in p.iLimit is reached, jump immediately to
** iBreak.
*/
    static int generateOutputSubroutine(
    Parse pParse,          /* Parsing context */
    Select p,              /* The SELECT statement */
    SelectDest pIn,        /* Coroutine supplying data */
    SelectDest pDest,      /* Where to send the data */
    int regReturn,         /* The return address register */
    int regPrev,           /* Previous result register.  No uniqueness if 0 */
    KeyInfo pKeyInfo,      /* For comparing with previous entry */
    int p4type,            /* The p4 type for pKeyInfo */
    int iBreak             /* Jump here if we hit the LIMIT */
    )
    {
      Vdbe v = pParse.pVdbe;
      int iContinue;
      int addr;

      addr = sqlite3VdbeCurrentAddr( v );
      iContinue = sqlite3VdbeMakeLabel( v );

      /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
      */
      if ( regPrev != 0 )
      {
        int j1, j2;
        j1 = sqlite3VdbeAddOp1( v, OP_IfNot, regPrev );
        j2 = sqlite3VdbeAddOp4( v, OP_Compare, pIn.iMem, regPrev + 1, pIn.nMem,
        pKeyInfo, p4type );
        sqlite3VdbeAddOp3( v, OP_Jump, j2 + 2, iContinue, j2 + 2 );
        sqlite3VdbeJumpHere( v, j1 );
        sqlite3ExprCodeCopy( pParse, pIn.iMem, regPrev + 1, pIn.nMem );
        sqlite3VdbeAddOp2( v, OP_Integer, 1, regPrev );
      }
      //if ( pParse.db.mallocFailed != 0 ) return 0;

      /* Suppress the the first OFFSET entries if there is an OFFSET clause
      */
      codeOffset( v, p, iContinue );

      switch ( pDest.eDest )
      {
        /* Store the result as data using a unique key.
        */
        case SRT_Table:
        case SRT_EphemTab:
          {
            int r1 = sqlite3GetTempReg( pParse );
            int r2 = sqlite3GetTempReg( pParse );
            testcase( pDest.eDest == SRT_Table );
            testcase( pDest.eDest == SRT_EphemTab );
            sqlite3VdbeAddOp3( v, OP_MakeRecord, pIn.iMem, pIn.nMem, r1 );
            sqlite3VdbeAddOp2( v, OP_NewRowid, pDest.iParm, r2 );
            sqlite3VdbeAddOp3( v, OP_Insert, pDest.iParm, r1, r2 );
            sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
            sqlite3ReleaseTempReg( pParse, r2 );
            sqlite3ReleaseTempReg( pParse, r1 );
            break;
          }

#if !SQLITE_OMIT_SUBQUERY
        /* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack.  Write this
** item into the set table with bogus data.
*/
        case SRT_Set:
          {
            int r1;
            Debug.Assert( pIn.nMem == 1 );
            p.affinity =
            sqlite3CompareAffinity( p.pEList.a[0].pExpr, pDest.affinity );
            r1 = sqlite3GetTempReg( pParse );
            sqlite3VdbeAddOp4( v, OP_MakeRecord, pIn.iMem, 1, r1, p.affinity, 1 );
            sqlite3ExprCacheAffinityChange( pParse, pIn.iMem, 1 );
            sqlite3VdbeAddOp2( v, OP_IdxInsert, pDest.iParm, r1 );
            sqlite3ReleaseTempReg( pParse, r1 );
            break;
          }

#if FALSE  //* Never occurs on an ORDER BY query */
/* If any row exist in the result set, record that fact and abort.
*/
case SRT_Exists: {
sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest.iParm);
/* The LIMIT clause will terminate the loop for us */
break;
}
#endif

        /* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
** of the scan loop.
*/
        case SRT_Mem:
          {
            Debug.Assert( pIn.nMem == 1 );
            sqlite3ExprCodeMove( pParse, pIn.iMem, pDest.iParm, 1 );
            /* The LIMIT clause will jump out of the loop for us */
            break;
          }
#endif //* #if !SQLITE_OMIT_SUBQUERY */

        /* The results are stored in a sequence of registers
** starting at pDest.iMem.  Then the co-routine yields.
*/
        case SRT_Coroutine:
          {
            if ( pDest.iMem == 0 )
            {
              pDest.iMem = sqlite3GetTempRange( pParse, pIn.nMem );
              pDest.nMem = pIn.nMem;
            }
            sqlite3ExprCodeMove( pParse, pIn.iMem, pDest.iMem, pDest.nMem );
            sqlite3VdbeAddOp1( v, OP_Yield, pDest.iParm );
            break;
          }

        /* If none of the above, then the result destination must be
        ** SRT_Output.  This routine is never called with any other
        ** destination other than the ones handled above or SRT_Output.
        **
        ** For SRT_Output, results are stored in a sequence of registers.
        ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
        ** return the next row of result.
        */
        default:
          {
            Debug.Assert( pDest.eDest == SRT_Output );
            sqlite3VdbeAddOp2( v, OP_ResultRow, pIn.iMem, pIn.nMem );
            sqlite3ExprCacheAffinityChange( pParse, pIn.iMem, pIn.nMem );
            break;
          }
      }

      /* Jump to the end of the loop if the LIMIT is reached.
      */
      if ( p.iLimit != 0 )
      {
        sqlite3VdbeAddOp3( v, OP_IfZero, p.iLimit, iBreak, -1 );
      }

      /* Generate the subroutine return
      */
      sqlite3VdbeResolveLabel( v, iContinue );
      sqlite3VdbeAddOp1( v, OP_Return, regReturn );

      return addr;
    }
Exemplo n.º 9
0
        static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf)
        {
            Vdbe v = parse.V;
            Context ctx = parse.Ctx;
            Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null);
            Debug.Assert(stepList != null);
            Debug.Assert(v != null);
            for (TriggerStep step = stepList; step != null; step = step.Next)
            {
                // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger
                // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger
                // step statement. Example:
                //
                //   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
                //     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
                //   END;
                //
                //   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
                //   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
                parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf);

                switch (step.OP)
                {
                    case TK.UPDATE:
                        Update(parse,
                          TargetSrcList(parse, step),
                          Expr.ListDup(ctx, step.ExprList, 0),
                          Expr.Dup(ctx, step.Where, 0),
                          parse.Orconf);
                        break;
                    case TK.INSERT:
                        Insert(parse,
                          TargetSrcList(parse, step),
                          Expr.ListDup(ctx, step.ExprList, 0),
                          Select.Dup(ctx, step.Select, 0),
                          Expr.IdListDup(ctx, step.IdList),
                          parse.Orconf);
                        break;
                    case TK.DELETE:
                        DeleteFrom(parse,
                          TargetSrcList(parse, step),
                          Expr.Dup(ctx, step.Where, 0));
                        break;
                    default:
                        Debug.Assert(step.OP == TK.SELECT);
                        SelectDest sDest = new SelectDest();
                        Select select = Expr.SelectDup(ctx, step.Select, 0);
                        Select.DestInit(sDest, SRT.Discard, 0);
                        Select.Select_(parse, select, ref sDest);
                        Select.Delete(ctx, ref select);
                        break;
                }
                if (step.OP != TK.SELECT)
                    v.AddOp0(OP.ResetCount);
            }
            return 0;
        }
Exemplo n.º 10
0
    /*
** If the inner loop was generated using a non-null pOrderBy argument,
** then the results were placed in a sorter.  After the loop is terminated
** we need to run the sorter and output the results.  The following
** routine generates the code needed to do that.
*/
    static void generateSortTail(
    Parse pParse,     /* Parsing context */
    Select p,         /* The SELECT statement */
    Vdbe v,           /* Generate code into this VDBE */
    int nColumn,      /* Number of columns of data */
    SelectDest pDest  /* Write the sorted results here */
    )
    {
      int addrBreak = sqlite3VdbeMakeLabel( v );    /* Jump here to exit loop */
      int addrContinue = sqlite3VdbeMakeLabel( v ); /* Jump here for next cycle */
      int addr;
      int iTab;
      int pseudoTab = 0;
      ExprList pOrderBy = p.pOrderBy;

      int eDest = pDest.eDest;
      int iParm = pDest.iParm;

      int regRow;
      int regRowid;

      iTab = pOrderBy.iECursor;
      regRow = sqlite3GetTempReg( pParse );
      if ( eDest == SRT_Output || eDest == SRT_Coroutine )
      {
        pseudoTab = pParse.nTab++;
        sqlite3VdbeAddOp3( v, OP_OpenPseudo, pseudoTab, regRow, nColumn );
        regRowid = 0;
      }
      else
      {
        regRowid = sqlite3GetTempReg( pParse );
      }
      addr = 1 + sqlite3VdbeAddOp2( v, OP_Sort, iTab, addrBreak );
      codeOffset( v, p, addrContinue );
      sqlite3VdbeAddOp3( v, OP_Column, iTab, pOrderBy.nExpr + 1, regRow );
      switch ( eDest )
      {
        case SRT_Table:
        case SRT_EphemTab:
          {
            testcase( eDest == SRT_Table );
            testcase( eDest == SRT_EphemTab );
            sqlite3VdbeAddOp2( v, OP_NewRowid, iParm, regRowid );
            sqlite3VdbeAddOp3( v, OP_Insert, iParm, regRow, regRowid );
            sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
            break;
          }
#if !SQLITE_OMIT_SUBQUERY
        case SRT_Set:
          {
            Debug.Assert( nColumn == 1 );
            sqlite3VdbeAddOp4( v, OP_MakeRecord, regRow, 1, regRowid, p.affinity, 1 );
            sqlite3ExprCacheAffinityChange( pParse, regRow, 1 );
            sqlite3VdbeAddOp2( v, OP_IdxInsert, iParm, regRowid );
            break;
          }
        case SRT_Mem:
          {
            Debug.Assert( nColumn == 1 );
            sqlite3ExprCodeMove( pParse, regRow, iParm, 1 );
            /* The LIMIT clause will terminate the loop for us */
            break;
          }
#endif
        default:
          {
            int i;
            Debug.Assert( eDest == SRT_Output || eDest == SRT_Coroutine );
            testcase( eDest == SRT_Output );
            testcase( eDest == SRT_Coroutine );
            for ( i = 0; i < nColumn; i++ )
            {
              Debug.Assert( regRow != pDest.iMem + i );
              sqlite3VdbeAddOp3( v, OP_Column, pseudoTab, i, pDest.iMem + i );
              if ( i == 0 )
              {
                sqlite3VdbeChangeP5( v, OPFLAG_CLEARCACHE );
              }
            }
            if ( eDest == SRT_Output )
            {
              sqlite3VdbeAddOp2( v, OP_ResultRow, pDest.iMem, nColumn );
              sqlite3ExprCacheAffinityChange( pParse, pDest.iMem, nColumn );
            }
            else
            {
              sqlite3VdbeAddOp1( v, OP_Yield, pDest.iParm );
            }
            break;
          }
      }
      sqlite3ReleaseTempReg( pParse, regRow );
      sqlite3ReleaseTempReg( pParse, regRowid );

      /* The bottom of the loop
      */
      sqlite3VdbeResolveLabel( v, addrContinue );
      sqlite3VdbeAddOp2( v, OP_Next, iTab, addr );
      sqlite3VdbeResolveLabel( v, addrBreak );
      if ( eDest == SRT_Output || eDest == SRT_Coroutine )
      {
        sqlite3VdbeAddOp2( v, OP_Close, pseudoTab, 0 );
      }

    }
Exemplo n.º 11
0
    /*
** Generate an error message when a SELECT is used within a subexpression
** (example:  "a IN (SELECT * FROM table)") but it has more than 1 result
** column.  We do this in a subroutine because the error used to occur
** in multiple places.  (The error only occurs in one place now, but we
** retain the subroutine to minimize code disruption.)
*/
    static bool checkForMultiColumnSelectError(
    Parse pParse,       /* Parse context. */
    SelectDest pDest,   /* Destination of SELECT results */
    int nExpr           /* Number of result columns returned by SELECT */
    )
    {
      int eDest = pDest.eDest;
      if ( nExpr > 1 && ( eDest == SRT_Mem || eDest == SRT_Set ) )
      {
        sqlite3ErrorMsg( pParse, "only a single result allowed for " +
        "a SELECT that is part of an expression" );
        return true;
      }
      else
      {
        return false;
      }
    }
Exemplo n.º 12
0
    /*
    ** Generate VDBE code for the statements inside the body of a single 
    ** trigger.
    */
    static int codeTriggerProgram(
    Parse pParse,            /* The parser context */
    TriggerStep pStepList,   /* List of statements inside the trigger body */
    int orconf               /* Conflict algorithm. (OE_Abort, etc) */
    )
    {
      TriggerStep pStep;
      Vdbe v = pParse.pVdbe;
      sqlite3 db = pParse.db;

      Debug.Assert( pParse.pTriggerTab != null && pParse.pToplevel != null );
      Debug.Assert( pStepList != null );
      Debug.Assert( v != null );
      for ( pStep = pStepList; pStep != null; pStep = pStep.pNext )
      {
        /* Figure out the ON CONFLICT policy that will be used for this step
        ** of the trigger program. If the statement that caused this trigger
        ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use
        ** the ON CONFLICT policy that was specified as part of the trigger
        ** step statement. Example:
        **
        **   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
        **     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
        **   END;
        **
        **   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
        **   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
        */
        pParse.eOrconf = ( orconf == OE_Default ) ? pStep.orconf : (u8)orconf;

        switch ( pStep.op )
        {
          case TK_UPDATE:
            {
              sqlite3Update( pParse,
                targetSrcList( pParse, pStep ),
                sqlite3ExprListDup( db, pStep.pExprList, 0 ),
                sqlite3ExprDup( db, pStep.pWhere, 0 ),
                pParse.eOrconf
              );
              break;
            }
          case TK_INSERT:
            {
              sqlite3Insert( pParse,
                targetSrcList( pParse, pStep ),
                sqlite3ExprListDup( db, pStep.pExprList, 0 ),
                sqlite3SelectDup( db, pStep.pSelect, 0 ),
                sqlite3IdListDup( db, pStep.pIdList ),
                pParse.eOrconf
              );
              break;
            }
          case TK_DELETE:
            {
              sqlite3DeleteFrom( pParse,
                targetSrcList( pParse, pStep ),
                sqlite3ExprDup( db, pStep.pWhere, 0 )
              );
              break;
            }
          default:
            Debug.Assert( pStep.op == TK_SELECT );
            {
              SelectDest sDest = new SelectDest();
              Select pSelect = sqlite3SelectDup( db, pStep.pSelect, 0 );
              sqlite3SelectDestInit( sDest, SRT_Discard, 0 );
              sqlite3Select( pParse, pSelect, ref sDest );
              sqlite3SelectDelete( db, ref pSelect );
              break;
            }
        }
        if ( pStep.op != TK_SELECT )
        {
          sqlite3VdbeAddOp0( v, OP_ResetCount );
        }
      }

      return 0;
    }
Exemplo n.º 13
0
    /*
** Generate code for scalar subqueries used as a subquery expression, EXISTS,
** or IN operators.  Examples:
**
**     (SELECT a FROM b)          -- subquery
**     EXISTS (SELECT a FROM b)   -- EXISTS subquery
**     x IN (4,5,11)              -- IN operator with list on right-hand side
**     x IN (SELECT a FROM b)     -- IN operator with subquery on the right
**
** The pExpr parameter describes the expression that contains the IN
** operator or subquery.
**
** If parameter isRowid is non-zero, then expression pExpr is guaranteed
** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
** to some integer key column of a table B-Tree. In this case, use an
** intkey B-Tree to store the set of IN(...) values instead of the usual
** (slower) variable length keys B-Tree.
**
** If rMayHaveNull is non-zero, that means that the operation is an IN
** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
** Furthermore, the IN is in a WHERE clause and that we really want
** to iterate over the RHS of the IN operator in order to quickly locate
** all corresponding LHS elements.  All this routine does is initialize
** the register given by rMayHaveNull to NULL.  Calling routines will take
** care of changing this register value to non-NULL if the RHS is NULL-free.
**
** If rMayHaveNull is zero, that means that the subquery is being used
** for membership testing only.  There is no need to initialize any
** registers to indicate the presense or absence of NULLs on the RHS.
**
** For a SELECT or EXISTS operator, return the register that holds the
** result.  For IN operators or if an error occurs, the return value is 0.
*/
#if !SQLITE_OMIT_SUBQUERY
    static int sqlite3CodeSubselect(
    Parse pParse,          /* Parsing context */
    Expr pExpr,            /* The IN, SELECT, or EXISTS operator */
    int rMayHaveNull,      /* Register that records whether NULLs exist in RHS */
    bool isRowid           /* If true, LHS of IN operator is a rowid */
    )
    {
      int testAddr = 0;                       /* One-time test address */
      int rReg = 0;                           /* Register storing resulting */
      Vdbe v = sqlite3GetVdbe( pParse );
      if ( NEVER( v == null ) )
        return 0;
      sqlite3ExprCachePush( pParse );

      /* This code must be run in its entirety every time it is encountered
      ** if any of the following is true:
      **
      **    *  The right-hand side is a correlated subquery
      **    *  The right-hand side is an expression list containing variables
      **    *  We are inside a trigger
      **
      ** If all of the above are false, then we can run this code just once
      ** save the results, and reuse the same result on subsequent invocations.
      */
      if ( !ExprHasAnyProperty( pExpr, EP_VarSelect ) && null == pParse.pTriggerTab )
      {
        int mem = ++pParse.nMem;
        sqlite3VdbeAddOp1( v, OP_If, mem );
        testAddr = sqlite3VdbeAddOp2( v, OP_Integer, 1, mem );
        Debug.Assert( testAddr > 0 /* || pParse.db.mallocFailed != 0 */ );
      }

#if !SQLITE_OMIT_EXPLAIN
      if ( pParse.explain == 2 )
      {
        string zMsg = sqlite3MPrintf(
            pParse.db, "EXECUTE %s%s SUBQUERY %d", testAddr != 0 ? "" : "CORRELATED ",
            pExpr.op == TK_IN ? "LIST" : "SCALAR", pParse.iNextSelectId
        );
        sqlite3VdbeAddOp4( v, OP_Explain, pParse.iSelectId, 0, 0, zMsg, P4_DYNAMIC );
      }
#endif

      switch ( pExpr.op )
      {
        case TK_IN:
          {
            char affinity;              /* Affinity of the LHS of the IN */
            KeyInfo keyInfo;            /* Keyinfo for the generated table */
            int addr;                   /* Address of OP_OpenEphemeral instruction */
            Expr pLeft = pExpr.pLeft;   /* the LHS of the IN operator */

            if ( rMayHaveNull != 0 )
            {
              sqlite3VdbeAddOp2( v, OP_Null, 0, rMayHaveNull );
            }

            affinity = sqlite3ExprAffinity( pLeft );

            /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
            ** expression it is handled the same way. An ephemeral table is
            ** filled with single-field index keys representing the results
            ** from the SELECT or the <exprlist>.
            **
            ** If the 'x' expression is a column value, or the SELECT...
            ** statement returns a column value, then the affinity of that
            ** column is used to build the index keys. If both 'x' and the
            ** SELECT... statement are columns, then numeric affinity is used
            ** if either column has NUMERIC or INTEGER affinity. If neither
            ** 'x' nor the SELECT... statement are columns, then numeric affinity
            ** is used.
            */
            pExpr.iTable = pParse.nTab++;
            addr = sqlite3VdbeAddOp2( v, OP_OpenEphemeral, (int)pExpr.iTable, !isRowid );
            if ( rMayHaveNull == 0 )
              sqlite3VdbeChangeP5( v, BTREE_UNORDERED );
            keyInfo = new KeyInfo();// memset( &keyInfo, 0, sizeof(keyInfo ));
            keyInfo.nField = 1;

            if ( ExprHasProperty( pExpr, EP_xIsSelect ) )
            {
              /* Case 1:     expr IN (SELECT ...)
              **
              ** Generate code to write the results of the select into the temporary
              ** table allocated and opened above.
              */
              SelectDest dest = new SelectDest();
              ExprList pEList;

              Debug.Assert( !isRowid );
              sqlite3SelectDestInit( dest, SRT_Set, pExpr.iTable );
              dest.affinity = (char)affinity;
              Debug.Assert( ( pExpr.iTable & 0x0000FFFF ) == pExpr.iTable );
              pExpr.x.pSelect.iLimit = 0;
              if ( sqlite3Select( pParse, pExpr.x.pSelect, ref dest ) != 0 )
              {
                return 0;
              }
              pEList = pExpr.x.pSelect.pEList;
              if ( ALWAYS( pEList != null ) && pEList.nExpr > 0 )
              {
                keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq( pParse, pExpr.pLeft,
                pEList.a[0].pExpr );
              }
            }
            else if ( ALWAYS( pExpr.x.pList != null ) )
            {
              /* Case 2:     expr IN (exprlist)
              **
              ** For each expression, build an index key from the evaluation and
              ** store it in the temporary table. If <expr> is a column, then use
              ** that columns affinity when building index keys. If <expr> is not
              ** a column, use numeric affinity.
              */
              int i;
              ExprList pList = pExpr.x.pList;
              ExprList_item pItem;
              int r1, r2, r3;

              if ( affinity == '\0' )
              {
                affinity = SQLITE_AFF_NONE;
              }
              keyInfo.aColl[0] = sqlite3ExprCollSeq( pParse, pExpr.pLeft );

              /* Loop through each expression in <exprlist>. */
              r1 = sqlite3GetTempReg( pParse );
              r2 = sqlite3GetTempReg( pParse );
              sqlite3VdbeAddOp2( v, OP_Null, 0, r2 );
              for ( i = 0; i < pList.nExpr; i++ )
              {//, pItem++){
                pItem = pList.a[i];
                Expr pE2 = pItem.pExpr;
                int iValToIns = 0;

                /* If the expression is not constant then we will need to
                ** disable the test that was generated above that makes sure
                ** this code only executes once.  Because for a non-constant
                ** expression we need to rerun this code each time.
                */
                if ( testAddr != 0 && sqlite3ExprIsConstant( pE2 ) == 0 )
                {
                  sqlite3VdbeChangeToNoop( v, testAddr - 1, 2 );
                  testAddr = 0;
                }

                /* Evaluate the expression and insert it into the temp table */
                if ( isRowid && sqlite3ExprIsInteger( pE2, ref iValToIns ) != 0 )
                {
                  sqlite3VdbeAddOp3( v, OP_InsertInt, pExpr.iTable, r2, iValToIns );
                }
                else
                {
                  r3 = sqlite3ExprCodeTarget( pParse, pE2, r1 );
                  if ( isRowid )
                  {
                    sqlite3VdbeAddOp2( v, OP_MustBeInt, r3,
                                       sqlite3VdbeCurrentAddr( v ) + 2 );
                    sqlite3VdbeAddOp3( v, OP_Insert, pExpr.iTable, r2, r3 );
                  }
                  else
                  {
                    sqlite3VdbeAddOp4( v, OP_MakeRecord, r3, 1, r2, affinity, 1 );
                    sqlite3ExprCacheAffinityChange( pParse, r3, 1 );
                    sqlite3VdbeAddOp2( v, OP_IdxInsert, pExpr.iTable, r2 );
                  }
                }
              }
              sqlite3ReleaseTempReg( pParse, r1 );
              sqlite3ReleaseTempReg( pParse, r2 );
            }
            if ( !isRowid )
            {
              sqlite3VdbeChangeP4( v, addr, keyInfo, P4_KEYINFO );
            }
            break;
          }

        case TK_EXISTS:
        case TK_SELECT:
        default:
          {
            /* If this has to be a scalar SELECT.  Generate code to put the
            ** value of this select in a memory cell and record the number
            ** of the memory cell in iColumn.  If this is an EXISTS, write
            ** an integer 0 (not exists) or 1 (exists) into a memory cell
            ** and record that memory cell in iColumn.
            */
            Select pSel;                        /* SELECT statement to encode */
            SelectDest dest = new SelectDest(); /* How to deal with SELECt result */

            testcase( pExpr.op == TK_EXISTS );
            testcase( pExpr.op == TK_SELECT );
            Debug.Assert( pExpr.op == TK_EXISTS || pExpr.op == TK_SELECT );

            Debug.Assert( ExprHasProperty( pExpr, EP_xIsSelect ) );
            pSel = pExpr.x.pSelect;
            sqlite3SelectDestInit( dest, 0, ++pParse.nMem );
            if ( pExpr.op == TK_SELECT )
            {
              dest.eDest = SRT_Mem;
              sqlite3VdbeAddOp2( v, OP_Null, 0, dest.iParm );
#if SQLITE_DEBUG
              VdbeComment( v, "Init subquery result" );
#endif
            }
            else
            {
              dest.eDest = SRT_Exists;
              sqlite3VdbeAddOp2( v, OP_Integer, 0, dest.iParm );
#if SQLITE_DEBUG
              VdbeComment( v, "Init EXISTS result" );
#endif
            }
            sqlite3ExprDelete( pParse.db, ref pSel.pLimit );
            pSel.pLimit = sqlite3PExpr( pParse, TK_INTEGER, null, null, sqlite3IntTokens[1] );
            pSel.iLimit = 0;
            if ( sqlite3Select( pParse, pSel, ref dest ) != 0 )
            {
              return 0;
            }
            rReg = dest.iParm;
            ExprSetIrreducible( pExpr );
            break;
          }
      }

      if ( testAddr != 0 )
      {
        sqlite3VdbeJumpHere( v, testAddr - 1 );
      }
      sqlite3ExprCachePop( pParse, 1 );

      return rReg;
    }
Exemplo n.º 14
0
    /*
    ** Generate VDBE code for zero or more statements inside the body of a
    ** trigger.
    */
    static int codeTriggerProgram(
    Parse pParse,            /* The parser context */
    TriggerStep pStepList,   /* List of statements inside the trigger body */
    int orconfin              /* Conflict algorithm. (OE_Abort, etc) */
    )
    {
      TriggerStep pTriggerStep = pStepList;
      int orconf;
      Vdbe v = pParse.pVdbe;
      sqlite3 db = pParse.db;

      Debug.Assert( pTriggerStep != null );
      Debug.Assert( v != null );
      sqlite3VdbeAddOp2( v, OP_ContextPush, 0, 0 );
#if SQLITE_DEBUG
      VdbeComment( v, "begin trigger %s", pStepList.pTrig.name );
#endif
      while ( pTriggerStep != null )
      {
        sqlite3ExprCacheClear( pParse );
        orconf = ( orconfin == OE_Default ) ? pTriggerStep.orconf : orconfin;
        pParse.trigStack.orconf = orconf;
        switch ( pTriggerStep.op )
        {
          case TK_UPDATE:
            {
              SrcList pSrc;
              pSrc = targetSrcList( pParse, pTriggerStep );
              sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 );
              sqlite3Update( pParse, pSrc,
              sqlite3ExprListDup( db, pTriggerStep.pExprList, 0 ),
              sqlite3ExprDup( db, pTriggerStep.pWhere, 0 ), orconf );
              sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 );
              break;
            }
          case TK_INSERT:
            {
              SrcList pSrc;
              pSrc = targetSrcList( pParse, pTriggerStep );
              sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 );
              sqlite3Insert( pParse, pSrc,
              sqlite3ExprListDup( db, pTriggerStep.pExprList, 0 ),
              sqlite3SelectDup( db, pTriggerStep.pSelect, 0 ),
              sqlite3IdListDup( db, pTriggerStep.pIdList ), orconf );
              sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 );
              break;
            }
          case TK_DELETE:
            {
              SrcList pSrc;
              sqlite3VdbeAddOp2( v, OP_ResetCount, 0, 0 );
              pSrc = targetSrcList( pParse, pTriggerStep );
              sqlite3DeleteFrom( pParse, pSrc,
              sqlite3ExprDup( db, pTriggerStep.pWhere, 0 ) );
              sqlite3VdbeAddOp2( v, OP_ResetCount, 1, 0 );
              break;
            }
          default: Debug.Assert( pTriggerStep.op == TK_SELECT );
            {
              Select ss = sqlite3SelectDup( db, pTriggerStep.pSelect, 0 );
              if ( ss != null )
              {
                SelectDest dest = new SelectDest();

                sqlite3SelectDestInit( dest, SRT_Discard, 0 );
                sqlite3Select( pParse, ss, ref dest );
                sqlite3SelectDelete( db, ref ss );
              }
              break;
            }
        }
        pTriggerStep = pTriggerStep.pNext;
      }
      sqlite3VdbeAddOp2( v, OP_ContextPop, 0, 0 );
#if SQLITE_DEBUG
      VdbeComment( v, "end trigger %s", pStepList.pTrig.name );
#endif
      return 0;
    }
Exemplo n.º 15
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 );
    }
Exemplo n.º 16
0
        /*
        ** Evaluate a view and store its result in an ephemeral table.  The
        ** pWhere argument is an optional WHERE clause that restricts the
        ** set of rows in the view that are to be added to the ephemeral table.
        */
        static void sqlite3MaterializeView(
            Parse pParse,      /* Parsing context */
            Table pView,       /* View definition */
            Expr pWhere,       /* Optional WHERE clause to be added */
            int iCur           /* VdbeCursor number for ephemerial table */
            )
        {
            SelectDest dest = new SelectDest();
              Select pDup;
              sqlite3 db = pParse.db;

              pDup = sqlite3SelectDup( db, pView.pSelect, 0 );
              if ( pWhere != null )
              {
            SrcList pFrom;

            pWhere = sqlite3ExprDup( db, pWhere, 0 );
            pFrom = sqlite3SrcListAppend( db, null, null, null );
            //if ( pFrom != null )
            //{
            Debug.Assert( pFrom.nSrc == 1 );
            pFrom.a[0].zAlias = pView.zName;// sqlite3DbStrDup( db, pView.zName );
            pFrom.a[0].pSelect = pDup;
            Debug.Assert( pFrom.a[0].pOn == null );
            Debug.Assert( pFrom.a[0].pUsing == null );
            //}
            //else
            //{
            //  sqlite3SelectDelete( db, ref pDup );
            //}
            pDup = sqlite3SelectNew( pParse, null, pFrom, pWhere, null, null, null, 0, null, null );
              }
              sqlite3SelectDestInit( dest, SRT_EphemTab, iCur );
              sqlite3Select( pParse, pDup, ref dest );
              sqlite3SelectDelete( db, ref pDup );
        }
Exemplo n.º 17
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).  */
        //#if isView
        // #undef isView
        //#endif
        //#if 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 */
            int onError        /* ON CONFLICT strategy */
            )
        {
            Vdbe       v       = pParse.pVdbe; /* Virtual machine under construction */
            ExprList   pEList  = null;         /* The result set of the SELECT statement */
            Select     pSelect = null;         /* 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 */
            VTable     pVTab = sqlite3GetVTable(db, pTab);
            SelectDest dest  = new SelectDest();

            /* 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 != null)
            {
                pEList = sqlite3ExprListAppend(pParse, pEList,
                                               sqlite3ExprDup(db, pRowid, 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, null, null, null, 0, null, null);

            /* Create the ephemeral table into which the update results will
            ** be stored.
            */
            Debug.Assert(v != null);
            ephemTab = pParse.nTab++;
            sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab.nCol + 1 + ((pRowid != null) ? 1 : 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 != null ? 1 : 0), iReg + 1);
            for (i = 0; i < pTab.nCol; i++)
            {
                sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i + 1 + ((pRowid != null) ? 1 : 0), iReg + 2 + i);
            }
            sqlite3VtabMakeWritable(pParse, pTab);
            sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab.nCol + 2, iReg, pVTab, P4_VTAB);
            sqlite3VdbeChangeP5(v, (byte)(onError == OE_Default ? OE_Abort : onError));
            sqlite3MayAbort(pParse);
            sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr + 1);
            sqlite3VdbeJumpHere(v, addr);
            sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

            /* Cleanup */
            sqlite3SelectDelete(db, ref pSelect);
        }
Exemplo n.º 18
0
        static void sqlite3EndTable(
            Parse pParse,          /* Parse context */
            Token pCons,           /* The ',' token after the last column defn. */
            Token pEnd,            /* The final ')' token in the CREATE TABLE */
            Select pSelect         /* Select from a "CREATE ... AS SELECT" */
            )
        {
            Table p;
            sqlite3 db = pParse.db;
            int iDb;

            if ((pEnd == null && pSelect == null) /*|| db.mallocFailed != 0 */ )
            {
                return;
            }
            p = pParse.pNewTable;
            if (p == null)
                return;

            Debug.Assert(0 == db.init.busy || pSelect == null);

            iDb = sqlite3SchemaToIndex(db, p.pSchema);

            #if !SQLITE_OMIT_CHECK
            /* Resolve names in all CHECK constraint expressions.
            */
            if (p.pCheck != null)
            {
                SrcList sSrc;                   /* Fake SrcList for pParse.pNewTable */
                NameContext sNC;                /* Name context for pParse.pNewTable */

                sNC = new NameContext();// memset(sNC, 0, sizeof(sNC));
                sSrc = new SrcList();// memset(sSrc, 0, sizeof(sSrc));
                sSrc.nSrc = 1;
                sSrc.a = new SrcList_item[1];
                sSrc.a[0] = new SrcList_item();
                sSrc.a[0].zName = p.zName;
                sSrc.a[0].pTab = p;
                sSrc.a[0].iCursor = -1;
                sNC.pParse = pParse;
                sNC.pSrcList = sSrc;
                sNC.isCheck = 1;
                if (sqlite3ResolveExprNames(sNC, ref p.pCheck) != 0)
                {
                    return;
                }
            }
            #endif // * !SQLITE_OMIT_CHECK) */

            /* If the db.init.busy is 1 it means we are reading the SQL off the
            ** "sqlite_master" or "sqlite_temp_master" table on the disk.
            ** So do not write to the disk again.  Extract the root page number
            ** for the table from the db.init.newTnum field.  (The page number
            ** should have been put there by the sqliteOpenCb routine.)
            */
            if (db.init.busy != 0)
            {
                p.tnum = db.init.newTnum;
            }

            /* If not initializing, then create a record for the new table
            ** in the SQLITE_MASTER table of the database.
            **
            ** If this is a TEMPORARY table, write the entry into the auxiliary
            ** file instead of into the main database file.
            */
            if (0 == db.init.busy)
            {
                int n;
                Vdbe v;
                String zType = "";    /* "view" or "table" */
                String zType2 = "";    /* "VIEW" or "TABLE" */
                String zStmt = "";    /* Text of the CREATE TABLE or CREATE VIEW statement */

                v = sqlite3GetVdbe(pParse);
                if (NEVER(v == null))
                    return;

                sqlite3VdbeAddOp1(v, OP_Close, 0);

                /*
                ** Initialize zType for the new view or table.
                */
                if (p.pSelect == null)
                {
                    /* A regular table */
                    zType = "table";
                    zType2 = "TABLE";
            #if !SQLITE_OMIT_VIEW
                }
                else
                {
                    /* A view */
                    zType = "view";
                    zType2 = "VIEW";
            #endif
                }

                /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
                ** statement to populate the new table. The root-page number for the
                ** new table is in register pParse->regRoot.
                **
                ** Once the SELECT has been coded by sqlite3Select(), it is in a
                ** suitable state to query for the column names and types to be used
                ** by the new table.
                **
                ** A shared-cache write-lock is not required to write to the new table,
                ** as a schema-lock must have already been obtained to create it. Since
                ** a schema-lock excludes all other database users, the write-lock would
                ** be redundant.
                */
                if (pSelect != null)
                {
                    SelectDest dest = new SelectDest();
                    Table pSelTab;

                    Debug.Assert(pParse.nTab == 1);
                    sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse.regRoot, iDb);
                    sqlite3VdbeChangeP5(v, 1);
                    pParse.nTab = 2;
                    sqlite3SelectDestInit(dest, SRT_Table, 1);
                    sqlite3Select(pParse, pSelect, ref dest);
                    sqlite3VdbeAddOp1(v, OP_Close, 1);
                    if (pParse.nErr == 0)
                    {
                        pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
                        if (pSelTab == null)
                            return;
                        Debug.Assert(p.aCol == null);
                        p.nCol = pSelTab.nCol;
                        p.aCol = pSelTab.aCol;
                        pSelTab.nCol = 0;
                        pSelTab.aCol = null;
                        sqlite3DeleteTable(db, ref pSelTab);
                    }
                }

                /* Compute the complete text of the CREATE statement */
                if (pSelect != null)
                {
                    zStmt = createTableStmt(db, p);
                }
                else
                {
                    n = (int)(pParse.sNameToken.z.Length - pEnd.z.Length) + 1;
                    zStmt = sqlite3MPrintf(db,
                    "CREATE %s %.*s", zType2, n, pParse.sNameToken.z
                    );
                }

                /* A slot for the record has already been allocated in the
                ** SQLITE_MASTER table.  We just need to update that slot with all
                ** the information we've collected.
                */
                sqlite3NestedParse(pParse,
                "UPDATE %Q.%s " +
                "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " +
                "WHERE rowid=#%d",
                db.aDb[iDb].zName, SCHEMA_TABLE(iDb),
                zType,
                p.zName,
                p.zName,
                pParse.regRoot,
                zStmt,
                pParse.regRowid
                );
                sqlite3DbFree(db, ref zStmt);
                sqlite3ChangeCookie(pParse, iDb);

            #if !SQLITE_OMIT_AUTOINCREMENT
                /* Check to see if we need to create an sqlite_sequence table for
            ** keeping track of autoincrement keys.
            */
                if ((p.tabFlags & TF_Autoincrement) != 0)
                {
                    Db pDb = db.aDb[iDb];
                    Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
                    if (pDb.pSchema.pSeqTab == null)
                    {
                        sqlite3NestedParse(pParse,
                        "CREATE TABLE %Q.sqlite_sequence(name,seq)",
                        pDb.zName
                        );
                    }
                }
            #endif

                /* Reparse everything to update our internal data structures */
                sqlite3VdbeAddParseSchemaOp(v, iDb,
                           sqlite3MPrintf(db, "tbl_name='%q'", p.zName));
            }

            /* Add the table to the in-memory representation of the database.
            */
            if (db.init.busy != 0)
            {
                Table pOld;
                Schema pSchema = p.pSchema;
                Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
                pOld = sqlite3HashInsert(ref pSchema.tblHash, p.zName,
                sqlite3Strlen30(p.zName), p);
                if (pOld != null)
                {
                    Debug.Assert(p == pOld);  /* Malloc must have failed inside HashInsert() */
                    //        db.mallocFailed = 1;
                    return;
                }
                pParse.pNewTable = null;
                db.nTable++;
                db.flags |= SQLITE_InternChanges;

            #if !SQLITE_OMIT_ALTERTABLE
                if (p.pSelect == null)
                {
                    string zName = pParse.sNameToken.z;
                    int nName;
                    Debug.Assert(pSelect == null && pCons != null && pEnd != null);
                    if (pCons.z == null)
                    {
                        pCons = pEnd;
                    }
                    nName = zName.Length - pCons.z.Length;
                    p.addColOffset = 13 + nName; // sqlite3Utf8CharLen(zName, nName);
                }
            #endif
            }
        }
Exemplo n.º 19
0
        static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf)
        {
            Vdbe    v   = parse.V;
            Context ctx = parse.Ctx;

            Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null);
            Debug.Assert(stepList != null);
            Debug.Assert(v != null);
            for (TriggerStep step = stepList; step != null; step = step.Next)
            {
                // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger
                // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger
                // step statement. Example:
                //
                //   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
                //     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
                //   END;
                //
                //   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
                //   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
                parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf);

                switch (step.OP)
                {
                case TK.UPDATE:
                    Update(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Expr.Dup(ctx, step.Where, 0),
                           parse.Orconf);
                    break;

                case TK.INSERT:
                    Insert(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Select.Dup(ctx, step.Select, 0),
                           Expr.IdListDup(ctx, step.IdList),
                           parse.Orconf);
                    break;

                case TK.DELETE:
                    DeleteFrom(parse,
                               TargetSrcList(parse, step),
                               Expr.Dup(ctx, step.Where, 0));
                    break;

                default:
                    Debug.Assert(step.OP == TK.SELECT);
                    SelectDest sDest  = new SelectDest();
                    Select     select = Expr.SelectDup(ctx, step.Select, 0);
                    Select.DestInit(sDest, SRT.Discard, 0);
                    Select.Select_(parse, select, ref sDest);
                    Select.Delete(ctx, ref select);
                    break;
                }
                if (step.OP != TK.SELECT)
                {
                    v.AddOp0(OP.ResetCount);
                }
            }
            return(0);
        }
Exemplo n.º 20
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;
    }
Exemplo n.º 21
0
 static bool CheckForMultiColumnSelectError(Parse parse, SelectDest dest, int exprs)
 {
     SRT dest2 = dest.Dest;
     if (exprs > 1 && (dest2 == SRT.Mem || dest2 == SRT.Set))
     {
         parse.ErrorMsg("only a single result allowed for a SELECT that is part of an expression");
         return true;
     }
     return false;
 }
Exemplo n.º 22
0
        static void sqlite3EndTable(
            Parse pParse,      /* Parse context */
            Token pCons,       /* The ',' token after the last column defn. */
            Token pEnd,        /* The final ')' token in the CREATE TABLE */
            Select pSelect     /* Select from a "CREATE ... AS SELECT" */
            )
        {
            Table   p;
            sqlite3 db = pParse.db;
            int     iDb;

            if ((pEnd == null && pSelect == null) /*|| db.mallocFailed != 0 */)
            {
                return;
            }
            p = pParse.pNewTable;
            if (p == null)
            {
                return;
            }

            Debug.Assert(0 == db.init.busy || pSelect == null);

            iDb = sqlite3SchemaToIndex(db, p.pSchema);

#if !SQLITE_OMIT_CHECK
            /* Resolve names in all CHECK constraint expressions.
             */
            if (p.pCheck != null)
            {
                SrcList     sSrc;                      /* Fake SrcList for pParse.pNewTable */
                NameContext sNC;                       /* Name context for pParse.pNewTable */

                sNC               = new NameContext(); // memset(sNC, 0, sizeof(sNC));
                sSrc              = new SrcList();     // memset(sSrc, 0, sizeof(sSrc));
                sSrc.nSrc         = 1;
                sSrc.a            = new SrcList_item[1];
                sSrc.a[0]         = new SrcList_item();
                sSrc.a[0].zName   = p.zName;
                sSrc.a[0].pTab    = p;
                sSrc.a[0].iCursor = -1;
                sNC.pParse        = pParse;
                sNC.pSrcList      = sSrc;
                sNC.isCheck       = 1;
                if (sqlite3ResolveExprNames(sNC, ref p.pCheck) != 0)
                {
                    return;
                }
            }
#endif // * !SQLITE_OMIT_CHECK) */

            /* If the db.init.busy is 1 it means we are reading the SQL off the
            ** "sqlite_master" or "sqlite_temp_master" table on the disk.
            ** So do not write to the disk again.  Extract the root page number
            ** for the table from the db.init.newTnum field.  (The page number
            ** should have been put there by the sqliteOpenCb routine.)
            */
            if (db.init.busy != 0)
            {
                p.tnum = db.init.newTnum;
            }

            /* If not initializing, then create a record for the new table
            ** in the SQLITE_MASTER table of the database.
            **
            ** If this is a TEMPORARY table, write the entry into the auxiliary
            ** file instead of into the main database file.
            */
            if (0 == db.init.busy)
            {
                int    n;
                Vdbe   v;
                String zType  = "";   /* "view" or "table" */
                String zType2 = "";   /* "VIEW" or "TABLE" */
                String zStmt  = "";   /* Text of the CREATE TABLE or CREATE VIEW statement */

                v = sqlite3GetVdbe(pParse);
                if (NEVER(v == null))
                {
                    return;
                }

                sqlite3VdbeAddOp1(v, OP_Close, 0);

                /*
                ** Initialize zType for the new view or table.
                */
                if (p.pSelect == null)
                {
                    /* A regular table */
                    zType  = "table";
                    zType2 = "TABLE";
#if !SQLITE_OMIT_VIEW
                }
                else
                {
                    /* A view */
                    zType  = "view";
                    zType2 = "VIEW";
#endif
                }

                /* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
                ** statement to populate the new table. The root-page number for the
                ** new table is in register pParse->regRoot.
                **
                ** Once the SELECT has been coded by sqlite3Select(), it is in a
                ** suitable state to query for the column names and types to be used
                ** by the new table.
                **
                ** A shared-cache write-lock is not required to write to the new table,
                ** as a schema-lock must have already been obtained to create it. Since
                ** a schema-lock excludes all other database users, the write-lock would
                ** be redundant.
                */
                if (pSelect != null)
                {
                    SelectDest dest = new SelectDest();
                    Table      pSelTab;

                    Debug.Assert(pParse.nTab == 1);
                    sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, pParse.regRoot, iDb);
                    sqlite3VdbeChangeP5(v, 1);
                    pParse.nTab = 2;
                    sqlite3SelectDestInit(dest, SRT_Table, 1);
                    sqlite3Select(pParse, pSelect, ref dest);
                    sqlite3VdbeAddOp1(v, OP_Close, 1);
                    if (pParse.nErr == 0)
                    {
                        pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
                        if (pSelTab == null)
                        {
                            return;
                        }
                        Debug.Assert(p.aCol == null);
                        p.nCol       = pSelTab.nCol;
                        p.aCol       = pSelTab.aCol;
                        pSelTab.nCol = 0;
                        pSelTab.aCol = null;
                        sqlite3DeleteTable(db, ref pSelTab);
                    }
                }

                /* Compute the complete text of the CREATE statement */
                if (pSelect != null)
                {
                    zStmt = createTableStmt(db, p);
                }
                else
                {
                    n     = (int)(pParse.sNameToken.z.Length - pEnd.z.Length) + 1;
                    zStmt = sqlite3MPrintf(db,
                                           "CREATE %s %.*s", zType2, n, pParse.sNameToken.z
                                           );
                }

                /* A slot for the record has already been allocated in the
                ** SQLITE_MASTER table.  We just need to update that slot with all
                ** the information we've collected.
                */
                sqlite3NestedParse(pParse,
                                   "UPDATE %Q.%s " +
                                   "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " +
                                   "WHERE rowid=#%d",
                                   db.aDb[iDb].zName, SCHEMA_TABLE(iDb),
                                   zType,
                                   p.zName,
                                   p.zName,
                                   pParse.regRoot,
                                   zStmt,
                                   pParse.regRowid
                                   );
                sqlite3DbFree(db, ref zStmt);
                sqlite3ChangeCookie(pParse, iDb);

#if !SQLITE_OMIT_AUTOINCREMENT
                /* Check to see if we need to create an sqlite_sequence table for
                ** keeping track of autoincrement keys.
                */
                if ((p.tabFlags & TF_Autoincrement) != 0)
                {
                    Db pDb = db.aDb[iDb];
                    Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
                    if (pDb.pSchema.pSeqTab == null)
                    {
                        sqlite3NestedParse(pParse,
                                           "CREATE TABLE %Q.sqlite_sequence(name,seq)",
                                           pDb.zName
                                           );
                    }
                }
#endif

                /* Reparse everything to update our internal data structures */
                sqlite3VdbeAddParseSchemaOp(v, iDb,
                                            sqlite3MPrintf(db, "tbl_name='%q'", p.zName));
            }


            /* Add the table to the in-memory representation of the database.
             */
            if (db.init.busy != 0)
            {
                Table  pOld;
                Schema pSchema = p.pSchema;
                Debug.Assert(sqlite3SchemaMutexHeld(db, iDb, null));
                pOld = sqlite3HashInsert(ref pSchema.tblHash, p.zName,
                                         sqlite3Strlen30(p.zName), p);
                if (pOld != null)
                {
                    Debug.Assert(p == pOld);  /* Malloc must have failed inside HashInsert() */
                    //        db.mallocFailed = 1;
                    return;
                }
                pParse.pNewTable = null;
                db.nTable++;
                db.flags |= SQLITE_InternChanges;

#if !SQLITE_OMIT_ALTERTABLE
                if (p.pSelect == null)
                {
                    string zName = pParse.sNameToken.z;
                    int    nName;
                    Debug.Assert(pSelect == null && pCons != null && pEnd != null);
                    if (pCons.z == null)
                    {
                        pCons = pEnd;
                    }
                    nName          = zName.Length - pCons.z.Length;
                    p.addColOffset = 13 + nName; // sqlite3Utf8CharLen(zName, nName);
                }
#endif
            }
        }
Exemplo n.º 23
0
        static void SelectInnerLoop(Parse parse, Select p, ExprList list, int srcTable, int columns, ExprList orderBy, DistinctCtx distinct, SelectDest dest, int continueId, int breakId)
        {
            Vdbe v = parse.V;

            Debug.Assert(v != null);
            if (C._NEVER(v == null)) return;
            Debug.Assert(list != null);
            WHERE_DISTINCT hasDistinct = (distinct != null ? distinct.TnctType : WHERE_DISTINCT.NOOP); // True if the DISTINCT keyword is present
            if (orderBy == null && hasDistinct == (WHERE_DISTINCT)0)
                CodeOffset(v, p, continueId);

            // Pull the requested columns.
            int resultCols = (columns > 0 ? columns : list.Exprs); // Number of result columns
            if (dest.Sdsts == 0)
            {
                dest.SdstId = parse.Mems + 1;
                dest.Sdsts = resultCols;
                parse.Mems += resultCols;
            }
            else
                Debug.Assert(dest.Sdsts == resultCols);
            int regResult = dest.SdstId; // Start of memory holding result set
            SRT dest2 = dest.Dest; // How to dispose of results
            int i;
            if (columns > 0)
                for (i = 0; i < columns; i++)
                    v.AddOp3(OP.Column, srcTable, i, regResult + i);
            else if (dest2 != SRT.Exists)
            {
                // If the destination is an EXISTS(...) expression, the actual values returned by the SELECT are not required.
                Expr.CacheClear(parse);
                Expr.CodeExprList(parse, list, regResult, dest2 == SRT.Output);
            }
            columns = resultCols;

            // If the DISTINCT keyword was present on the SELECT statement and this row has been seen before, then do not make this row part of the result.
            if (hasDistinct != 0)
            {
                Debug.Assert(list != null);
                Debug.Assert(list.Exprs == columns);
                switch (distinct.TnctType)
                {
                    case WHERE_DISTINCT.ORDERED:
                        {
                            // Allocate space for the previous row
                            int regPrev = parse.Mems + 1; // Previous row content
                            parse.Mems += columns;

                            // Change the OP_OpenEphemeral coded earlier to an OP_Null sets the MEM_Cleared bit on the first register of the
                            // previous value.  This will cause the OP_Ne below to always fail on the first iteration of the loop even if the first
                            // row is all NULLs.
                            v.ChangeToNoop(distinct.AddrTnct);
                            Vdbe.VdbeOp op = v.GetOp(distinct.AddrTnct); // No longer required OpenEphemeral instr.
                            op.Opcode = OP.Null;
                            op.P1 = 1;
                            op.P2 = regPrev;

                            int jumpId = v.CurrentAddr() + columns; // Jump destination
                            for (i = 0; i < columns; i++)
                            {
                                CollSeq coll = list.Ids[i].Expr.CollSeq(parse);
                                if (i < columns - 1)
                                    v.AddOp3(OP.Ne, regResult + i, jumpId, regPrev + i);
                                else
                                    v.AddOp3(OP.Eq, regResult + i, continueId, regPrev + i);
                                v.ChangeP4(-1, coll, Vdbe.P4T.COLLSEQ);
                                v.ChangeP5(AFF.BIT_NULLEQ);
                            }
                            Debug.Assert(v.CurrentAddr() == jumpId);
                            v.AddOp3(OP.Copy, regResult, regPrev, columns - 1);
                            break;
                        }
                    case WHERE_DISTINCT.UNIQUE:
                        {
                            v.ChangeToNoop(distinct.AddrTnct);
                            break;
                        }
                    default:
                        {
                            Debug.Assert(distinct.TnctType == WHERE_DISTINCT.UNORDERED);
                            CodeDistinct(parse, distinct.TableTnct, continueId, columns, regResult);
                            break;
                        }
                }
                if (orderBy != null)
                    CodeOffset(v, p, continueId);
            }

            int paramId = dest.SDParmId; // First argument to disposal method
            switch (dest2)
            {
#if !OMIT_COMPOUND_SELECT
                case SRT.Union:
                    {
                        // In this mode, write each query result to the key of the temporary table iParm.
                        int r1 = Expr.GetTempReg(parse);
                        v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                        v.AddOp2(OP.IdxInsert, paramId, r1);
                        Expr.ReleaseTempReg(parse, r1);
                        break;
                    }
                case SRT.Except:
                    {
                        // Construct a record from the query result, but instead of saving that record, use it as a key to delete elements from
                        // the temporary table iParm.
                        v.AddOp3(OP.IdxDelete, paramId, regResult, columns);
                        break;
                    }
#endif
                case SRT.Table:
                case SRT.EphemTab:
                    {
                        // Store the result as data using a unique key.
                        int r1 = Expr.GetTempReg(parse);
                        C.ASSERTCOVERAGE(dest2 == SRT.Table);
                        C.ASSERTCOVERAGE(dest2 == SRT.EphemTab);
                        v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, r1);
                        else
                        {
                            int r2 = Expr.GetTempReg(parse);
                            v.AddOp2(OP.NewRowid, paramId, r2);
                            v.AddOp3(OP.Insert, paramId, r1, r2);
                            v.ChangeP5(Vdbe.OPFLAG.APPEND);
                            Expr.ReleaseTempReg(parse, r2);
                        }
                        Expr.ReleaseTempReg(parse, r1);
                        break;
                    }
#if !OMIT_SUBQUERY
                case SRT.Set:
                    {
                        // If we are creating a set for an "expr IN (SELECT ...)" construct, then there should be a single item on the stack.  Write this
                        // item into the set table with bogus data.
                        Debug.Assert(columns == 1);
                        dest.AffSdst = list.Ids[0].Expr.CompareAffinity(dest.AffSdst);
                        // At first glance you would think we could optimize out the ORDER BY in this case since the order of entries in the set
                        // does not matter.  But there might be a LIMIT clause, in which case the order does matter
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, regResult);
                        else
                        {
                            int r1 = Expr.GetTempReg(parse);
                            v.AddOp4(OP.MakeRecord, regResult, 1, r1, dest.AffSdst, 1);
                            Expr.CacheAffinityChange(parse, regResult, 1);
                            v.AddOp2(OP.IdxInsert, paramId, r1);
                            Expr.ReleaseTempReg(parse, r1);
                        }
                        break;
                    }
                case SRT.Exists:
                    {
                        // If any row exist in the result set, record that fact and abort.
                        v.AddOp2(OP.Integer, 1, paramId);
                        // The LIMIT clause will terminate the loop for us
                        break;
                    }
                case SRT.Mem:
                    {
                        // If this is a scalar select that is part of an expression, then store the results in the appropriate memory cell and break out
                        // of the scan loop.
                        Debug.Assert(columns == 1);
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, regResult);
                        else
                            Expr.CodeMove(parse, regResult, paramId, 1);
                        // The LIMIT clause will jump out of the loop for us
                        break;
                    }
#endif
                case SRT.Coroutine:
                case SRT.Output:
                    {
                        // Send the data to the callback function or to a subroutine.  In the case of a subroutine, the subroutine itself is responsible for
                        // popping the data from the stack.
                        C.ASSERTCOVERAGE(dest2 == SRT.Coroutine);
                        C.ASSERTCOVERAGE(dest2 == SRT.Output);
                        if (orderBy != null)
                        {
                            int r1 = Expr.GetTempReg(parse);
                            v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                            PushOntoSorter(parse, orderBy, p, r1);
                            Expr.ReleaseTempReg(parse, r1);
                        }
                        else if (dest2 == SRT.Coroutine)
                            v.AddOp1(OP.Yield, dest.SDParmId);
                        else
                        {
                            v.AddOp2(OP.ResultRow, regResult, columns);
                            Expr.CacheAffinityChange(parse, regResult, columns);
                        }
                        break;
                    }
#if !OMIT_TRIGGER
                default:
                    {
                        // Discard the results.  This is used for SELECT statements inside the body of a TRIGGER.  The purpose of such selects is to call
                        // user-defined functions that have side effects.  We do not care about the actual results of the select.
                        Debug.Assert(dest2 == SRT.Discard);
                        break;
                    }
#endif
            }

            // Jump to the end of the loop if the LIMIT is reached.  Except, if there is a sorter, in which case the sorter has already limited the output for us.
            if (orderBy == null && p.LimitId != 0)
                v.AddOp3(OP.IfZero, p.LimitId, breakId, -1);
        }
Exemplo n.º 24
0
    /*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
** If srcTab and nColumn are both zero, then the pEList expressions
** are evaluated in order to get the data for this row.  If nColumn>0
** then data is pulled from srcTab and pEList is used only to get the
** datatypes for each column.
*/
    static void selectInnerLoop(
    Parse pParse,          /* The parser context */
    Select p,              /* The complete select statement being coded */
    ExprList pEList,       /* List of values being extracted */
    int srcTab,            /* Pull data from this table */
    int nColumn,           /* Number of columns in the source table */
    ExprList pOrderBy,     /* If not NULL, sort results using this key */
    int distinct,          /* If >=0, make sure results are distinct */
    SelectDest pDest,      /* How to dispose of the results */
    int iContinue,         /* Jump here to continue with next row */
    int iBreak             /* Jump here to break out of the inner loop */
    )
    {
      Vdbe v = pParse.pVdbe;
      int i;
      bool hasDistinct;         /* True if the DISTINCT keyword is present */
      int regResult;            /* Start of memory holding result set */
      int eDest = pDest.eDest;  /* How to dispose of results */
      int iParm = pDest.iParm;  /* First argument to disposal method */
      int nResultCol;           /* Number of result columns */

      Debug.Assert( v != null );
      if ( NEVER( v == null ) )
        return;
      Debug.Assert( pEList != null );
      hasDistinct = distinct >= 0;
      if ( pOrderBy == null && !hasDistinct )
      {
        codeOffset( v, p, iContinue );
      }

      /* Pull the requested columns.
      */
      if ( nColumn > 0 )
      {
        nResultCol = nColumn;
      }
      else
      {
        nResultCol = pEList.nExpr;
      }
      if ( pDest.iMem == 0 )
      {
        pDest.iMem = pParse.nMem + 1;
        pDest.nMem = nResultCol;
        pParse.nMem += nResultCol;
      }
      else
      {
        Debug.Assert( pDest.nMem == nResultCol );
      }
      regResult = pDest.iMem;
      if ( nColumn > 0 )
      {
        for ( i = 0; i < nColumn; i++ )
        {
          sqlite3VdbeAddOp3( v, OP_Column, srcTab, i, regResult + i );
        }
      }
      else if ( eDest != SRT_Exists )
      {
        /* If the destination is an EXISTS(...) expression, the actual
        ** values returned by the SELECT are not required.
        */
        sqlite3ExprCacheClear( pParse );
        sqlite3ExprCodeExprList( pParse, pEList, regResult, eDest == SRT_Output );
      }
      nColumn = nResultCol;

      /* If the DISTINCT keyword was present on the SELECT statement
      ** and this row has been seen before, then do not make this row
      ** part of the result.
      */
      if ( hasDistinct )
      {
        Debug.Assert( pEList != null );
        Debug.Assert( pEList.nExpr == nColumn );
        codeDistinct( pParse, distinct, iContinue, nColumn, regResult );
        if ( pOrderBy == null )
        {
          codeOffset( v, p, iContinue );
        }
      }

      switch ( eDest )
      {
        /* In this mode, write each query result to the key of the temporary
        ** table iParm.
        */
#if !SQLITE_OMIT_COMPOUND_SELECT
        case SRT_Union:
          {
            int r1;
            r1 = sqlite3GetTempReg( pParse );
            sqlite3VdbeAddOp3( v, OP_MakeRecord, regResult, nColumn, r1 );
            sqlite3VdbeAddOp2( v, OP_IdxInsert, iParm, r1 );
            sqlite3ReleaseTempReg( pParse, r1 );
            break;
          }

        /* Construct a record from the query result, but instead of
        ** saving that record, use it as a key to delete elements from
        ** the temporary table iParm.
        */
        case SRT_Except:
          {
            sqlite3VdbeAddOp3( v, OP_IdxDelete, iParm, regResult, nColumn );
            break;
          }
#endif

        /* Store the result as data using a unique key.
*/
        case SRT_Table:
        case SRT_EphemTab:
          {
            int r1 = sqlite3GetTempReg( pParse );
            testcase( eDest == SRT_Table );
            testcase( eDest == SRT_EphemTab );
            sqlite3VdbeAddOp3( v, OP_MakeRecord, regResult, nColumn, r1 );
            if ( pOrderBy != null )
            {
              pushOntoSorter( pParse, pOrderBy, p, r1 );
            }
            else
            {
              int r2 = sqlite3GetTempReg( pParse );
              sqlite3VdbeAddOp2( v, OP_NewRowid, iParm, r2 );
              sqlite3VdbeAddOp3( v, OP_Insert, iParm, r1, r2 );
              sqlite3VdbeChangeP5( v, OPFLAG_APPEND );
              sqlite3ReleaseTempReg( pParse, r2 );
            }
            sqlite3ReleaseTempReg( pParse, r1 );
            break;
          }

#if !SQLITE_OMIT_SUBQUERY
        /* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack.  Write this
** item into the set table with bogus data.
*/
        case SRT_Set:
          {
            Debug.Assert( nColumn == 1 );
            p.affinity = sqlite3CompareAffinity( pEList.a[0].pExpr, pDest.affinity );
            if ( pOrderBy != null )
            {
              /* At first glance you would think we could optimize out the
              ** ORDER BY in this case since the order of entries in the set
              ** does not matter.  But there might be a LIMIT clause, in which
              ** case the order does matter */
              pushOntoSorter( pParse, pOrderBy, p, regResult );
            }
            else
            {
              int r1 = sqlite3GetTempReg( pParse );
              sqlite3VdbeAddOp4( v, OP_MakeRecord, regResult, 1, r1, p.affinity, 1 );
              sqlite3ExprCacheAffinityChange( pParse, regResult, 1 );
              sqlite3VdbeAddOp2( v, OP_IdxInsert, iParm, r1 );
              sqlite3ReleaseTempReg( pParse, r1 );
            }
            break;
          }

        /* If any row exist in the result set, record that fact and abort.
        */
        case SRT_Exists:
          {
            sqlite3VdbeAddOp2( v, OP_Integer, 1, iParm );
            /* The LIMIT clause will terminate the loop for us */
            break;
          }

        /* If this is a scalar select that is part of an expression, then
        ** store the results in the appropriate memory cell and break out
        ** of the scan loop.
        */
        case SRT_Mem:
          {
            Debug.Assert( nColumn == 1 );
            if ( pOrderBy != null )
            {
              pushOntoSorter( pParse, pOrderBy, p, regResult );
            }
            else
            {
              sqlite3ExprCodeMove( pParse, regResult, iParm, 1 );
              /* The LIMIT clause will jump out of the loop for us */
            }
            break;
          }
#endif // * #if !SQLITE_OMIT_SUBQUERY */

        /* Send the data to the callback function or to a subroutine.  In the
** case of a subroutine, the subroutine itself is responsible for
** popping the data from the stack.
*/
        case SRT_Coroutine:
        case SRT_Output:
          {
            testcase( eDest == SRT_Coroutine );
            testcase( eDest == SRT_Output );
            if ( pOrderBy != null )
            {
              int r1 = sqlite3GetTempReg( pParse );
              sqlite3VdbeAddOp3( v, OP_MakeRecord, regResult, nColumn, r1 );
              pushOntoSorter( pParse, pOrderBy, p, r1 );
              sqlite3ReleaseTempReg( pParse, r1 );
            }
            else if ( eDest == SRT_Coroutine )
            {
              sqlite3VdbeAddOp1( v, OP_Yield, pDest.iParm );
            }
            else
            {
              sqlite3VdbeAddOp2( v, OP_ResultRow, regResult, nColumn );
              sqlite3ExprCacheAffinityChange( pParse, regResult, nColumn );
            }
            break;
          }

#if !SQLITE_OMIT_TRIGGER
        /* Discard the results.  This is used for SELECT statements inside
** the body of a TRIGGER.  The purpose of such selects is to call
** user-defined functions that have side effects.  We do not care
** about the actual results of the select.
*/
        default:
          {
            Debug.Assert( eDest == SRT_Discard );
            break;
          }
#endif
      }

      /* Jump to the end of the loop if the LIMIT is reached.  Except, if
      ** there is a sorter, in which case the sorter has already limited
      ** the output for us.
      */
      if ( pOrderBy == null && p.iLimit != 0 )
      {
        sqlite3VdbeAddOp3( v, OP_IfZero, p.iLimit, iBreak, -1 );
      }
    }
Exemplo n.º 25
0
        static void GenerateSortTail(Parse parse, Select p, Vdbe v, int columns, SelectDest dest)
        {
            int addrBreak = v.MakeLabel(); // Jump here to exit loop
            int addrContinue = v.MakeLabel(); // Jump here for next cycle
            ExprList orderBy = p.OrderBy;
            SRT dest2 = dest.Dest;
            int parmId = dest.SDParmId;

            int tabId = orderBy.ECursor;
            int regRow = Expr.GetTempReg(parse);
            int pseudoTab = 0;
            int regRowid;
            if (dest2 == SRT.Output || dest2 == SRT.Coroutine)
            {
                pseudoTab = parse.Tabs++;
                v.AddOp3(OP.OpenPseudo, pseudoTab, regRow, columns);
                regRowid = 0;
            }
            else
                regRowid = Expr.GetTempReg(parse);
            int addr;
            if ((p.SelFlags & SF.UseSorter) != 0)
            {
                int regSortOut = ++parse.Mems;
                int ptab2 = parse.Tabs++;
                v.AddOp3(OP.OpenPseudo, ptab2, regSortOut, orderBy.Exprs + 2);
                addr = 1 + v.AddOp2(OP.SorterSort, tabId, addrBreak);
                CodeOffset(v, p, addrContinue);
                v.AddOp2(OP.SorterData, tabId, regSortOut);
                v.AddOp3(OP.Column, ptab2, orderBy.Exprs + 1, regRow);
                v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE);
            }
            else
            {
                addr = 1 + v.AddOp2(OP.Sort, tabId, addrBreak);
                CodeOffset(v, p, addrContinue);
                v.AddOp3(OP.Column, tabId, orderBy.Exprs + 1, regRow);
            }
            switch (dest2)
            {
                case SRT.Table:
                case SRT.EphemTab:
                    {
                        C.ASSERTCOVERAGE(dest2 == SRT.Table);
                        C.ASSERTCOVERAGE(dest2 == SRT.EphemTab);
                        v.AddOp2(OP.NewRowid, parmId, regRowid);
                        v.AddOp3(OP.Insert, parmId, regRow, regRowid);
                        v.ChangeP5(Vdbe.OPFLAG.APPEND);
                        break;
                    }
#if !OMIT_SUBQUERY
                case SRT.Set:
                    {
                        Debug.Assert(columns == 1);
                        v.AddOp4(OP.MakeRecord, regRow, 1, regRowid, dest->AffSdst, 1);
                        Expr.CacheAffinityChange(parse, regRow, 1);
                        v.AddOp2(OP.IdxInsert, parmId, regRowid);
                        break;
                    }
                case SRT.Mem:
                    {
                        Debug.Assert(columns == 1);
                        Expr.CodeMove(parse, regRow, parmId, 1);
                        // The LIMIT clause will terminate the loop for us
                        break;
                    }
#endif
                default:
                    {
                        Debug.Assert(dest2 == SRT.Output || dest2 == SRT.Coroutine);
                        C.ASSERTCOVERAGE(dest2 == SRT.Output);
                        C.ASSERTCOVERAGE(dest2 == SRT.Coroutine);
                        for (int i = 0; i < columns; i++)
                        {
                            Debug.Assert(regRow != dest.SdstId + i);
                            v.AddOp3(OP.Column, pseudoTab, i, dest.SdstId + i);
                            if (i == 0)
                                v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE);
                        }
                        if (dest2 == SRT.Output)
                        {
                            v.AddOp2(OP.ResultRow, dest.SdstId, columns);
                            Expr.CacheAffinityChange(parse, dest.SdstId, columns);
                        }
                        else
                            v.AddOp1(OP.Yield, dest.SDParmId);
                        break;
                    }
            }
            Expr.ReleaseTempReg(parse, regRow);
            Expr.ReleaseTempReg(parse, regRowid);

            // The bottom of the loop
            v.ResolveLabel(addrContinue);
            v.AddOp2(OP.Next, tabId, addr);
            v.ResolveLabel(addrBreak);
            if (dest2 == SRT.Output || dest2 == SRT.Coroutine)
                v.AddOp2(OP.Close, pseudoTab, 0);
        }
Exemplo n.º 26
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).  */
		//#if isView
		// #undef isView
		//#endif
		//#if 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 */
		int onError         /* ON CONFLICT strategy */
		)
		{
			Vdbe v = pParse.pVdbe;  /* Virtual machine under construction */
			ExprList pEList = null;     /* The result set of the SELECT statement */
			Select pSelect = null;      /* 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 */
			VTable pVTab = sqlite3GetVTable(db, pTab);
			SelectDest dest = new SelectDest();

			/* 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 != null)
			{
				pEList = sqlite3ExprListAppend(pParse, pEList,
				sqlite3ExprDup(db, pRowid, 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, null, null, null, 0, null, null);

			/* Create the ephemeral table into which the update results will
			** be stored.
			*/
			Debug.Assert(v != null);
			ephemTab = pParse.nTab++;
			sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab.nCol + 1 + ((pRowid != null) ? 1 : 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 != null ? 1 : 0), iReg + 1);
			for (i = 0; i < pTab.nCol; i++)
			{
				sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i + 1 + ((pRowid != null) ? 1 : 0), iReg + 2 + i);
			}
			sqlite3VtabMakeWritable(pParse, pTab);
			sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab.nCol + 2, iReg, pVTab, P4_VTAB);
			sqlite3VdbeChangeP5(v, (byte)(onError == OE_Default ? OE_Abort : onError));
			sqlite3MayAbort(pParse);
			sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr + 1);
			sqlite3VdbeJumpHere(v, addr);
			sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);

			/* Cleanup */
			sqlite3SelectDelete(db, ref pSelect);
		}
Exemplo n.º 27
0
        /*
        ** Generate VDBE code for zero or more statements inside the body of a
        ** trigger.
        */
        static int codeTriggerProgram(
            Parse pParse,          /* The parser context */
            TriggerStep pStepList, /* List of statements inside the trigger body */
            int orconfin           /* Conflict algorithm. (OE_Abort, etc) */
            )
        {
            TriggerStep pTriggerStep = pStepList;
            int         orconf;
            Vdbe        v  = pParse.pVdbe;
            sqlite3     db = pParse.db;

            Debug.Assert(pTriggerStep != null);
            Debug.Assert(v != null);
            sqlite3VdbeAddOp2(v, OP_ContextPush, 0, 0);
#if SQLITE_DEBUG
            VdbeComment(v, "begin trigger %s", pStepList.pTrig.name);
#endif
            while (pTriggerStep != null)
            {
                sqlite3ExprCacheClear(pParse);
                orconf = (orconfin == OE_Default) ? pTriggerStep.orconf : orconfin;
                pParse.trigStack.orconf = orconf;
                switch (pTriggerStep.op)
                {
                case TK_UPDATE:
                {
                    SrcList pSrc;
                    pSrc = targetSrcList(pParse, pTriggerStep);
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
                    sqlite3Update(pParse, pSrc,
                                  sqlite3ExprListDup(db, pTriggerStep.pExprList, 0),
                                  sqlite3ExprDup(db, pTriggerStep.pWhere, 0), orconf);
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
                    break;
                }

                case TK_INSERT:
                {
                    SrcList pSrc;
                    pSrc = targetSrcList(pParse, pTriggerStep);
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
                    sqlite3Insert(pParse, pSrc,
                                  sqlite3ExprListDup(db, pTriggerStep.pExprList, 0),
                                  sqlite3SelectDup(db, pTriggerStep.pSelect, 0),
                                  sqlite3IdListDup(db, pTriggerStep.pIdList), orconf);
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
                    break;
                }

                case TK_DELETE:
                {
                    SrcList pSrc;
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 0, 0);
                    pSrc = targetSrcList(pParse, pTriggerStep);
                    sqlite3DeleteFrom(pParse, pSrc,
                                      sqlite3ExprDup(db, pTriggerStep.pWhere, 0));
                    sqlite3VdbeAddOp2(v, OP_ResetCount, 1, 0);
                    break;
                }

                default: Debug.Assert(pTriggerStep.op == TK_SELECT);
                    {
                        Select ss = sqlite3SelectDup(db, pTriggerStep.pSelect, 0);
                        if (ss != null)
                        {
                            SelectDest dest = new SelectDest();

                            sqlite3SelectDestInit(dest, SRT_Discard, 0);
                            sqlite3Select(pParse, ss, ref dest);
                            sqlite3SelectDelete(db, ref ss);
                        }
                        break;
                    }
                }
                pTriggerStep = pTriggerStep.pNext;
            }
            sqlite3VdbeAddOp2(v, OP_ContextPop, 0, 0);
#if SQLITE_DEBUG
            VdbeComment(v, "end trigger %s", pStepList.pTrig.name);
#endif
            return(0);
        }