blob: ef07a198415287d3e5c23d0cc728e742ba12a076 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "dbcommon/function/agg-func.h"
#include <float.h>
#include <algorithm>
#include <cassert>
#include <string>
#include "dbcommon/common/tuple-batch.h"
#include "dbcommon/common/vector/decimal-vector.h"
#include "dbcommon/function/decimal-function.h"
#include "dbcommon/function/invoker.h"
#include "dbcommon/log/debug-logger.h"
#include "dbcommon/utils/macro.h"
namespace dbcommon {
/*
* 1. Handle agg(Scalar)
* 2. Handle optimization for statistics
* 3. Handle !hasGroupBy. When there is !hasGroupBy, the size of grpVals is 1
* and hasGroups[i] is 0
* 4. Handle small scale and large scale while getAccessor is always correct but
* getQuickAccessor is faster and correct only for small scale
* 5. Handle hasNull and !hasNull
* 6. Handle select list and no select list
* 7. It has been experimented that select with bit arithmetic performs better
* than hand written CMOV instruction.
* 8. The second stage SUM() is identical to the first stage.
* 9. The second stage AVG() differs from the first stage.
*/
AggStringGroupValues::~AggStringGroupValues() {
if (isSmallScale()) {
auto accessor = getAccessor<QuickAccessor>();
auto size = data_.size();
for (uint64_t i = 0; i < size; i++) {
auto tmp = (accessor.at(i)->accVal.value);
if (accessor.at(i)->accVal.isNotNull) cnfree(tmp);
}
return;
}
auto accessor = getAccessor<Accessor>();
auto size = data_.size();
for (uint64_t i = 0; i < size; i++) {
auto tmp = (accessor.at(i)->accVal.value);
if (accessor.at(i)->accVal.isNotNull) cnfree(tmp);
}
}
template <typename T, std::size_t = sizeof(T)>
struct Selector;
template <typename T>
struct Selector<T, sizeof(uint64_t)> {
typedef uint64_t type;
};
template <typename T>
struct Selector<T, sizeof(uint32_t)> {
typedef uint32_t type;
};
template <typename T>
struct Selector<T, sizeof(uint16_t)> {
typedef uint16_t type;
};
template <typename T>
struct Selector<T, sizeof(uint8_t)> {
typedef uint8_t type;
};
template <typename Accessor>
Datum count_star_impl(Datum *params, uint64_t size) {
assert(size == 4);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!hasGroupBy) {
assert(grpVals.size() == 1);
Datum &val = accessor.at(0)->accVal.value;
DatumPlus(val, sz);
return CreateDatum(0);
}
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; i++) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
DatumPlus(val, (uint64_t)1);
}
return CreateDatum(0);
}
Datum count_star(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? count_star_impl<AggPrimitiveGroupValues::QuickAccessor>(params,
size)
: count_star_impl<AggPrimitiveGroupValues::Accessor>(params, size);
}
template <typename Accessor>
Datum count_inc_impl(Datum *params, uint64_t size) {
assert(size == 5);
Object *para = DatumGetValue<Object *>(params[4]);
if (dynamic_cast<Scalar *>(para)) {
return count_star(params, 4);
}
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
Vector *vec = DatumGetValue<Vector *>(params[4]);
Accessor accessor = grpVals.getAccessor<Accessor>();
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
Datum &val = accessor.at(0)->accVal.value;
DatumPlus(val, stats->valueCount);
return CreateDatum(0);
}
uint64_t sz = vec->getNumOfRows();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
assert(vec->isValid() && "bug");
if (!hasGroupBy) {
assert(grpVals.size() == 1);
Datum &val = accessor.at(0)->accVal.value;
uint64_t inc = sz;
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
if (sel) {
#pragma clang loop unroll_count(4)
for (int64_t i = 0; i < sz; ++i) {
uint64_t isNull = nulls->getChar((*sel)[i]); // 0x1 or 0x0
inc -= isNull;
}
} else {
#pragma clang loop unroll_count(4)
for (int64_t i = 0; i < sz; ++i) {
uint64_t isNull = nulls->getChar(i); // 0x1 or 0x0
inc -= isNull;
}
}
}
DatumPlus(val, inc);
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
uint64_t index = (*sel)[i];
uint64_t isNotNull = nulls->getChar(index) ^ 0x1; // 0x1 or 0x0
DatumPlus(val, isNotNull);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
DatumPlus(val, (uint64_t)1);
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
uint64_t isNotNull = nulls->getChar(i) ^ 0x1; // 0x1 or 0x0
DatumPlus(val, isNotNull);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
DatumPlus(val, (uint64_t)1);
}
}
}
return CreateDatum(0);
}
Datum count_inc(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? count_inc_impl<AggPrimitiveGroupValues::QuickAccessor>(params,
size)
: count_inc_impl<AggPrimitiveGroupValues::Accessor>(params, size);
}
// todo: check the count_add with null
template <typename Accessor>
Datum count_add_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Vector *vec = DatumGetValue<Vector *>(params[4]);
SelectList *sel = vec->getSelected();
const int64_t *v = reinterpret_cast<const int64_t *>(vec->getValue());
assert(vec && "invalid input");
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!hasGroupBy) {
assert(grpVals.size() == 1);
Datum &val = accessor.at(0)->accVal.value;
if (sel) {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
DatumPlus(val, v[index]);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
DatumPlus(val, v[i]);
}
}
return CreateDatum(0);
}
if (sel) {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
uint64_t index = (*sel)[i];
DatumPlus(val, v[index]);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = accessor.at(hashGroups[i])->accVal.value;
DatumPlus(val, v[i]);
}
}
return CreateDatum(0);
}
Datum count_add(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? count_add_impl<AggPrimitiveGroupValues::QuickAccessor>(params,
size)
: count_add_impl<AggPrimitiveGroupValues::Accessor>(params, size);
}
template <typename T, typename R, typename Accessor>
Datum sum_type_sum_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
R value = DatumGetValue<R>(val);
value += DatumGetValue<T>(scalar->value) * sz;
val = CreateDatum(value);
return CreateDatum(0);
}
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
R value = DatumGetValue<R>(val);
value += DatumGetValue<T>(scalar->value);
val = CreateDatum(value);
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
Datum &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = stats->sum;
} else {
DatumPlus<R>(val, DatumGetValue<R>(stats->sum));
}
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
const T *v = reinterpret_cast<const T *>(vec->getValue());
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
Datum &val = aggVal->accVal.value;
char isNull = nulls->getChar(index);
char isNotNull = isNull ^ 0x1; // 0x1 or 0x0
aggVal->accVal.isNotNull |= isNotNull;
R acc = v[index];
typename Selector<R>::type accSrc =
*reinterpret_cast<typename Selector<R>::type *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<R *>(&accSrc);
DatumPlus<R>(val, acc);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
DatumPlus<R>(val, v[index]);
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = aggVal->accVal.value;
char isNull = nulls->getChar(i);
char isNotNull = isNull ^ 0x1; // 0x1 or 0x0
aggVal->accVal.isNotNull |= isNotNull;
R acc = v[i];
typename Selector<R>::type accSrc =
*reinterpret_cast<typename Selector<R>::type *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<R *>(&accSrc);
DatumPlus<R>(val, acc);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
DatumPlus<R>(val, v[i]);
}
}
}
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
char isNull = nulls->getChar(index);
char isNotNull = isNull ^ 0x1; // 0x1 or 0x0
aggVal->accVal.isNotNull |= isNotNull;
R acc = v[index];
typename Selector<R>::type accSrc =
*reinterpret_cast<typename Selector<R>::type *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<R *>(&accSrc);
DatumPlus<R>(val, acc);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
DatumPlus<R>(val, v[index]);
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
char isNull = nulls->getChar(i);
char isNotNull = isNull ^ 0x1; // 0x1 or 0x0
aggVal->accVal.isNotNull |= isNotNull;
R acc = v[i];
typename Selector<R>::type accSrc =
*reinterpret_cast<typename Selector<R>::type *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<R *>(&accSrc);
DatumPlus<R>(val, acc);
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
aggVal->accVal.isNotNull = true;
DatumPlus<R>(val, v[i]);
}
}
}
return CreateDatum(0);
}
template <typename T, typename R>
Datum sum_type_sum(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? sum_type_sum_impl<T, R, AggPrimitiveGroupValues::QuickAccessor>(
params, size)
: sum_type_sum_impl<T, R, AggPrimitiveGroupValues::Accessor>(
params, size);
}
template <typename Accessor>
Datum sum_decimal_sum_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggDecimalGroupValues &grpVals =
*DatumGetValue<AggDecimalGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
// Aggregate scalar
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
DecimalVar val = *DatumGetValue<DecimalVar *>(scalar->value);
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
val *= sz;
aggVal->accVal.value += val;
aggVal->accVal.isNotNull = true;
return CreateDatum(0);
}
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->accVal.value += val;
aggVal->accVal.isNotNull = true;
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats && !hasGroupBy) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
char *sum = DatumGetValue<char *>(stats->sum);
DecimalVar decVal = DecimalType::fromString(std::string(sum, strlen(sum)));
aggVal->accVal.value += decVal;
aggVal->accVal.isNotNull = true;
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
DecimalVector *dvec = dynamic_cast<DecimalVector *>(vec);
const int64_t *hval =
reinterpret_cast<const int64_t *>(dvec->getAuxiliaryValue());
const uint64_t *lval = reinterpret_cast<const uint64_t *>(dvec->getValue());
const int64_t *sval =
reinterpret_cast<const int64_t *>(dvec->getScaleValue());
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
auto nulls = vec->getNulls();
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
if (!nulls[plainIdx]) {
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
if (hasNull) {
auto nulls = vec->getNulls();
for (uint64_t plainIdx = 0; plainIdx < sz; ++plainIdx) {
if (!nulls[plainIdx]) {
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
for (uint64_t plainIdx = 0; plainIdx < sz; ++plainIdx) {
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
}
return CreateDatum(0);
}
// Aggregate with group by
if (sel) {
if (hasNull) {
auto nulls = vec->getNulls();
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
if (!nulls[plainIdx]) {
auto aggVal = accessor.at(hashGroups[actualIdx]);
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
auto aggVal = accessor.at(hashGroups[actualIdx]);
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
if (hasNull) {
auto nulls = vec->getNulls();
for (uint64_t plainIdx = 0; plainIdx < sz; ++plainIdx) {
if (!nulls[plainIdx]) {
auto aggVal = accessor.at(hashGroups[plainIdx]);
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
} else {
for (uint64_t plainIdx = 0; plainIdx < sz; ++plainIdx) {
auto aggVal = accessor.at(hashGroups[plainIdx]);
aggVal->accVal.value +=
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
aggVal->accVal.isNotNull = true;
}
}
}
return CreateDatum(0);
}
Datum sum_decimal_sum(Datum *params, uint64_t size) {
auto grpVals = DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? sum_decimal_sum_impl<AggDecimalGroupValues::QuickAccessor>(
params, size)
: sum_decimal_sum_impl<AggDecimalGroupValues::Accessor>(params,
size);
}
template <typename T, typename R, typename Accessor>
Datum avg_type_accu_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = reinterpret_cast<Scalar *>(para);
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
aggVal->avgVal.sum +=
static_cast<double>(DatumGetValue<T>(scalar->value)) * sz;
aggVal->avgVal.count += sz;
return CreateDatum(0);
}
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->avgVal.sum +=
static_cast<double>(DatumGetValue<T>(scalar->value));
aggVal->avgVal.count += 1;
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
aggVal->avgVal.sum += static_cast<double>(DatumGetValue<R>(stats->sum));
aggVal->avgVal.count += stats->valueCount;
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
Vector *valVec = vec;
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
const T *v = reinterpret_cast<const T *>(valVec->getValue());
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto val = &(aggVal->avgVal);
char isNotNull = nulls->getChar(index) ^ 0x1; // 0x1 or 0x0
double acc = v[index];
uint64_t accSrc = *reinterpret_cast<uint64_t *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<double *>(&accSrc);
val->sum += acc;
val->count += isNotNull;
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto val = &(aggVal->avgVal);
val->sum += v[index];
++val->count;
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto val = &(aggVal->avgVal);
char isNotNull = nulls->getChar(i) ^ 0x1; // 0x1 or 0x0
double acc = v[i];
uint64_t accSrc = *reinterpret_cast<uint64_t *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<double *>(&accSrc);
val->sum += acc;
val->count += isNotNull;
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto val = &(aggVal->avgVal);
val->sum += v[i];
++val->count;
}
}
}
return CreateDatum(0);
}
const T *v = reinterpret_cast<const T *>(valVec->getValue());
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
char isNotNull = nulls->getChar(index) ^ 0x1; // 0x1 or 0x0
double acc = v[index];
uint64_t accSrc = *reinterpret_cast<uint64_t *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<double *>(&accSrc);
val->sum += acc;
val->count += isNotNull;
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += v[index];
++val->count;
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
char isNotNull = nulls->getChar(i) ^ 0x1; // 0x1 or 0x0
double acc = v[i];
uint64_t accSrc = *reinterpret_cast<uint64_t *>(&acc);
accSrc &= (~(uint64_t)isNotNull + 1);
acc = *reinterpret_cast<double *>(&accSrc);
val->sum += acc;
val->count += isNotNull;
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += v[i];
++val->count;
}
}
}
return CreateDatum(0);
}
template <typename T, typename R>
Datum avg_type_accu(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? avg_type_accu_impl<T, R, AggPrimitiveGroupValues::QuickAccessor>(
params, size)
: avg_type_accu_impl<T, R, AggPrimitiveGroupValues::Accessor>(
params, size);
}
template <typename Accessor>
Datum avg_type_amalg_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = reinterpret_cast<Vector *>(para);
assert(dynamic_cast<Vector *>(para)->getTypeKind() ==
TypeKind::AVG_DOUBLE_TRANS_DATA_ID);
Accessor accessor = grpVals.getAccessor<Accessor>();
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
Vector *valVec = vec->getChildVector(0);
Vector *countVec = vec->getChildVector(1);
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
const double *v = reinterpret_cast<const double *>(valVec->getValue());
const int64_t *countv =
reinterpret_cast<const int64_t *>(countVec->getValue());
if (sel) {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!nulls->get(index)) {
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += v[index];
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += v[index];
}
}
} else {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!nulls->get(i)) {
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += v[i];
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += v[i];
}
}
}
return CreateDatum(0);
}
const double *v = reinterpret_cast<const double *>(valVec->getValue());
const int64_t *countv =
reinterpret_cast<const int64_t *>(countVec->getValue());
if (sel) {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!nulls->get(index)) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += v[index];
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += v[index];
}
}
} else {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!nulls->get(i)) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += v[i];
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += v[i];
}
}
}
return CreateDatum(0);
}
Datum avg_type_amalg(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? avg_type_amalg_impl<AggPrimitiveGroupValues::QuickAccessor>(
params, size)
: avg_type_amalg_impl<AggPrimitiveGroupValues::Accessor>(params,
size);
}
template <typename Accessor>
Datum avg_decimal_accu_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggDecimalGroupValues &grpVals =
*DatumGetValue<AggDecimalGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = reinterpret_cast<Scalar *>(para);
DecimalVar val = *DatumGetValue<DecimalVar *>(scalar->value);
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
val *= sz;
aggVal->avgVal.sum += val;
aggVal->avgVal.count += sz;
return CreateDatum(0);
}
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->avgVal.sum += val;
aggVal->avgVal.count += 1;
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto sum = DatumGetValue<const char *>(stats->sum);
auto sumDecVal = DecimalType::fromString(std::string(sum, strlen(sum)));
auto aggVal = accessor.at(0);
aggVal->avgVal.sum += sumDecVal;
aggVal->avgVal.count += stats->valueCount;
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
Vector *valVec = vec;
DecimalVector *dvec = reinterpret_cast<DecimalVector *>(valVec);
const int64_t *hval =
reinterpret_cast<const int64_t *>(dvec->getAuxiliaryValue());
const uint64_t *lval = reinterpret_cast<const uint64_t *>(dvec->getValue());
const int64_t *sval =
reinterpret_cast<const int64_t *>(dvec->getScaleValue());
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
char isNotNull = nulls->getChar(index) ^ 0x1; // 0x1 or 0x0
if (isNotNull) {
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
val->count += 1;
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
val->count += 1;
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
char isNotNull = nulls->getChar(i) ^ 0x1; // 0x1 or 0x0
if (isNotNull) {
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
val->count += 1;
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
val->count += 1;
}
}
}
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
char isNotNull = nulls->getChar(index) ^ 0x1; // 0x1 or 0x0
if (isNotNull) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
val->count += 1;
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
val->count += 1;
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
char isNotNull = nulls->getChar(i) ^ 0x1; // 0x1 or 0x0
if (isNotNull) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
val->count += 1;
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
val->count += 1;
}
}
}
return CreateDatum(0);
}
Datum avg_decimal_accu(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? avg_decimal_accu_impl<AggDecimalGroupValues::QuickAccessor>(
params, size)
: avg_decimal_accu_impl<AggDecimalGroupValues::Accessor>(params,
size);
}
template <typename Accessor>
Datum avg_decimal_amalg_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggDecimalGroupValues &grpVals =
*DatumGetValue<AggDecimalGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = reinterpret_cast<Vector *>(para);
assert(dynamic_cast<Vector *>(para)->getTypeKind() ==
TypeKind::AVG_DECIMAL_TRANS_DATA_ID);
Accessor accessor = grpVals.getAccessor<Accessor>();
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
Vector *valVec = vec->getChildVector(0);
Vector *countVec = vec->getChildVector(1);
DecimalVector *dvec = dynamic_cast<DecimalVector *>(valVec);
const int64_t *hval =
reinterpret_cast<const int64_t *>(dvec->getAuxiliaryValue());
const uint64_t *lval = reinterpret_cast<const uint64_t *>(dvec->getValue());
const int64_t *sval =
reinterpret_cast<const int64_t *>(dvec->getScaleValue());
if (!hasGroupBy) {
auto aggVal = accessor.at(0);
const int64_t *countv =
reinterpret_cast<const int64_t *>(countVec->getValue());
if (sel) {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!nulls->get(index)) {
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
}
}
} else {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!nulls->get(i)) {
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
}
}
}
return CreateDatum(0);
}
const int64_t *countv =
reinterpret_cast<const int64_t *>(countVec->getValue());
if (sel) {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!nulls->get(index)) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[index];
val->sum += DecimalVar(hval[index], lval[index], sval[index]);
}
}
} else {
if (valVec->hasNullValue()) {
dbcommon::BoolBuffer *nulls = valVec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!nulls->get(i)) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
auto val = &(aggVal->avgVal);
val->count += countv[i];
val->sum += DecimalVar(hval[i], lval[i], sval[i]);
}
}
}
return CreateDatum(0);
}
Datum avg_decimal_amalg(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? avg_decimal_amalg_impl<AggDecimalGroupValues::QuickAccessor>(
params, size)
: avg_decimal_amalg_impl<AggDecimalGroupValues::Accessor>(params,
size);
}
Datum avg_decimal_avg(Datum *params, uint64_t size) {
assert(size == 1);
AvgDecimalTransData *val = DatumGetValue<AvgDecimalTransData *>(params[0]);
if (val->count != 0) {
val->sum /= DecimalVar(val->count);
}
return CreateDatum(&val->sum);
}
Datum sum_int8_sum(Datum *params, uint64_t size) {
return sum_type_sum<int64_t, int64_t>(params, size);
}
Datum sum_int16_sum(Datum *params, uint64_t size) {
return sum_type_sum<int64_t, int64_t>(params, size);
}
Datum sum_int32_sum(Datum *params, uint64_t size) {
return sum_type_sum<int64_t, int64_t>(params, size);
}
Datum sum_int64_sum(Datum *params, uint64_t size) {
return sum_type_sum<int64_t, int64_t>(params, size);
}
Datum sum_float_sum(Datum *params, uint64_t size) {
return sum_type_sum<double, double>(params, size);
}
Datum sum_double_sum(Datum *params, uint64_t size) {
return sum_type_sum<double, double>(params, size);
}
Datum sum_int8_add(Datum *params, uint64_t size) {
return sum_type_sum<int8_t, int64_t>(params, size);
}
Datum sum_int16_add(Datum *params, uint64_t size) {
return sum_type_sum<int16_t, int64_t>(params, size);
}
Datum sum_int32_add(Datum *params, uint64_t size) {
return sum_type_sum<int32_t, int64_t>(params, size);
}
Datum sum_int64_add(Datum *params, uint64_t size) {
return sum_type_sum<int64_t, int64_t>(params, size);
}
Datum sum_float_add(Datum *params, uint64_t size) {
return sum_type_sum<float, double>(params, size);
}
Datum sum_double_add(Datum *params, uint64_t size) {
return sum_type_sum<double, double>(params, size);
}
Datum sum_decimal_add(Datum *params, uint64_t size) {
return sum_decimal_sum(params, size);
}
Datum avg_int8_accu(Datum *params, uint64_t size) {
return avg_type_accu<int8_t, int64_t>(params, size);
}
Datum avg_int16_accu(Datum *params, uint64_t size) {
return avg_type_accu<int16_t, int64_t>(params, size);
}
Datum avg_int32_accu(Datum *params, uint64_t size) {
return avg_type_accu<int32_t, int64_t>(params, size);
}
Datum avg_int64_accu(Datum *params, uint64_t size) {
return avg_type_accu<int64_t, int64_t>(params, size);
}
Datum avg_float_accu(Datum *params, uint64_t size) {
return avg_type_accu<float, double>(params, size);
}
Datum avg_double_accu(Datum *params, uint64_t size) {
return avg_type_accu<double, double>(params, size);
}
Datum avg_int8_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_int16_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_int32_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_int64_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_float_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_double_amalg(Datum *params, uint64_t size) {
return avg_type_amalg(params, size);
}
Datum avg_double_avg(Datum *params, uint64_t size) {
assert(size == 1);
auto val = DatumGetValue<AvgPrimitiveTransData *>(params[0]);
double value = val->sum / val->count;
return CreateDatum<double>(value);
}
template <typename T, typename C, typename Accessor>
Datum min_max_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggPrimitiveGroupValues &grpVals =
*DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
TupleBatch *batch = DatumGetValue<TupleBatch *>(params[1]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = scalar->value;
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
Datum &val = aggVal->accVal.value;
Datum statsVal = CreateDatum<T>(C()(DatumGetValue<T>(stats->minimum),
DatumGetValue<T>(stats->maximum)));
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = statsVal;
} else {
val = CreateDatum<T>(
C()(DatumGetValue<T>(statsVal), DatumGetValue<T>(val)));
}
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
bool hasGroupBy = DatumGetValue<bool>(params[3]);
const T *v = reinterpret_cast<const T *>(vec->getValue());
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
Datum &val = aggVal->accVal.value;
if (!nulls->get(index)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[index]);
} else {
val = CreateDatum<T>(C()(v[index], DatumGetValue<T>(val)));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
Datum &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[index]);
} else {
val = CreateDatum<T>(C()(v[index], DatumGetValue<T>(val)));
}
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = aggVal->accVal.value;
if (!nulls->get(i)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[i]);
} else {
val = CreateDatum<T>(C()(v[i], DatumGetValue<T>(val)));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
Datum &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[i]);
} else {
val = CreateDatum<T>(C()(v[i], DatumGetValue<T>(val)));
}
}
}
}
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
if (!nulls->get(index)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[index]);
} else {
val = CreateDatum<T>(C()(v[index], DatumGetValue<T>(val)));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[index]);
} else {
val = CreateDatum<T>(C()(v[index], DatumGetValue<T>(val)));
}
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
if (!nulls->get(i)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[i]);
} else {
val = CreateDatum<T>(C()(v[i], DatumGetValue<T>(val)));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
Datum &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = CreateDatum<T>(v[i]);
} else {
val = CreateDatum<T>(C()(v[i], DatumGetValue<T>(val)));
}
}
}
}
return CreateDatum(0);
}
template <typename T, typename C>
Datum min_max_internal(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? min_max_impl<T, C, AggPrimitiveGroupValues::QuickAccessor>(
params, size)
: min_max_impl<T, C, AggPrimitiveGroupValues::Accessor>(params,
size);
}
template <typename C, typename Accessor>
Datum min_max_string_impl(Datum *params, uint64_t size) {
assert(size == 5);
auto &grpVals = *DatumGetValue<AggStringGroupValues *>(params[0]);
TupleBatch *batch = DatumGetValue<TupleBatch *>(params[1]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
if (!aggVal->accVal.isNotNull) {
auto str = DatumGetValue<char *>(scalar->value);
aggVal->accVal.value = grpVals.newStrTransData(str, strlen(str));
}
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
char *minStr = DatumGetValue<char *>(stats->minimum);
char *maxStr = DatumGetValue<char *>(stats->maximum);
char *statsStr = maxStr;
if (C::strCmp(minStr, strlen(minStr), maxStr, strlen(maxStr))) {
statsStr = minStr;
}
if (aggVal->accVal.isNotNull) {
auto valStr = aggVal->accVal.value;
if (C::strCmp(statsStr, strlen(statsStr), valStr->str, valStr->length)) {
cnfree(valStr);
aggVal->accVal.value =
grpVals.newStrTransData(statsStr, strlen(statsStr));
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(statsStr, strlen(statsStr));
}
return CreateDatum(0);
}
SelectList *sel = vec->getSelected();
const bool *__restrict__ nulls = vec->getNulls();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
bool hasGroupBy = DatumGetValue<bool>(params[3]);
const char **v = vec->getValPtrs();
const uint64_t *lens = vec->getLengths();
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (nulls) {
#pragma clang loop unroll_count(4)
for (auto plainIdx : *sel) {
if (!nulls[plainIdx]) {
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (auto plainIdx : *sel) {
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
if (nulls) {
#pragma clang loop unroll_count(4)
for (auto plainIdx = 0; plainIdx < sz; plainIdx++) {
if (!nulls[plainIdx]) {
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (auto plainIdx = 0; plainIdx < sz; plainIdx++) {
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
}
return CreateDatum(0);
}
if (sel) {
if (nulls) {
#pragma clang loop unroll_count(4)
for (auto actualIdx = 0; actualIdx < sz; actualIdx++) {
auto plainIdx = (*sel)[actualIdx];
if (!nulls[plainIdx]) {
auto aggVal = accessor.at(hashGroups[actualIdx]);
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (auto actualIdx = 0; actualIdx < sz; actualIdx++) {
auto plainIdx = (*sel)[actualIdx];
auto aggVal = accessor.at(hashGroups[actualIdx]);
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
if (nulls) {
#pragma clang loop unroll_count(4)
for (auto plainIdx = 0; plainIdx < sz; plainIdx++) {
if (!nulls[plainIdx]) {
auto actualIdx = plainIdx;
auto aggVal = accessor.at(hashGroups[actualIdx]);
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (auto plainIdx = 0; plainIdx < sz; plainIdx++) {
auto actualIdx = plainIdx;
auto aggVal = accessor.at(hashGroups[actualIdx]);
if (aggVal->accVal.isNotNull) {
auto oldStr = aggVal->accVal.value;
if (C::strCmp(v[plainIdx], lens[plainIdx], oldStr->str,
oldStr->length)) {
cnfree(oldStr);
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
} else {
aggVal->accVal.value =
grpVals.newStrTransData(v[plainIdx], lens[plainIdx]);
}
}
}
}
return CreateDatum(0);
}
template <typename C>
Datum min_max_string(Datum *params, uint64_t size) {
using AggGroupValues = AggStringGroupValues;
AggGroupValues *grpVals = DatumGetValue<AggGroupValues *>(params[0]);
return grpVals->isSmallScale()
? min_max_string_impl<C, AggGroupValues::QuickAccessor>(params,
size)
: min_max_string_impl<C, AggGroupValues::Accessor>(params, size);
}
template <typename C, typename Accessor>
Datum min_max_timestamp_impl(Datum *params, uint64_t size) {
assert(size == 5);
auto &grpVals = *DatumGetValue<AggTimestampGroupValues *>(params[0]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->accVal.value = *DatumGetValue<Timestamp *>(scalar->value);
aggVal->accVal.isNotNull = true;
}
return CreateDatum(0);
}
// optimize based on vector statistics, but now it is disabled for statistics
// for timestamp is only millisecond
const VectorStatistics *stats = vec->getVectorStatistics();
if (false && stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto aggVal = accessor.at(0);
auto &val = aggVal->accVal.value;
Timestamp *minTs = DatumGetValue<Timestamp *>(stats->minimum);
Timestamp *maxTs = DatumGetValue<Timestamp *>(stats->minimum);
Timestamp *statsTs = maxTs;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = C()(*minTs, *maxTs);
} else {
val = C()(val, C()(*minTs, *maxTs));
}
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
bool hasGroupBy = DatumGetValue<bool>(params[3]);
const int64_t *v = reinterpret_cast<const int64_t *>(vec->getValue());
const int64_t *nano =
reinterpret_cast<const int64_t *>(vec->getNanoseconds());
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!nulls->get(index)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[index], nano[index]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[index], nano[index]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[index], nano[index]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[index], nano[index]));
}
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!nulls->get(i)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[i], nano[i]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[i], nano[i]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[i], nano[i]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[i], nano[i]));
}
}
}
}
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
if (!nulls->get(index)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[index], nano[index]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[index], nano[index]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
uint64_t index = (*sel)[i];
auto aggVal = accessor.at(hashGroups[i]);
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[index], nano[index]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[index], nano[index]));
}
}
}
} else {
if (hasNull) {
dbcommon::BoolBuffer *nulls = vec->getNullBuffer();
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
if (!nulls->get(i)) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[i], nano[i]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[i], nano[i]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = Timestamp(v[i], nano[i]);
} else {
auto val = aggVal->accVal.value;
aggVal->accVal.value = C()(val, Timestamp(v[i], nano[i]));
}
}
}
}
return CreateDatum(0);
}
template <typename C>
Datum min_max_timestamp(Datum *params, uint64_t size) {
using AggGroupValues = AggTimestampGroupValues;
auto grpVals = DatumGetValue<AggGroupValues *>(params[0]);
return grpVals->isSmallScale()
? min_max_timestamp_impl<C, AggGroupValues::QuickAccessor>(params,
size)
: min_max_timestamp_impl<C, AggGroupValues::Accessor>(params,
size);
}
template <typename C, typename Accessor>
Datum min_max_decimal_impl(Datum *params, uint64_t size) {
assert(size == 5);
AggDecimalGroupValues &grpVals =
*DatumGetValue<AggDecimalGroupValues *>(params[0]);
TupleBatch *batch = DatumGetValue<TupleBatch *>(params[1]);
uint64_t sz = DatumGetValue<const std::vector<uint64_t> *>(params[2])->size();
const uint64_t *__restrict__ hashGroups =
DatumGetValue<const std::vector<uint64_t> *>(params[2])->data();
bool hasGroupBy = DatumGetValue<bool>(params[3]);
Object *para = DatumGetValue<Object *>(params[4]);
Vector *vec = dynamic_cast<Vector *>(para);
Accessor accessor = grpVals.getAccessor<Accessor>();
if (!vec) {
Scalar *scalar = dynamic_cast<Scalar *>(para);
DecimalVar val = *DatumGetValue<DecimalVar *>(scalar->value);
#pragma clang loop unroll_count(4)
for (uint64_t i = 0; i < sz; ++i) {
auto aggVal = accessor.at(hashGroups[i]);
aggVal->accVal.isNotNull = true;
aggVal->accVal.value = val;
}
return CreateDatum(0);
}
// optimize based on vector statistics
const VectorStatistics *stats = vec->getVectorStatistics();
if (stats) {
if (!stats->hasMinMaxStats) return CreateDatum(0);
auto min = DatumGetValue<const char *>(stats->minimum);
auto max = DatumGetValue<const char *>(stats->maximum);
DecimalVar minDecVal =
DecimalType::fromString(std::string(min, strlen(min)));
DecimalVar maxDecVal =
DecimalType::fromString(std::string(max, strlen(max)));
auto statsVal = (C()(minDecVal, maxDecVal));
auto aggVal = accessor.at(0);
auto &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.value = statsVal;
aggVal->accVal.isNotNull = true;
} else {
aggVal->accVal.value = C()(aggVal->accVal.value, statsVal);
}
return CreateDatum(0);
}
bool hasNull = vec->hasNullValue();
SelectList *sel = vec->getSelected();
assert(sz == DatumGetValue<const std::vector<uint64_t> *>(params[2])->size());
DecimalVector *dvec = dynamic_cast<DecimalVector *>(vec);
const int64_t *hval =
reinterpret_cast<const int64_t *>(dvec->getAuxiliaryValue());
const uint64_t *lval = reinterpret_cast<const uint64_t *>(dvec->getValue());
const int64_t *sval =
reinterpret_cast<const int64_t *>(dvec->getScaleValue());
if (!hasGroupBy) {
assert(grpVals.size() == 1);
auto aggVal = accessor.at(0);
if (sel) {
if (hasNull) {
auto nulls = vec->getNulls();
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
auto &val = aggVal->accVal.value;
if (!nulls[plainIdx]) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
auto &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
} else {
if (hasNull) {
auto nulls = vec->getNulls();
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = actualIdx;
auto &val = aggVal->accVal.value;
if (!nulls[plainIdx]) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = actualIdx;
auto &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
}
return CreateDatum(0);
}
if (sel) {
if (hasNull) {
auto nulls = vec->getNulls();
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
auto aggVal = accessor.at(hashGroups[actualIdx]);
auto &val = aggVal->accVal.value;
if (!nulls[plainIdx]) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = (*sel)[actualIdx];
auto aggVal = accessor.at(hashGroups[actualIdx]);
auto &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val,
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]));
}
}
}
} else {
if (hasNull) {
auto nulls = vec->getNulls();
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = actualIdx;
auto aggVal = accessor.at(hashGroups[actualIdx]);
auto &val = aggVal->accVal.value;
if (!nulls[plainIdx]) {
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val, DecimalVar(hval[plainIdx], lval[plainIdx],
sval[plainIdx]));
}
}
}
} else {
#pragma clang loop unroll_count(4)
for (uint64_t actualIdx = 0; actualIdx < sz; ++actualIdx) {
uint64_t plainIdx = actualIdx;
auto aggVal = accessor.at(hashGroups[actualIdx]);
auto &val = aggVal->accVal.value;
if (!aggVal->accVal.isNotNull) {
aggVal->accVal.isNotNull = true;
val = DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]);
} else {
val = C()(val,
DecimalVar(hval[plainIdx], lval[plainIdx], sval[plainIdx]));
}
}
}
}
return CreateDatum(0);
}
template <typename C>
Datum min_max_decimal(Datum *params, uint64_t size) {
AggPrimitiveGroupValues *grpVals =
DatumGetValue<AggPrimitiveGroupValues *>(params[0]);
return grpVals->isSmallScale()
? min_max_decimal_impl<C, AggDecimalGroupValues::QuickAccessor>(
params, size)
: min_max_decimal_impl<C, AggDecimalGroupValues::Accessor>(params,
size);
}
template <typename T>
class MinCmp {
public:
T operator()(T x, T y) { return std::min<T>(x, y); }
static bool strCmp(const char *__restrict__ xSrc, uint64_t lenx,
const char *__restrict__ ySrc, uint64_t leny) {
const unsigned char *__restrict__ x =
reinterpret_cast<const unsigned char *>(xSrc);
const unsigned char *__restrict__ y =
reinterpret_cast<const unsigned char *>(ySrc);
uint64_t len = lenx < leny ? lenx : leny;
if (lenx < leny) {
auto xEnd = x + lenx;
while (x < xEnd && (*x == *y)) {
x++;
y++;
}
if (x == xEnd || *x < *y) return true;
} else {
auto yEnd = y + leny;
while (y < yEnd && (*x == *y)) {
x++;
y++;
}
if (y != yEnd && *x < *y) return true;
}
return false;
}
};
template <typename T>
class MaxCmp {
public:
T operator()(T x, T y) { return std::max<T>(x, y); }
static bool strCmp(const char *__restrict__ xSrc, uint64_t lenx,
const char *__restrict__ ySrc, uint64_t leny) {
const unsigned char *__restrict__ x =
reinterpret_cast<const unsigned char *>(xSrc);
const unsigned char *__restrict__ y =
reinterpret_cast<const unsigned char *>(ySrc);
uint64_t len = lenx < leny ? lenx : leny;
if (lenx > leny) {
auto yEnd = y + leny;
while (y < yEnd && (*x == *y)) {
x++;
y++;
}
if (y == yEnd || *x > *y) return true;
} else {
auto xEnd = x + lenx;
while (x < xEnd && (*x == *y)) {
x++;
y++;
}
if (x != xEnd && *x > *y) return true;
}
return false;
}
};
Datum min_int8_smaller(Datum *params, uint64_t size) {
return min_max_internal<int8_t, MinCmp<int8_t>>(params, size);
}
Datum min_int16_smaller(Datum *params, uint64_t size) {
return min_max_internal<int16_t, MinCmp<int16_t>>(params, size);
}
Datum min_int32_smaller(Datum *params, uint64_t size) {
return min_max_internal<int32_t, MinCmp<int32_t>>(params, size);
}
Datum min_int64_smaller(Datum *params, uint64_t size) {
return min_max_internal<int64_t, MinCmp<int64_t>>(params, size);
}
Datum min_float_smaller(Datum *params, uint64_t size) {
return min_max_internal<float, MinCmp<float>>(params, size);
}
Datum min_double_smaller(Datum *params, uint64_t size) {
return min_max_internal<double, MinCmp<double>>(params, size);
}
Datum min_string_smaller(Datum *params, uint64_t size) {
return min_max_string<MinCmp<std::string>>(params, size);
}
Datum min_date_smaller(Datum *params, uint64_t size) {
return min_max_internal<int32_t, MinCmp<int32_t>>(params, size);
}
Datum min_time_smaller(Datum *params, uint64_t size) {
return min_max_internal<int64_t, MinCmp<int64_t>>(params, size);
}
Datum min_timestamp_smaller(Datum *params, uint64_t size) {
return min_max_timestamp<MinCmp<Timestamp>>(params, size);
}
Datum min_decimal_smaller(Datum *params, uint64_t size) {
return min_max_decimal<MinCmp<DecimalVar>>(params, size);
}
Datum max_int8_larger(Datum *params, uint64_t size) {
return min_max_internal<int8_t, MaxCmp<int8_t>>(params, size);
}
Datum max_int16_larger(Datum *params, uint64_t size) {
return min_max_internal<int16_t, MaxCmp<int16_t>>(params, size);
}
Datum max_int32_larger(Datum *params, uint64_t size) {
return min_max_internal<int32_t, MaxCmp<int32_t>>(params, size);
}
Datum max_int64_larger(Datum *params, uint64_t size) {
return min_max_internal<int64_t, MaxCmp<int64_t>>(params, size);
}
Datum max_float_larger(Datum *params, uint64_t size) {
return min_max_internal<float, MaxCmp<float>>(params, size);
}
Datum max_double_larger(Datum *params, uint64_t size) {
return min_max_internal<double, MaxCmp<double>>(params, size);
}
Datum max_string_larger(Datum *params, uint64_t size) {
return min_max_string<MaxCmp<std::string>>(params, size);
}
Datum max_date_larger(Datum *params, uint64_t size) {
return min_max_internal<int32_t, MaxCmp<int32_t>>(params, size);
}
Datum max_time_larger(Datum *params, uint64_t size) {
return min_max_internal<int64_t, MaxCmp<int64_t>>(params, size);
}
Datum max_timestamp_larger(Datum *params, uint64_t size) {
return min_max_timestamp<MaxCmp<Timestamp>>(params, size);
}
Datum max_decimal_larger(Datum *params, uint64_t size) {
return min_max_decimal<MaxCmp<DecimalVar>>(params, size);
}
} // namespace dbcommon