SumAvgAggregate.java 2.98 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package edu.caltech.nanodb.functions;


import java.util.HashSet;
import java.util.List;

import edu.caltech.nanodb.expressions.ArithmeticOperator;
import edu.caltech.nanodb.expressions.Expression;

import edu.caltech.nanodb.relations.ColumnType;
import edu.caltech.nanodb.relations.Schema;


/**
 * This aggregate function can be used to compute both SUM and AVERAGE
 * functions. It computes both the sum and average of a collection of values.
 */
public class SumAvgAggregate extends AggregateFunction {

    /**
     * This value is set to true if we want to compute the average value.
     * Otherwise, we compute the sum.
     */
    private boolean computeAverage;


    /** Contains the actual value of the sum */
    private Object sum;


    /** The current count of items that have been added */
    private int count;


    /** Indicates whether we want distinct values or not */
    private boolean distinct;


    /** Set to keep track of distinct values */
    HashSet<Object> set;


    public SumAvgAggregate(boolean computeAverage, boolean distinct) {
        super(/* supportsDistinct */ true);
        this.computeAverage = computeAverage;
        this.distinct = distinct;
        if (distinct)
            set = new HashSet<Object>();
    }


    @Override
    public void clearResult() {
        sum = null;
        count = 0;
        if (distinct)
            set.clear();
    }


    @Override
    public void addValue(Object value) {
        if (value == null)
            return;

        // If we are doing distinct, then only add the values if it has not
        // yet appeared
        if (distinct && set.contains(value))
            return;
        else if (distinct)
            set.add(value);

        if (sum == null) {
            // This is the first value.  Store it.
            sum = value;
        }
        else {
            // Add in the new value.
            sum = ArithmeticOperator.evalObjects(ArithmeticOperator.Type.ADD,
                sum, value);
        }

        if (computeAverage)
            count++;
    }


    @Override
    public Object getResult() {
        if (sum == null) {
            return null;
        }
        else if (computeAverage) {
94
            // TODO:  Need to generate NUMERIC result.  Using double right now.
95
96
            // Compute average from the sum and count.
            return ArithmeticOperator.evalObjects(
97
                ArithmeticOperator.Type.DIVIDE, sum, (double) count);
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        }
        else {
            // Just return the sum.
            return sum;
        }
    }


    @Override
    public ColumnType getReturnType(List<Expression> args, Schema schema) {
        if (args.size() != 1) {
            throw new IllegalArgumentException(
                "Sum/average aggregate function takes 1 argument; got " +
                args.size());
        }

        // When finding the min or max, the resulting aggregate column is the
        // same type as the values of the column.
        return args.get(0).getColumnInfo(schema).getType();
    }
}