// analyzeExpr performs semantic analysis of an axpression, including: // - replacing sub-queries by a sql.subquery node; // - resolving qnames (optional); // - type checking (with optional type enforcement); // - normalization. // The parameters tables and qvals, if both are non-nil, indicate // qname resolution should be performed. The qvals map will be filled // as a result. func (p *planner) analyzeExpr( raw parser.Expr, /* arguments for qname resolution */ tables []*tableInfo, qvals qvalMap, /* arguments for type checking */ expectedType parser.Datum, requireType bool, typingContext string, ) (parser.TypedExpr, error) { // Replace the sub-queries. // In all contexts that analyze a single expression, a single value // is expected. Tell this to replaceSubqueries. (See UPDATE for a // counter-example; cases where a subquery is an operand of a // comparison are handled specially in the subqueryVisitor already.) replaced, err := p.replaceSubqueries(raw, 1 /* one value expected */) if err != nil { return nil, err } // Perform optional qname resolution. var resolved parser.Expr if tables == nil || qvals == nil { resolved = replaced } else { resolved, err = resolveQNames(replaced, tables, qvals, &p.qnameVisitor) if err != nil { return nil, err } } // Type check. var typedExpr parser.TypedExpr if requireType { typedExpr, err = parser.TypeCheckAndRequire(resolved, &p.semaCtx, expectedType, typingContext) } else { typedExpr, err = parser.TypeCheck(resolved, &p.semaCtx, expectedType) } if err != nil { return nil, err } // Normalize. return p.parser.NormalizeExpr(&p.evalCtx, typedExpr) }
func (s *selectNode) initWhere(where *parser.Where) error { if where == nil { return nil } var untypedFilter parser.Expr var err error untypedFilter, err = s.planner.replaceSubqueries(where.Expr, 1) if err != nil { return err } untypedFilter, err = s.resolveQNames(untypedFilter) if err != nil { return err } s.filter, err = parser.TypeCheckAndRequire(untypedFilter, &s.planner.semaCtx, parser.TypeBool, "WHERE") if err != nil { return err } // Normalize the expression (this will also evaluate any branches that are // constant). s.filter, err = s.planner.parser.NormalizeExpr(s.planner.evalCtx, s.filter) if err != nil { return err } // Make sure there are no aggregation functions in the filter (after subqueries have been // expanded). if s.planner.aggregateInExpr(s.filter) { return fmt.Errorf("aggregate functions are not allowed in WHERE") } return nil }
// limit constructs a limitNode based on the LIMIT and OFFSET clauses. func (p *planner) Limit(n *parser.Limit) (*limitNode, error) { if n == nil || (n.Count == nil && n.Offset == nil) { // No LIMIT nor OFFSET; there is nothing special to do. return nil, nil } res := limitNode{p: p} data := []struct { name string src parser.Expr dst *parser.TypedExpr }{ {"LIMIT", n.Count, &res.countExpr}, {"OFFSET", n.Offset, &res.offsetExpr}, } for _, datum := range data { if datum.src != nil { replaced, err := p.replaceSubqueries(datum.src, 1) if err != nil { return nil, err } typedExpr, err := parser.TypeCheckAndRequire(replaced, &p.semaCtx, parser.TypeInt, datum.name) if err != nil { return nil, err } normalized, err := p.parser.NormalizeExpr(p.evalCtx, typedExpr) if err != nil { return nil, err } *datum.dst = normalized } } return &res, nil }