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); }
/* ** 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; }
static void DestInit(SelectDest dest, SRT dest2, int parmId) { dest.Dest = dest2; dest.SDParmId = parmId; dest.AffSdst = '\0'; dest.SdstId = 0; dest.Sdsts = 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); }
/* ** 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); }
/* ** 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; }
/* 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; }
/* ** 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; }
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; }
/* ** 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 ); } }
/* ** 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; } }
/* ** 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; }
/* ** 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; }
/* ** 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; }
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 ); }
/* ** 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 ); }
/* 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); }
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 } }
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); }
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; }
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; }
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 } }
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); }
/* ** 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 ); } }
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); }
/* ** 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); }