Example #1
0
 public static void Delete(Context ctx, ref Select p)
 {
     if (p != null)
     {
         ClearSelect(ctx, p);
         C._tagfree(ctx, ref p);
     }
 }
Example #2
0
 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);
 }
Example #3
0
 public static Select New(Parse parse, ExprList list, SrcList src, Expr where_, ExprList groupBy, Expr having, ExprList orderBy, SF selFlags, Expr limit, Expr offset)
 {
     Context ctx = parse.Ctx;
     Select newSelect = new Select();
     Debug.Assert(ctx.MallocFailed || offset == null || limit != null); // OFFSET implies LIMIT
     // Select standin;
     if (newSelect == null)
     {
         Debug.Assert(ctx.MallocFailed);
         //newSelect = standin;
         //_memset(newSelect, 0, sizeof(newSelect));
     }
     if (list == null)
         list = Expr.ListAppend(parse, null, Expr.Expr_(ctx, TK.ALL, null));
     newSelect.EList = list;
     if (src == null) src = new SrcList();
     newSelect.Src = src;
     newSelect.Where = where_;
     newSelect.GroupBy = groupBy;
     newSelect.Having = having;
     newSelect.OrderBy = orderBy;
     newSelect.SelFlags = selFlags;
     newSelect.OP = TK.SELECT;
     newSelect.Limit = limit;
     newSelect.Offset = offset;
     Debug.Assert(offset == null || limit != null);
     newSelect.AddrOpenEphms[0] = (OP) - 1;
     newSelect.AddrOpenEphms[1] = (OP) - 1;
     newSelect.AddrOpenEphms[2] = (OP) - 1;
     if (ctx.MallocFailed)
     {
         ClearSelect(ctx, newSelect);
         //if (newSelect != standin) C._tagfree(ctx, ref newSelect);
         newSelect = null;
     }
     else
         Debug.Assert(newSelect.Src != null || parse.Errs > 0);
     //Debug.Assert(newSelect != standin);
     return newSelect;
 }
Example #4
0
        static void SelectInnerLoop(Parse parse, Select p, ExprList list, int srcTable, int columns, ExprList orderBy, DistinctCtx distinct, SelectDest dest, int continueId, int breakId)
        {
            Vdbe v = parse.V;

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

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

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

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

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

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

            // Jump to the end of the loop if the LIMIT is reached.  Except, if there is a sorter, in which case the sorter has already limited the output for us.
            if (orderBy == null && p.LimitId != 0)
                v.AddOp3(OP.IfZero, p.LimitId, breakId, -1);
        }
Example #5
0
 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);
     }
 }
Example #6
0
 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);
     }
 }
Example #7
0
 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;
     }
 }
Example #8
0
 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;
 }
Example #9
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); }
Example #10
0
 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;
 }
Example #11
0
 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);
 }
Example #12
0
        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);
        }
Example #13
0
        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);
        }
Example #14
0
        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;
        }
Example #15
0
        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;
        }
Example #16
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);
        }
Example #17
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;
 }
Example #18
0
 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;
 }