001package gudusoft.gsqlparser.resolver2.scope;
002
003import gudusoft.gsqlparser.nodes.TExpression;
004import gudusoft.gsqlparser.resolver2.ScopeType;
005
006/**
007 * Scope for HAVING clause.
008 *
009 * <p>Visibility rules:
010 * - Can access GROUP BY columns
011 * - Can access aggregate functions
012 * - Can access SELECT list aliases (in some databases)
013 * - Cannot access non-aggregated columns not in GROUP BY
014 *
015 * <p>Example:
016 * <pre>
017 * SELECT department, COUNT(*) as emp_count
018 * FROM employees
019 * GROUP BY department
020 * HAVING COUNT(*) > 10  -- Can use aggregates
021 *    OR emp_count > 10  -- Can use SELECT list alias (database-dependent)
022 * </pre>
023 *
024 * <p>The HAVING scope has access to:
025 * - GROUP BY scope (for grouped columns)
026 * - SELECT scope (for SELECT list aliases, database-dependent)
027 */
028public class HavingScope extends AbstractScope {
029
030    /** The HAVING condition expression */
031    private final TExpression havingCondition;
032
033    /** Parent GROUP BY scope (for grouped column resolution) */
034    private IScope groupByScope;
035
036    /** Parent SELECT scope (for SELECT list alias resolution) */
037    private IScope selectScope;
038
039    public HavingScope(IScope parent, TExpression havingCondition) {
040        super(parent, havingCondition, ScopeType.HAVING);
041        this.havingCondition = havingCondition;
042    }
043
044    /**
045     * Set the GROUP BY scope for column resolution.
046     * HAVING can reference columns that appear in GROUP BY.
047     *
048     * @param groupByScope the GROUP BY scope
049     */
050    public void setGroupByScope(IScope groupByScope) {
051        this.groupByScope = groupByScope;
052    }
053
054    /**
055     * Set the SELECT scope for alias resolution.
056     * HAVING can reference SELECT list aliases in some databases.
057     *
058     * @param selectScope the SELECT scope
059     */
060    public void setSelectScope(IScope selectScope) {
061        this.selectScope = selectScope;
062    }
063
064    /**
065     * Get the GROUP BY scope.
066     *
067     * @return the GROUP BY scope, or null if not set
068     */
069    public IScope getGroupByScope() {
070        return groupByScope;
071    }
072
073    /**
074     * Get the SELECT scope.
075     *
076     * @return the SELECT scope, or null if not set
077     */
078    public IScope getSelectScope() {
079        return selectScope;
080    }
081
082    public TExpression getHavingCondition() {
083        return havingCondition;
084    }
085
086    @Override
087    public String toString() {
088        return "HavingScope";
089    }
090}