@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(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 ExpressionList params = function.getParameters(); if (params != null) { List<Expression> listParams = params.getExpressions(); for (Expression param : listParams) { param.accept(this); } } }
// my VISITOR methods @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 ExpressionList params = function.getParameters(); int numParams = 0; if (params != null) { List<Expression> listParams = params.getExpressions(); numParams = listParams.size(); for (Expression param : listParams) { param.accept(this); } } List<ValueExpression> expressions = new ArrayList<ValueExpression>(); for (int i = 0; i < numParams; i++) { expressions.add(_exprStack.pop()); } String fnName = function.getName(); if (fnName.equalsIgnoreCase("SUM")) { // there must be only one parameter, if not SQL parser will raise an exception ValueExpression expr = expressions.get(0); NumericConversion numConv = (NumericConversion) expr.getType(); _agg = new AggregateSumOperator(numConv, expr, _map); // DISTINCT and agg are stored on the same component. if (function.isDistinct()) { DistinctOperator distinct = new DistinctOperator(_map, expressions); _agg.setDistinct(distinct); } } else if (fnName.equalsIgnoreCase("COUNT")) { // COUNT(R.A) and COUNT(1) have the same semantics as COUNT(*), since we do not have NULLs in // R.A _agg = new AggregateCountOperator(_map); // DISTINCT and agg are stored on the same component. if (function.isDistinct()) { DistinctOperator distinct = new DistinctOperator(_map, expressions); _agg.setDistinct(distinct); } } else 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); } }
/** * Recursive methods to create a {@link Function} starting from a {@link BinaryExpression} We * consider all possible values of the left and right expressions * * @param pred * @param lookupTable * @return */ private Function getFunction(Expression pred, LookupTable lookupTable) { if (pred instanceof BinaryExpression) { return getFunction((BinaryExpression) pred, lookupTable); } else if (pred instanceof IsNullExpression) { return getFunction((IsNullExpression) pred, lookupTable); } else if (pred instanceof Parenthesis) { Expression inside = ((Parenthesis) pred).getExpression(); return getFunction(inside, lookupTable); } else if (pred instanceof Between) { Between between = (Between) pred; Expression left = between.getLeftExpression(); Expression e1 = between.getBetweenExpressionStart(); Expression e2 = between.getBetweenExpressionEnd(); GreaterThanEquals gte = new GreaterThanEquals(); gte.setLeftExpression(left); gte.setRightExpression(e1); MinorThanEquals mte = new MinorThanEquals(); mte.setLeftExpression(left); mte.setRightExpression(e2); AndExpression ande = new AndExpression(gte, mte); return getFunction(ande, lookupTable); } else if (pred instanceof InExpression) { InExpression inExpr = (InExpression) pred; Expression left = inExpr.getLeftExpression(); ExpressionList ilist = (ExpressionList) inExpr.getRightItemsList(); List<EqualsTo> eqList = new ArrayList<EqualsTo>(); for (Expression item : ilist.getExpressions()) { EqualsTo eq = new EqualsTo(); eq.setLeftExpression(left); eq.setRightExpression(item); eqList.add(eq); } int size = eqList.size(); if (size > 1) { OrExpression or = new OrExpression(eqList.get(size - 1), eqList.get(size - 2)); for (int i = size - 3; i >= 0; i--) { OrExpression orexpr = new OrExpression(eqList.get(i), or); or = orexpr; } return getFunction(or, lookupTable); } else { return getFunction(eqList.get(0), lookupTable); } } else return null; }
@Override public void visit(ExpressionList el) { for (Iterator iter = el.getExpressions().iterator(); iter.hasNext(); ) { Expression expression = (Expression) iter.next(); expression.accept(this); } }
@Override public void visit(Function function) { boolean recognized = isRecognized(function); if (!recognized) { // try to extract SUM // parameters for COUNT are ignored, as explained in super final String fnName = function.getName(); if (fnName.equalsIgnoreCase("SUM")) { recognized = isRecognized(function.getParameters()); if (recognized) { final ValueExpression expr = popFromExprStack(); createSum(expr, function.isDistinct()); } } else if (fnName.equalsIgnoreCase("COUNT")) { final List<ValueExpression> expressions = new ArrayList<ValueExpression>(); if (function.isDistinct()) { // putting something on stack only if isDistinct is set to // true recognized = isRecognized(function.getParameters()); // it might happen that we put on stack something we don't // use // this is the case only when some exprs are recognized and // the others not if (recognized) { // create a list of expressions int numParams = 0; final ExpressionList params = function.getParameters(); if (params != null) numParams = params.getExpressions().size(); for (int i = 0; i < numParams; i++) expressions.add(popFromExprStack()); } } else recognized = true; if (recognized) // finally, create CountAgg out of expressions (empty if // nonDistinct) createCount(expressions, function.isDistinct()); } } if (!recognized) // normal call to parent super.visit(function); }
/* * Has to be separate because ExpressionList does not extend Expression */ private boolean isRecognized(ExpressionList params) { if (params == null) return true; final List<Expression> exprs = params.getExpressions(); if (exprs == null || exprs.isEmpty()) return true; // if any of the children is not recognized, we have to go to super // if some of exprs are recognized and some not, we will have some extra // elements on stack for (final Expression expr : exprs) if (!isRecognized(expr)) return false; // all exprs recognized return true; }
public void visit(ExpressionList expressionList) throws Exception { for (Iterator iter = expressionList.getExpressions().iterator(); iter.hasNext(); ) { Expression expression = (Expression) iter.next(); expression.accept(this); } }