Beispiel #1
0
// 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)
}
Beispiel #2
0
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
}
Beispiel #3
0
// 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
}