public static void Delete(Context ctx, ref Select p) { if (p != null) { ClearSelect(ctx, p); C._tagfree(ctx, ref p); } }
static void ClearSelect(Context ctx, Select p) { Expr.ListDelete(ctx, ref p.EList); Parse.SrcListDelete(ctx, ref p.Src); Expr.Delete(ctx, ref p.Where); Expr.ListDelete(ctx, ref p.GroupBy); Expr.Delete(ctx, ref p.Having); Expr.ListDelete(ctx, ref p.OrderBy); Select.Delete(ctx, ref p.Prior); Expr.Delete(ctx, ref p.Limit); Expr.Delete(ctx, ref p.Offset); }
public static Select New(Parse parse, ExprList list, SrcList src, Expr where_, ExprList groupBy, Expr having, ExprList orderBy, SF selFlags, Expr limit, Expr offset) { Context ctx = parse.Ctx; Select newSelect = new Select(); Debug.Assert(ctx.MallocFailed || offset == null || limit != null); // OFFSET implies LIMIT // Select standin; if (newSelect == null) { Debug.Assert(ctx.MallocFailed); //newSelect = standin; //_memset(newSelect, 0, sizeof(newSelect)); } if (list == null) list = Expr.ListAppend(parse, null, Expr.Expr_(ctx, TK.ALL, null)); newSelect.EList = list; if (src == null) src = new SrcList(); newSelect.Src = src; newSelect.Where = where_; newSelect.GroupBy = groupBy; newSelect.Having = having; newSelect.OrderBy = orderBy; newSelect.SelFlags = selFlags; newSelect.OP = TK.SELECT; newSelect.Limit = limit; newSelect.Offset = offset; Debug.Assert(offset == null || limit != null); newSelect.AddrOpenEphms[0] = (OP) - 1; newSelect.AddrOpenEphms[1] = (OP) - 1; newSelect.AddrOpenEphms[2] = (OP) - 1; if (ctx.MallocFailed) { ClearSelect(ctx, newSelect); //if (newSelect != standin) C._tagfree(ctx, ref newSelect); newSelect = null; } else Debug.Assert(newSelect.Src != null || parse.Errs > 0); //Debug.Assert(newSelect != standin); return newSelect; }
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); }
static void CodeOffset(Vdbe v, Select p, int continueId) { if (p.OffsetId != 0 && continueId != 0) { v.AddOp2(OP.AddImm, p.OffsetId, -1); int addr = v.AddOp1(OP.IfNeg, p.OffsetId); v.AddOp2(OP.Goto, 0, continueId); v.Comment("skip OFFSET records"); v.JumpHere(addr); } }
static void PushOntoSorter(Parse parse, ExprList orderBy, Select select, int regData) { Vdbe v = parse.V; int exprs = orderBy.Exprs; int regBase = Expr.GetTempRange(parse, exprs + 2); int regRecord = Expr.GetTempReg(parse); Expr.CacheClear(parse); Expr.CodeExprList(parse, orderBy, regBase, false); v.AddOp2(OP.Sequence, orderBy.ECursor, regBase + exprs); Expr.CodeMove(parse, regData, regBase + exprs + 1, 1); v.AddOp3(OP.MakeRecord, regBase, exprs + 2, regRecord); v.AddOp2(OP.IdxInsert, orderBy.ECursor, regRecord); Expr.ReleaseTempReg(parse, regRecord); Expr.ReleaseTempRange(parse, regBase, exprs + 2); if (select.LimitId != 0) { int limitId = (select.OffsetId != 0 ? select.OffsetId + 1 : select.LimitId); int addr1 = v.AddOp1(OP.IfZero, limitId); v.AddOp2(OP.AddImm, limitId, -1); int addr2 = v.AddOp0(OP.Goto); v.JumpHere(addr1); v.AddOp1(OP.Last, orderBy.ECursor); v.AddOp1(OP.Delete, orderBy.ECursor); v.JumpHere(addr2); } }
static void SelectAddColumnTypeAndCollation(Parse parse, int colsLength, Column[] cols, Select select) { Context ctx = parse.Ctx; Debug.Assert(select != null); Debug.Assert((select.SelFlags & SF.Resolved) != 0); Debug.Assert(colsLength == select.EList.Exprs || ctx.MallocFailed); if (ctx.MallocFailed) return; NameContext sNC = new NameContext(); sNC.SrcList = select.Src; ExprList.ExprListItem[] ids = select.EList.Ids; int i; Column col; for (i = 0; i < colsLength; i++) { col = cols[i]; Expr p = ids[i].Expr; string dummy1 = null; col.Type = ColumnType(sNC, p, ref dummy1, ref dummy1, ref dummy1); col.Affinity = p.Affinity(); if (col.Affinity == 0) col.Affinity = AFF.NONE; CollSeq coll = p.CollSeq(parse); if (coll != null) col.Coll = coll.Name; } }
static int ResolveOrderByTermToExprList(Parse parse, Select select, Expr expr) { int i = 0; Debug.Assert(!expr.IsInteger(ref i)); ExprList list = select.EList; // The columns of the result set // Resolve all names in the ORDER BY term expression NameContext nc = new NameContext(); // Name context for resolving pE nc.Parse = parse; nc.SrcList = select.Src; nc.EList = list; nc.NCFlags = NC.AllowAgg; nc.Errs = 0; Context ctx = parse.Ctx; // Database connection byte savedSuppErr = ctx.SuppressErr; // Saved value of db->suppressErr ctx.SuppressErr = 1; bool r = Walker.ResolveExprNames(nc, ref expr); ctx.SuppressErr = savedSuppErr; if (r) return 0; // Try to match the ORDER BY expression against an expression in the result set. Return an 1-based index of the matching result-set entry. for (i = 0; i < list.Exprs; i++) if (Expr.Compare(list.Ids[i].Expr, expr) < 2) return i + 1; // If no match, return 0. return 0; }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, int null_4, Select select, OE orconf) { return TriggerInsertStep(ctx, tableName, column, null, select, orconf); }
public static TriggerStep SelectStep(Context ctx, Select select) { TriggerStep triggerStep = new TriggerStep(); //: _tagalloc(ctx, sizeof(TriggerStep), true); if (triggerStep == null) { Select.Delete(ctx, ref select); return null; } triggerStep.OP = TK.SELECT; triggerStep.Select = select; triggerStep.Orconf = OE.Default; return triggerStep; }
public static void ResolveSelectNames(Parse parse, Select p, NameContext outerNC) { Debug.Assert(p != null); Walker w = new Walker(); w.ExprCallback = ResolveExprStep; w.SelectCallback = ResolveSelectStep; w.Parse = parse; w.u.NC = outerNC; w.WalkSelect(p); }
static WRC ResolveSelectStep(Walker walker, Select p) { Debug.Assert(p != null); if ((p.SelFlags & SF.Resolved) != 0) return WRC.Prune; NameContext outerNC = walker.u.NC; // Context that contains this SELECT Parse parse = walker.Parse; // Parsing context Context ctx = parse.Ctx; // Database connection // Normally sqlite3SelectExpand() will be called first and will have already expanded this SELECT. However, if this is a subquery within // an expression, sqlite3ResolveExprNames() will be called without a prior call to sqlite3SelectExpand(). When that happens, let // sqlite3SelectPrep() do all of the processing for this SELECT. sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and // this routine in the correct order. if ((p.SelFlags & SF.Expanded) == 0) { p.Prep(parse, outerNC); return (parse.Errs != 0 || ctx.MallocFailed ? WRC.Abort : WRC.Prune); } bool isCompound = (p.Prior != null); // True if p is a compound select int compounds = 0; // Number of compound terms processed so far Select leftmost = p; // Left-most of SELECT of a compound int i; NameContext nc; // Name context of this SELECT while (p != null) { Debug.Assert((p.SelFlags & SF.Expanded) != 0); Debug.Assert((p.SelFlags & SF.Resolved) == 0); p.SelFlags |= SF.Resolved; // Resolve the expressions in the LIMIT and OFFSET clauses. These are not allowed to refer to any names, so pass an empty NameContext. nc = new NameContext(); //: _memset(&nc, 0, sizeof(nc)); nc.Parse = parse; if (Walker.ResolveExprNames(nc, ref p.Limit) || Walker.ResolveExprNames(nc, ref p.Offset)) return WRC.Abort; // Recursively resolve names in all subqueries SrcList.SrcListItem item; for (i = 0; i < p.Src.Srcs; i++) { item = p.Src.Ids[i]; if (item.Select != null) { NameContext nc2; // Used to iterate name contexts int refs = 0; // Refcount for pOuterNC and outer contexts string savedContext = parse.AuthContext; // Count the total number of references to pOuterNC and all of its parent contexts. After resolving references to expressions in // pItem->pSelect, check if this value has changed. If so, then SELECT statement pItem->pSelect must be correlated. Set the // pItem->isCorrelated flag if this is the case. for (nc2 = outerNC; nc2 != null; nc2 = nc2.Next) refs += nc2.Refs; if (item.Name != null) parse.AuthContext = item.Name; Walker.ResolveSelectNames(parse, item.Select, outerNC); parse.AuthContext = savedContext; if (parse.Errs != 0 || ctx.MallocFailed) return WRC.Abort; for (nc2 = outerNC; nc2 != null; nc2 = nc2.Next) refs -= nc2.Refs; Debug.Assert(!item.IsCorrelated && refs <= 0); item.IsCorrelated = (refs != 0); } } // Set up the local name-context to pass to sqlite3ResolveExprNames() to resolve the result-set expression list. nc.NCFlags = NC.AllowAgg; nc.SrcList = p.Src; nc.Next = outerNC; // Resolve names in the result set. ExprList list = p.EList; // Result set expression list Debug.Assert(list != null); for (i = 0; i < list.Exprs; i++) { Expr expr = list.Ids[i].Expr; if (Walker.ResolveExprNames(nc, ref expr)) return WRC.Abort; } // If there are no aggregate functions in the result-set, and no GROUP BY expression, do not allow aggregates in any of the other expressions. Debug.Assert((p.SelFlags & SF.Aggregate) == 0); ExprList groupBy = p.GroupBy; // The GROUP BY clause if (groupBy != null || (nc.NCFlags & NC.HasAgg) != 0) p.SelFlags |= SF.Aggregate; else nc.NCFlags &= ~NC.AllowAgg; // If a HAVING clause is present, then there must be a GROUP BY clause. if (p.Having != null && groupBy == null) { parse.ErrorMsg("a GROUP BY clause is required before HAVING"); return WRC.Abort; } // Add the expression list to the name-context before parsing the other expressions in the SELECT statement. This is so that // expressions in the WHERE clause (etc.) can refer to expressions by aliases in the result set. // // Minor point: If this is the case, then the expression will be re-evaluated for each reference to it. nc.EList = p.EList; if (Walker.ResolveExprNames(nc, ref p.Where) || Walker.ResolveExprNames(nc, ref p.Having)) return WRC.Abort; // The ORDER BY and GROUP BY clauses may not refer to terms in outer queries nc.Next = null; nc.NCFlags |= NC.AllowAgg; // Process the ORDER BY clause for singleton SELECT statements. The ORDER BY clause for compounds SELECT statements is handled // below, after all of the result-sets for all of the elements of the compound have been resolved. if (!isCompound && Walker.ResolveOrderGroupBy(nc, p, p.OrderBy, "ORDER")) return WRC.Abort; if (ctx.MallocFailed) return WRC.Abort; // Resolve the GROUP BY clause. At the same time, make sure the GROUP BY clause does not contain aggregate functions. if (groupBy != null) { if (Walker.ResolveOrderGroupBy(nc, p, groupBy, "GROUP") || ctx.MallocFailed) return WRC.Abort; ExprList.ExprListItem item2; for (i = 0; i < groupBy.Exprs; i++) { item2 = groupBy.Ids[i]; if (E.ExprHasProperty(item2.Expr, EP.Agg)) { parse.ErrorMsg("aggregate functions are not allowed in the GROUP BY clause"); return WRC.Abort; } } } // Advance to the next term of the compound p = p.Prior; compounds++; } // Resolve the ORDER BY on a compound SELECT after all terms of the compound have been resolved. return (isCompound && ResolveCompoundOrderBy(parse, leftmost) != 0 ? WRC.Abort : WRC.Prune); }
static bool ResolveOrderGroupBy(NameContext nc, Select select, ExprList orderBy, string type) { if (orderBy == null) return false; int result = select.EList.Exprs; // Number of terms in the result set Parse parse = nc.Parse; // Parsing context int i; ExprList.ExprListItem item; // A term of the ORDER BY clause for (i = 0; i < orderBy.Exprs; i++) { item = orderBy.Ids[i]; Expr expr = item.Expr; int colId = ResolveAsName(parse, select.EList, expr); // Column number if (colId > 0) { // If an AS-name match is found, mark this ORDER BY column as being a copy of the iCol-th result-set column. The subsequent call to // sqlite3ResolveOrderGroupBy() will convert the expression to a copy of the iCol-th result-set expression. item.OrderByCol = (ushort)colId; continue; } if (expr.SkipCollate().IsInteger(ref colId)) { // The ORDER BY term is an integer constant. Again, set the column number so that sqlite3ResolveOrderGroupBy() will convert the // order-by term to a copy of the result-set expression if (colId < 1 || colId > 0xffff) { ResolveOutOfRangeError(parse, type, i + 1, result); return true; } item.OrderByCol = (ushort)colId; continue; } // Otherwise, treat the ORDER BY term as an ordinary expression item.OrderByCol = 0; if (Walker.ResolveExprNames(nc, ref expr)) return true; for (int j = 0; j < select.EList.Exprs; j++) if (Expr.Compare(expr, select.EList.Ids[j].Expr) == 0) item.OrderByCol = (ushort)(j + 1); } return Walker.ResolveOrderGroupBy(parse, select, orderBy, type); }
public static bool ResolveOrderGroupBy(Parse parse, Select select, ExprList orderBy, string type) { Context ctx = parse.Ctx; if (orderBy == null || parse.Ctx.MallocFailed) return 0; #if !MAX_COLUMN if (orderBy.Exprs > ctx.Limits[(int)LIMIT.COLUMN]) { parse.ErrorMsg("too many terms in %s BY clause", type); return true; } #endif ExprList list = select.EList; Debug.Assert(list != null); // sqlite3SelectNew() guarantees this int i; ExprList.ExprListItem item; for (i = 0; i < orderBy.Exprs; i++) { item = orderBy.Ids[i]; if (item.OrderByCol != null) { if (item.OrderByCol > list.Exprs) { ResolveOutOfRangeError(parse, type, i + 1, list.Exprs); return true; } ResolveAlias(parse, list, item.OrderByCol - 1, item.Expr, type); } } return false; }
static int ResolveCompoundOrderBy(Parse parse, Select select) { ExprList orderBy = select.OrderBy; if (orderBy == null) return 0; Context ctx = parse.Ctx; #if true || MAX_COLUMN if (orderBy.Exprs > ctx.Limits[(int)LIMIT.COLUMN]) { parse.ErrorMsg("too many terms in ORDER BY clause"); return 1; } #endif int i; for (i = 0; i < orderBy.Exprs; i++) orderBy.Ids[i].Done = false; select.Next = null; while (select.Prior != null) { select.Prior.Next = select; select = select.Prior; } bool moreToDo = true; while (select != null && moreToDo) { moreToDo = false; ExprList list = select.EList; Debug.Assert(list != null); ExprList.ExprListItem item; for (i = 0; i < orderBy.Exprs; i++) { item = orderBy.Ids[i]; Expr pDup; if (item.Done) continue; Expr expr = item.Expr; int colId = -1; if (expr.IsInteger(ref colId)) { if (colId <= 0 || colId > list.Exprs) { ResolveOutOfRangeError(parse, "ORDER", i + 1, list.Exprs); return 1; } } else { colId = ResolveAsName(parse, list, expr); if (colId == 0) { Expr dupExpr = Expr.Dup(ctx, expr, 0); if (!ctx.MallocFailed) { Debug.Assert(dupExpr != null); colId = ResolveOrderByTermToExprList(parse, select, dupExpr); } Expr.Delete(ctx, ref dupExpr); } } if (colId > 0) { // Convert the ORDER BY term into an integer column number iCol, taking care to preserve the COLLATE clause if it exists Expr newExpr = Expr.Expr_(ctx, TK.INTEGER, null); if (newExpr == null) return 1; newExpr.Flags |= EP.IntValue; newExpr.u.I = colId; if (item.Expr == expr) item.Expr = newExpr; else { Debug.Assert(item.Expr.OP == TK.COLLATE); Debug.Assert(item.Expr.Left == expr); item.Expr.Left = newExpr; } Expr.Delete(ctx, ref expr); item.OrderByCol = (ushort)colId; item.Done = true; } else moreToDo = true; } select = select.Next; } for (i = 0; i < orderBy.Exprs; i++) { if (!orderBy.Ids[i].Done) { parse.ErrorMsg("%r ORDER BY term does not match any column in the result set", i + 1); return 1; } } return 0; }
static void GenerateSortTail(Parse parse, Select p, Vdbe v, int columns, SelectDest dest) { int addrBreak = v.MakeLabel(); // Jump here to exit loop int addrContinue = v.MakeLabel(); // Jump here for next cycle ExprList orderBy = p.OrderBy; SRT dest2 = dest.Dest; int parmId = dest.SDParmId; int tabId = orderBy.ECursor; int regRow = Expr.GetTempReg(parse); int pseudoTab = 0; int regRowid; if (dest2 == SRT.Output || dest2 == SRT.Coroutine) { pseudoTab = parse.Tabs++; v.AddOp3(OP.OpenPseudo, pseudoTab, regRow, columns); regRowid = 0; } else regRowid = Expr.GetTempReg(parse); int addr; if ((p.SelFlags & SF.UseSorter) != 0) { int regSortOut = ++parse.Mems; int ptab2 = parse.Tabs++; v.AddOp3(OP.OpenPseudo, ptab2, regSortOut, orderBy.Exprs + 2); addr = 1 + v.AddOp2(OP.SorterSort, tabId, addrBreak); CodeOffset(v, p, addrContinue); v.AddOp2(OP.SorterData, tabId, regSortOut); v.AddOp3(OP.Column, ptab2, orderBy.Exprs + 1, regRow); v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE); } else { addr = 1 + v.AddOp2(OP.Sort, tabId, addrBreak); CodeOffset(v, p, addrContinue); v.AddOp3(OP.Column, tabId, orderBy.Exprs + 1, regRow); } switch (dest2) { case SRT.Table: case SRT.EphemTab: { C.ASSERTCOVERAGE(dest2 == SRT.Table); C.ASSERTCOVERAGE(dest2 == SRT.EphemTab); v.AddOp2(OP.NewRowid, parmId, regRowid); v.AddOp3(OP.Insert, parmId, regRow, regRowid); v.ChangeP5(Vdbe.OPFLAG.APPEND); break; } #if !OMIT_SUBQUERY case SRT.Set: { Debug.Assert(columns == 1); v.AddOp4(OP.MakeRecord, regRow, 1, regRowid, dest->AffSdst, 1); Expr.CacheAffinityChange(parse, regRow, 1); v.AddOp2(OP.IdxInsert, parmId, regRowid); break; } case SRT.Mem: { Debug.Assert(columns == 1); Expr.CodeMove(parse, regRow, parmId, 1); // The LIMIT clause will terminate the loop for us break; } #endif default: { Debug.Assert(dest2 == SRT.Output || dest2 == SRT.Coroutine); C.ASSERTCOVERAGE(dest2 == SRT.Output); C.ASSERTCOVERAGE(dest2 == SRT.Coroutine); for (int i = 0; i < columns; i++) { Debug.Assert(regRow != dest.SdstId + i); v.AddOp3(OP.Column, pseudoTab, i, dest.SdstId + i); if (i == 0) v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE); } if (dest2 == SRT.Output) { v.AddOp2(OP.ResultRow, dest.SdstId, columns); Expr.CacheAffinityChange(parse, dest.SdstId, columns); } else v.AddOp1(OP.Yield, dest.SDParmId); break; } } Expr.ReleaseTempReg(parse, regRow); Expr.ReleaseTempReg(parse, regRowid); // The bottom of the loop v.ResolveLabel(addrContinue); v.AddOp2(OP.Next, tabId, addr); v.ResolveLabel(addrBreak); if (dest2 == SRT.Output || dest2 == SRT.Coroutine) v.AddOp2(OP.Close, pseudoTab, 0); }
public static TriggerStep TriggerInsertStep(Context ctx, Token tableName, IdList column, ExprList list, Select select, OE orconf) { Debug.Assert(list == null || select == null); Debug.Assert(list != null || select != null || ctx.MallocFailed); TriggerStep triggerStep = TriggerStepAllocate(ctx, TK.INSERT, tableName); if (triggerStep != null) { triggerStep.Select = Select.Dup(ctx, select, E.EXPRDUP_REDUCE); triggerStep.IdList = column; triggerStep.ExprList = Expr.ListDup(ctx, list, E.EXPRDUP_REDUCE); triggerStep.Orconf = orconf; } else Expr.IdListDelete(ctx, ref column); Expr.ListDelete(ctx, ref list); Select.Delete(ctx, ref select); return triggerStep; }
public bool FixSelect(Select select) { while (select != null) { if (FixExprList(select.EList) || FixSrcList(select.Src) || FixExpr(select.Where) || FixExpr(select.Having)) return true; select = select.Prior; } return false; }