| 223 | } |
| 224 | |
| 225 | OpBase *NewAggregateOp |
| 226 | ( |
| 227 | const ExecutionPlan *plan, |
| 228 | AR_ExpNode **exps |
| 229 | ) { |
| 230 | OpAggregate *op = rm_malloc(sizeof(OpAggregate)); |
| 231 | |
| 232 | op->groups = HashTableCreate(&_dt); |
| 233 | op->group_iter = NULL; |
| 234 | |
| 235 | OpBase_Init((OpBase *)op, OPType_AGGREGATE, "Aggregate", NULL, |
| 236 | AggregateConsume, AggregateReset, NULL, AggregateClone, |
| 237 | AggregateFree, false, plan); |
| 238 | |
| 239 | // expand hashtable to 2048 slots |
| 240 | int res = HashTableExpand(op->groups, 2048); |
| 241 | ASSERT(res == DICT_OK); |
| 242 | |
| 243 | // migrate each expression to the keys array or |
| 244 | // the aggregations array as appropriate |
| 245 | _migrate_expressions(op, exps); |
| 246 | array_free(exps); |
| 247 | |
| 248 | // the projected record will associate values with their resolved name |
| 249 | // to ensure that space is allocated for each entry |
| 250 | op->record_offsets = array_new(uint, op->aggregate_count + op->key_count); |
| 251 | for(uint i = 0; i < op->key_count; i++) { |
| 252 | // store the index of each key expression |
| 253 | int record_idx = OpBase_Modifies((OpBase *)op, |
| 254 | op->key_exps[i]->resolved_name); |
| 255 | array_append(op->record_offsets, record_idx); |
| 256 | } |
| 257 | for(uint i = 0; i < op->aggregate_count; i++) { |
| 258 | // store the index of each aggregating expression |
| 259 | int record_idx = OpBase_Modifies((OpBase *)op, |
| 260 | op->aggregate_exps[i]->resolved_name); |
| 261 | array_append(op->record_offsets, record_idx); |
| 262 | } |
| 263 | |
| 264 | return (OpBase *)op; |
| 265 | } |
| 266 | |
| 267 | static Record AggregateConsume |
| 268 | ( |
no test coverage detected