@Override
  public void visit(Function function) {
    // all aggregate functions (SUM, AVG, COUNT, MAX, MIN) have only one parameter (Expression)
    // although COUNT(*) has no parameters
    // EXTRACT_YEAR has one parameter
    // if you change this method, NameProjectVisitor.visit(Function) has to be changed as well
    ExpressionList params = function.getParameters();
    int numParams = 0;
    if (params != null) {
      params.accept(this);

      // in order to determine the size
      List<Expression> listParams = params.getExpressions();
      numParams = listParams.size();
    }
    List<ValueExpression> expressions = new ArrayList<ValueExpression>();
    for (int i = 0; i < numParams; i++) {
      expressions.add(_exprStack.pop());
    }
    Collections.reverse(expressions); // at the stack top is the lastly added VE

    String fnName = function.getName();
    if (fnName.equalsIgnoreCase("EXTRACT_YEAR")) {
      if (numParams != 1) {
        throw new RuntimeException("EXTRACT_YEAR function has exactly one parameter!");
      }
      ValueExpression expr = expressions.get(0);
      ValueExpression ve = new IntegerYearFromDate(expr);
      _exprStack.push(ve);
    }
  }
 public SelectOperator getSelectOperator() {
   if (_predStack.size() != 1) {
     throw new RuntimeException(
         "After WhereVisitor is done, it should contain one predicate exactly!");
   }
   return new SelectOperator(_predStack.peek());
 }
  @Override
  public void visit(Division dvsn) {
    visitBinaryOperation(dvsn);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ValueExpression division = new plan_runner.expressions.Division(left, right);
    _exprStack.push(division);
  }
  @Override
  public void visit(NotEqualsTo net) {
    visitBinaryOperation(net);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ComparisonPredicate cp = new ComparisonPredicate(ComparisonPredicate.NONEQUAL_OP, left, right);
    _predStack.push(cp);
  }
  @Override
  public void visit(MinorThan mt) {
    visitBinaryOperation(mt);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ComparisonPredicate cp = new ComparisonPredicate(ComparisonPredicate.LESS_OP, left, right);
    _predStack.push(cp);
  }
  @Override
  public void visit(GreaterThanEquals gte) {
    visitBinaryOperation(gte);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ComparisonPredicate cp = new ComparisonPredicate(ComparisonPredicate.NONLESS_OP, left, right);
    _predStack.push(cp);
  }
  @Override
  public void visit(LikeExpression le) {
    visitBinaryOperation(le);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    LikePredicate lp = new LikePredicate(left, right);
    _predStack.push(lp);
  }
  @Override
  public void visit(Subtraction s) {
    visitBinaryOperation(s);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ValueExpression sub = new plan_runner.expressions.Subtraction(left, right);
    _exprStack.push(sub);
  }
  /*
   * Each of these operations create a Squall type, that's why so much similar code
   */
  @Override
  public void visit(Addition adtn) {
    visitBinaryOperation(adtn);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ValueExpression add = new plan_runner.expressions.Addition(left, right);
    _exprStack.push(add);
  }
  @Override
  public void visit(Multiplication m) {
    visitBinaryOperation(m);

    ValueExpression right = _exprStack.pop();
    ValueExpression left = _exprStack.pop();

    ValueExpression mult = new plan_runner.expressions.Multiplication(left, right);
    _exprStack.push(mult);
  }
  @Override
  public void visit(OrExpression oe) {
    visitBinaryOperation(oe);

    Predicate right = _predStack.pop();
    Predicate left = _predStack.pop();

    Predicate or = new OrPredicate(left, right);
    _predStack.push(or);
  }
  @Override
  public void visit(AndExpression ae) {
    visitBinaryOperation(ae);

    Predicate right = _predStack.pop();
    Predicate left = _predStack.pop();

    Predicate and = new AndPredicate(left, right);
    _predStack.push(and);
  }
  @Override
  public void visit(Column column) {
    // extract type for the column
    TypeConversion tc = _schema.getType(ParserUtil.getFullSchemaColumnName(column, _tan));

    // extract the position (index) of the required column
    int position = _it.getColumnIndex(column, _affectedComponent);

    ValueExpression ve = new ColumnReference(tc, position);
    _exprStack.push(ve);
  }
 protected void pushToExprStack(ValueExpression ve) {
   _exprStack.push(ve);
 }
 @Override
 public void visit(LongValue lv) {
   ValueExpression ve = new ValueSpecification(_lc, lv.getValue());
   _exprStack.push(ve);
 }
 @Override
 public void visit(StringValue sv) {
   ValueExpression ve = new ValueSpecification(_sc, sv.getValue());
   _exprStack.push(ve);
 }
 @Override
 public void visit(DateValue dv) {
   ValueExpression ve = new ValueSpecification(_dateConv, dv.getValue());
   _exprStack.push(ve);
 }