@Override public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { SumAggregateFunction sumFunc; CountAggregateFunction countFunc = (CountAggregateFunction)context.getExpressionManager().addIfAbsent(new CountAggregateFunction(children)); if (!countFunc.isConstantExpression()) { sumFunc = (SumAggregateFunction)context.getExpressionManager().addIfAbsent(new SumAggregateFunction(countFunc.getChildren(),null)); } else { sumFunc = null; } return new AvgAggregateFunction(children, countFunc, sumFunc); } }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (!countFunc.evaluate(tuple, ptr)) { return false; } long count = countFunc.getDataType().getCodec().decodeLong(ptr, SortOrder.getDefault()); if (count == 0) { return false; } // Normal case where a column reference was used as the argument to AVG if (!countFunc.isConstantExpression()) { sumFunc.evaluate(tuple, ptr); BigDecimal sum = (BigDecimal) PDecimal.INSTANCE.toObject(ptr, sumFunc.getDataType()); // For the final column projection, we divide the sum by the count, both coerced to BigDecimal. // TODO: base the precision on column metadata instead of constant BigDecimal avg = sum.divide(BigDecimal.valueOf(count), PDataType.DEFAULT_MATH_CONTEXT); avg = avg.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(avg)); return true; } BigDecimal value = (BigDecimal) ((LiteralExpression)countFunc.getChildren().get(0)).getValue(); value = value.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(value)); return true; }
@Override public Aggregator newServerAggregator(Configuration config, ImmutableBytesWritable ptr) { LongSumAggregator sumAgg = newClientAggregator(); sumAgg.aggregate(null, ptr); return new CountAggregator(sumAgg); } }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CountAggregateFunction other = (CountAggregateFunction)obj; return (isConstantExpression() && other.isConstantExpression()) || children.equals(other.getChildren()); }
protected CountAggregateFunction getDelegateFunction(List<Expression> children, StatementContext context) { CountAggregateFunction countFunc = null; if (getChildren().get(0).isStateless()) { countFunc = (CountAggregateFunction)context.getExpressionManager().addIfAbsent(new CountAggregateFunction(children)); } return countFunc; }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (delegate == null) { return super.evaluate(tuple, ptr); } delegate.evaluate(tuple, ptr); if (PLong.INSTANCE.compareTo(ptr,ZERO) == 0) { return false; } return true; }
@Override public int hashCode() { return isConstantExpression() ? 0 : super.hashCode(); }
@Test public void testAggFuncInHaving() throws SQLException { String query = "select count(1) from atable group by a_string having count(a_string) >= 1"; List<Object> binds = Collections.emptyList(); Expressions expressions = compileStatement(query,binds); Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(Arrays.asList(A_STRING)),1L); assertNull(expressions.whereClause); assertEquals(h, expressions.havingClause); }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CountAggregateFunction other = (CountAggregateFunction)obj; return (isConstantExpression() && other.isConstantExpression()) || children.equals(other.getChildren()); }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (delegate == null) { return super.evaluate(tuple, ptr); } delegate.evaluate(tuple, ptr); if (PLong.INSTANCE.compareTo(ptr,ZERO) == 0) { return false; } return true; }
@Override public int hashCode() { return isConstantExpression() ? 0 : super.hashCode(); }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (!countFunc.evaluate(tuple, ptr)) { return false; } long count = countFunc.getDataType().getCodec().decodeLong(ptr, SortOrder.getDefault()); if (count == 0) { return false; } // Normal case where a column reference was used as the argument to AVG if (!countFunc.isConstantExpression()) { sumFunc.evaluate(tuple, ptr); BigDecimal sum = (BigDecimal) PDecimal.INSTANCE.toObject(ptr, sumFunc.getDataType()); // For the final column projection, we divide the sum by the count, both coerced to BigDecimal. // TODO: base the precision on column metadata instead of constant BigDecimal avg = sum.divide(BigDecimal.valueOf(count), PDataType.DEFAULT_MATH_CONTEXT); avg = avg.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(avg)); return true; } BigDecimal value = (BigDecimal) ((LiteralExpression)countFunc.getChildren().get(0)).getValue(); value = value.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(value)); return true; }
@Override public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { SumAggregateFunction sumFunc; CountAggregateFunction countFunc = (CountAggregateFunction)context.getExpressionManager().addIfAbsent(new CountAggregateFunction(children)); if (!countFunc.isConstantExpression()) { sumFunc = (SumAggregateFunction)context.getExpressionManager().addIfAbsent(new SumAggregateFunction(countFunc.getChildren(),null)); } else { sumFunc = null; } return new AvgAggregateFunction(children, countFunc, sumFunc); } }
@Test public void testAndHavingToWhere() throws SQLException { String query = "select count(1) from atable group by a_string having count(1) >= 1 and a_string = 'foo'"; List<Object> binds = Collections.emptyList(); Expressions expressions = compileStatement(query,binds); Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L); Expression w = constantComparison(CompareOp.EQUAL, A_STRING,"foo"); assertEquals(w, expressions.whereClause); assertEquals(h, expressions.havingClause); }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CountAggregateFunction other = (CountAggregateFunction)obj; return (isConstantExpression() && other.isConstantExpression()) || children.equals(other.getChildren()); }
@Override public Aggregator newServerAggregator(Configuration config, ImmutableBytesWritable ptr) { LongSumAggregator sumAgg = newClientAggregator(); sumAgg.aggregate(null, ptr); return new CountAggregator(sumAgg); } }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (delegate == null) { return super.evaluate(tuple, ptr); } delegate.evaluate(tuple, ptr); if (PLong.INSTANCE.compareTo(ptr,ZERO) == 0) { return false; } return true; }
@Override public int hashCode() { return isConstantExpression() ? 0 : super.hashCode(); }
@Override public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { if (!countFunc.evaluate(tuple, ptr)) { return false; } long count = countFunc.getDataType().getCodec().decodeLong(ptr, SortOrder.getDefault()); if (count == 0) { return false; } // Normal case where a column reference was used as the argument to AVG if (!countFunc.isConstantExpression()) { sumFunc.evaluate(tuple, ptr); BigDecimal sum = (BigDecimal) PDecimal.INSTANCE.toObject(ptr, sumFunc.getDataType()); // For the final column projection, we divide the sum by the count, both coerced to BigDecimal. // TODO: base the precision on column metadata instead of constant BigDecimal avg = sum.divide(BigDecimal.valueOf(count), PDataType.DEFAULT_MATH_CONTEXT); avg = avg.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(avg)); return true; } BigDecimal value = (BigDecimal) ((LiteralExpression)countFunc.getChildren().get(0)).getValue(); value = value.setScale(scale, BigDecimal.ROUND_DOWN); ptr.set(PDecimal.INSTANCE.toBytes(value)); return true; }
@Override public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { SumAggregateFunction sumFunc; CountAggregateFunction countFunc = (CountAggregateFunction)context.getExpressionManager().addIfAbsent(new CountAggregateFunction(children)); if (!countFunc.isConstantExpression()) { sumFunc = (SumAggregateFunction)context.getExpressionManager().addIfAbsent(new SumAggregateFunction(countFunc.getChildren(),null)); } else { sumFunc = null; } return new AvgAggregateFunction(children, countFunc, sumFunc); } }