Example #1
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 #2
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 #3
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);
        }