@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);
    }
  }
 @Override
 public void visit(ExpressionList el) {
   for (Iterator iter = el.getExpressions().iterator(); iter.hasNext(); ) {
     Expression expression = (Expression) iter.next();
     expression.accept(this);
   }
 }