Fixes #2771
Main changes in this CL
* RoaringBitmap is renamed to BitmapValue and moved into bitmap_value.h
* leveraging Roaring64Map to support unsigned BIGINT for BITMAP type
* introduces two new format (SINGLE64 and BITMAP64) for BITMAP type
So far we have three storage format for BITMAP type
```
EMPTY := TypeCode(0x00)
SINGLE32 := TypeCode(0x01), UInt32LittleEndian
BITMAP32 := TypeCode(0x02), RoaringBitmap(defined by https://github.com/RoaringBitmap/RoaringFormatSpec/)
```
In order to support BIGINT element and keep backward compatibility, introduce two new format
```
SINGLE64 := TypeCode(0x03), UInt64LittleEndian
BITMAP64 := TypeCode(0x04), CustomRoaringBitmap64
```
Please note that SINGLE64/BITMAP64 doesn't replace SINGLE32/BITMAP32. Doris will choose the smaller (in terms of space) type automatically during serializing. For example, BITMAP32 is preferred over BITMAP64 when the maximum element is <= UINT32_MAX. This will also make BE rollback possible as long as user didn't write element larger than UINT32_MAX into bitmap column.
Another important design decision is that we fork and maintain our own version of Roaring64Map instead of using the one in "roaring/roaring64map.hh". The reasons are
1. RoaringBitmap doesn't define a standard for the binary format of 64-bits bitmap. As a result, different implementations of Roaring64Map use different format. For example the [C++ version](https://github.com/RoaringBitmap/CRoaring/blob/v0.2.60/cpp/roaring64map.hh#L545) is different from the [Java version](35104c564e/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java (L1097)). Even for CRoaring, the format may change in future releases. However Doris require the serialized format to be stable across versions. Fork is a safe way to achieve this.
2. We may want to make some code changes to Roaring64Map according to our needs. For example, in order to use the BITMAP32 format when the maximum element can be represented in 32 bits, we may want to access the private member of Roaring64Map. Another example is we want to further customize and optimize the format for BITMAP64 case, such as using vint64 instead of uint64 for map size.
617 lines
22 KiB
C++
617 lines
22 KiB
C++
// 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 "exprs/bitmap_function.h"
|
|
|
|
#include "exprs/anyval_util.h"
|
|
#include "util/bitmap_value.h"
|
|
#include "util/string_parser.hpp"
|
|
#include "gutil/strings/split.h"
|
|
#include "gutil/strings/numbers.h"
|
|
|
|
namespace doris {
|
|
|
|
namespace detail {
|
|
|
|
const int DATETIME_PACKED_TIME_BYTE_SIZE = 8;
|
|
const int DATETIME_TYPE_BYTE_SIZE = 4;
|
|
|
|
const int DECIMAL_BYTE_SIZE = 16;
|
|
|
|
// get_val start
|
|
template<typename ValType, typename T>
|
|
T get_val(const ValType& x) {
|
|
DCHECK(!x.is_null);
|
|
return x.val;
|
|
}
|
|
|
|
template<>
|
|
StringValue get_val(const StringVal& x) {
|
|
DCHECK(!x.is_null);
|
|
return StringValue::from_string_val(x);
|
|
}
|
|
|
|
template<>
|
|
DateTimeValue get_val(const DateTimeVal& x) {
|
|
return DateTimeValue::from_datetime_val(x);
|
|
}
|
|
|
|
template<>
|
|
DecimalV2Value get_val(const DecimalV2Val& x) {
|
|
return DecimalV2Value::from_decimal_val(x);
|
|
}
|
|
// get_val end
|
|
|
|
// serialize_size start
|
|
template<typename T>
|
|
int32_t serialize_size(const T& v) {
|
|
return sizeof(T);
|
|
}
|
|
|
|
template<>
|
|
int32_t serialize_size(const DateTimeValue& v) {
|
|
return DATETIME_PACKED_TIME_BYTE_SIZE + DATETIME_TYPE_BYTE_SIZE;
|
|
}
|
|
|
|
template<>
|
|
int32_t serialize_size(const DecimalV2Value& v) {
|
|
return DECIMAL_BYTE_SIZE;
|
|
}
|
|
|
|
template<>
|
|
int32_t serialize_size(const StringValue& v) {
|
|
return v.len + 4;
|
|
}
|
|
// serialize_size end
|
|
|
|
// write_to start
|
|
template<typename T>
|
|
char* write_to(const T& v, char* dest) {
|
|
size_t type_size = sizeof(T);
|
|
memcpy(dest, &v, type_size);
|
|
dest += type_size;
|
|
return dest;
|
|
}
|
|
|
|
template<>
|
|
char* write_to(const DateTimeValue& v, char* dest) {
|
|
DateTimeVal value;
|
|
v.to_datetime_val(&value);
|
|
*(int64_t*)dest = value.packed_time;
|
|
dest += DATETIME_PACKED_TIME_BYTE_SIZE;
|
|
*(int*)dest = value.type;
|
|
dest += DATETIME_TYPE_BYTE_SIZE;
|
|
return dest;
|
|
}
|
|
|
|
template<>
|
|
char* write_to(const DecimalV2Value& v, char* dest) {
|
|
__int128 value = v.value();
|
|
memcpy(dest, &value, DECIMAL_BYTE_SIZE);
|
|
dest += DECIMAL_BYTE_SIZE;
|
|
return dest;
|
|
}
|
|
|
|
template<>
|
|
char* write_to(const StringValue& v, char* dest) {
|
|
*(int32_t*)dest = v.len;
|
|
dest += 4;
|
|
memcpy(dest, v.ptr, v.len);
|
|
dest += v.len;
|
|
return dest;
|
|
}
|
|
// write_to end
|
|
|
|
// read_from start
|
|
template<typename T>
|
|
void read_from(const char** src, T* result) {
|
|
size_t type_size = sizeof(T);
|
|
memcpy(result, *src, type_size);
|
|
*src += type_size;
|
|
}
|
|
|
|
template<>
|
|
void read_from(const char** src, DateTimeValue* result) {
|
|
DateTimeVal value;
|
|
value.is_null = false;
|
|
value.packed_time = *(int64_t*)(*src);
|
|
*src += DATETIME_PACKED_TIME_BYTE_SIZE;
|
|
value.type = *(int*)(*src);
|
|
*src += DATETIME_TYPE_BYTE_SIZE;
|
|
*result = DateTimeValue::from_datetime_val(value);;
|
|
}
|
|
|
|
template<>
|
|
void read_from(const char** src, DecimalV2Value* result) {
|
|
__int128 v = 0;
|
|
memcpy(&v, *src, DECIMAL_BYTE_SIZE);
|
|
*src += DECIMAL_BYTE_SIZE;
|
|
*result = DecimalV2Value(v);
|
|
}
|
|
|
|
template<>
|
|
void read_from(const char** src, StringValue* result) {
|
|
int32_t length = *(int32_t*)(*src);
|
|
*src += 4;
|
|
*result = StringValue((char *)*src, length);
|
|
*src += length;
|
|
}
|
|
// read_from end
|
|
|
|
} // namespace detail
|
|
|
|
static StringVal serialize(FunctionContext* ctx, BitmapValue* value) {
|
|
StringVal result(ctx, value->getSizeInBytes());
|
|
value->write((char*) result.ptr);
|
|
return result;
|
|
}
|
|
|
|
// Calculate the intersection of two or more bitmaps
|
|
// Usage: intersect_count(bitmap_column_to_count, filter_column, filter_values ...)
|
|
// Example: intersect_count(user_id, event, 'A', 'B', 'C'), meaning find the intersect count of user_id in all A/B/C 3 bitmaps
|
|
// Todo(kks) Use Array type instead of variable arguments
|
|
template<typename T>
|
|
struct BitmapIntersect {
|
|
public:
|
|
BitmapIntersect() {}
|
|
|
|
explicit BitmapIntersect(const char* src) {
|
|
deserialize(src);
|
|
}
|
|
|
|
void add_key(const T key) {
|
|
BitmapValue empty_bitmap;
|
|
_bitmaps[key] = empty_bitmap;
|
|
}
|
|
|
|
void update(const T& key, const BitmapValue& bitmap) {
|
|
if (_bitmaps.find(key) != _bitmaps.end()) {
|
|
_bitmaps[key] |= bitmap;
|
|
}
|
|
}
|
|
|
|
void merge(const BitmapIntersect& other) {
|
|
for (auto& kv: other._bitmaps) {
|
|
if (_bitmaps.find(kv.first) != _bitmaps.end()) {
|
|
_bitmaps[kv.first] |= kv.second;
|
|
} else {
|
|
_bitmaps[kv.first] = kv.second;
|
|
}
|
|
}
|
|
}
|
|
|
|
// calculate the intersection for _bitmaps's bitmap values
|
|
int64_t intersect_count() const {
|
|
if (_bitmaps.empty()) {
|
|
return 0;
|
|
}
|
|
|
|
BitmapValue result;
|
|
auto it = _bitmaps.begin();
|
|
result |= it->second;
|
|
it++;
|
|
for (;it != _bitmaps.end(); it++) {
|
|
result &= it->second;
|
|
}
|
|
|
|
return result.cardinality();
|
|
}
|
|
|
|
// the serialize size
|
|
size_t size() {
|
|
size_t size = 4;
|
|
for (auto& kv: _bitmaps) {
|
|
size += detail::serialize_size(kv.first);;
|
|
size += kv.second.getSizeInBytes();
|
|
}
|
|
return size;
|
|
}
|
|
|
|
//must call size() first
|
|
void serialize(char* dest) {
|
|
char* writer = dest;
|
|
*(int32_t*)writer = _bitmaps.size();
|
|
writer += 4;
|
|
for (auto& kv: _bitmaps) {
|
|
writer = detail::write_to(kv.first, writer);
|
|
kv.second.write(writer);
|
|
writer += kv.second.getSizeInBytes();
|
|
}
|
|
}
|
|
|
|
void deserialize(const char* src) {
|
|
const char* reader = src;
|
|
int32_t bitmaps_size = *(int32_t*)reader;
|
|
reader += 4;
|
|
for (int32_t i = 0; i < bitmaps_size; i++) {
|
|
T key;
|
|
detail::read_from(&reader, &key);
|
|
BitmapValue bitmap(reader);
|
|
reader += bitmap.getSizeInBytes();
|
|
_bitmaps[key] = bitmap;
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::map<T, BitmapValue> _bitmaps;
|
|
};
|
|
|
|
void BitmapFunctions::init() {
|
|
}
|
|
|
|
void BitmapFunctions::bitmap_init(FunctionContext* ctx, StringVal* dst) {
|
|
dst->is_null = false;
|
|
dst->len = sizeof(BitmapValue);
|
|
dst->ptr = (uint8_t*)new BitmapValue();
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_empty(FunctionContext* ctx) {
|
|
BitmapValue bitmap;
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
template <typename T>
|
|
void BitmapFunctions::bitmap_update_int(FunctionContext* ctx, const T& src, StringVal* dst) {
|
|
if (src.is_null) {
|
|
return;
|
|
}
|
|
|
|
auto dst_bitmap = reinterpret_cast<BitmapValue*>(dst->ptr);
|
|
dst_bitmap->add(src.val);
|
|
}
|
|
|
|
BigIntVal BitmapFunctions::bitmap_finalize(FunctionContext* ctx, const StringVal& src) {
|
|
auto src_bitmap = reinterpret_cast<BitmapValue*>(src.ptr);
|
|
BigIntVal result(src_bitmap->cardinality());
|
|
delete src_bitmap;
|
|
return result;
|
|
}
|
|
|
|
void BitmapFunctions::bitmap_union(FunctionContext* ctx, const StringVal& src, StringVal* dst) {
|
|
auto dst_bitmap = reinterpret_cast<BitmapValue*>(dst->ptr);
|
|
// zero size means the src input is a agg object
|
|
if (src.len == 0) {
|
|
(*dst_bitmap) |= *reinterpret_cast<BitmapValue*>(src.ptr);
|
|
} else {
|
|
(*dst_bitmap) |= BitmapValue((char*) src.ptr);
|
|
}
|
|
}
|
|
|
|
BigIntVal BitmapFunctions::bitmap_count(FunctionContext* ctx, const StringVal& src) {
|
|
// zero size means the src input is a agg object
|
|
if (src.len == 0) {
|
|
auto bitmap = reinterpret_cast<BitmapValue*>(src.ptr);
|
|
return { bitmap->cardinality() };
|
|
} else {
|
|
BitmapValue bitmap((char*)src.ptr);
|
|
return { bitmap.cardinality() };
|
|
}
|
|
}
|
|
|
|
StringVal BitmapFunctions::to_bitmap(doris_udf::FunctionContext* ctx, const doris_udf::StringVal& src) {
|
|
BitmapValue bitmap;
|
|
if (!src.is_null) {
|
|
StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS;
|
|
uint64_t int_value = StringParser::string_to_unsigned_int<uint64_t>(reinterpret_cast<char*>(src.ptr), src.len, &parse_result);
|
|
if (UNLIKELY(parse_result != StringParser::PARSE_SUCCESS)) {
|
|
std::stringstream error_msg;
|
|
error_msg << "The input: " << std::string(reinterpret_cast<char*>(src.ptr), src.len)
|
|
<< " is not valid, to_bitmap only support bigint value from 0 to 18446744073709551615 currently";
|
|
ctx->set_error(error_msg.str().c_str());
|
|
return StringVal::null();
|
|
}
|
|
bitmap.add(int_value);
|
|
}
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_hash(doris_udf::FunctionContext* ctx, const doris_udf::StringVal& src) {
|
|
BitmapValue bitmap;
|
|
if (!src.is_null) {
|
|
uint32_t hash_value = HashUtil::murmur_hash3_32(src.ptr, src.len, HashUtil::MURMUR3_32_SEED);
|
|
bitmap.add(hash_value);
|
|
}
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_serialize(FunctionContext* ctx, const StringVal& src) {
|
|
auto src_bitmap = reinterpret_cast<BitmapValue*>(src.ptr);
|
|
StringVal result = serialize(ctx, src_bitmap);
|
|
delete src_bitmap;
|
|
return result;
|
|
}
|
|
|
|
template<typename T, typename ValType>
|
|
void BitmapFunctions::bitmap_intersect_init(FunctionContext* ctx, StringVal* dst) {
|
|
dst->is_null = false;
|
|
dst->len = sizeof(BitmapIntersect<T>);
|
|
auto intersect = new BitmapIntersect<T>();
|
|
|
|
// constant args start from index 2
|
|
for (int i = 2; i < ctx->get_num_constant_args(); ++i) {
|
|
DCHECK(ctx->is_arg_constant(i));
|
|
ValType* arg = reinterpret_cast<ValType*>(ctx->get_constant_arg(i));
|
|
intersect->add_key(detail::get_val<ValType, T>(*arg));
|
|
}
|
|
|
|
dst->ptr = (uint8_t*)intersect;
|
|
}
|
|
|
|
template<typename T, typename ValType>
|
|
void BitmapFunctions::bitmap_intersect_update(FunctionContext* ctx, const StringVal& src, const ValType& key,
|
|
int num_key, const ValType* keys, const StringVal* dst) {
|
|
auto* dst_bitmap = reinterpret_cast<BitmapIntersect<T>*>(dst->ptr);
|
|
// zero size means the src input is a agg object
|
|
if (src.len == 0) {
|
|
dst_bitmap->update(detail::get_val<ValType, T>(key), *reinterpret_cast<BitmapValue*>(src.ptr));
|
|
} else {
|
|
dst_bitmap->update(detail::get_val<ValType, T>(key), BitmapValue((char*)src.ptr));
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void BitmapFunctions::bitmap_intersect_merge(FunctionContext* ctx, const StringVal& src, const StringVal* dst) {
|
|
auto* dst_bitmap = reinterpret_cast<BitmapIntersect<T>*>(dst->ptr);
|
|
dst_bitmap->merge(BitmapIntersect<T>((char*)src.ptr));
|
|
}
|
|
|
|
template<typename T>
|
|
StringVal BitmapFunctions::bitmap_intersect_serialize(FunctionContext* ctx, const StringVal& src) {
|
|
auto* src_bitmap = reinterpret_cast<BitmapIntersect<T>*>(src.ptr);
|
|
StringVal result(ctx, src_bitmap->size());
|
|
src_bitmap->serialize((char*)result.ptr);
|
|
delete src_bitmap;
|
|
return result;
|
|
}
|
|
|
|
template<typename T>
|
|
BigIntVal BitmapFunctions::bitmap_intersect_finalize(FunctionContext* ctx, const StringVal& src) {
|
|
auto* src_bitmap = reinterpret_cast<BitmapIntersect<T>*>(src.ptr);
|
|
BigIntVal result = BigIntVal(src_bitmap->intersect_count());
|
|
delete src_bitmap;
|
|
return result;
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_or(FunctionContext* ctx, const StringVal& lhs, const StringVal& rhs){
|
|
if (lhs.is_null || rhs.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
BitmapValue bitmap;
|
|
if (lhs.len == 0) {
|
|
bitmap |= *reinterpret_cast<BitmapValue*>(lhs.ptr);
|
|
} else {
|
|
bitmap |= BitmapValue((char*)lhs.ptr);
|
|
}
|
|
|
|
if (rhs.len == 0) {
|
|
bitmap |= *reinterpret_cast<BitmapValue*>(rhs.ptr);
|
|
} else {
|
|
bitmap |= BitmapValue((char*)rhs.ptr);
|
|
}
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_and(FunctionContext* ctx, const StringVal& lhs, const StringVal& rhs){
|
|
if (lhs.is_null || rhs.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
BitmapValue bitmap;
|
|
if (lhs.len == 0) {
|
|
bitmap |= *reinterpret_cast<BitmapValue*>(lhs.ptr);
|
|
} else {
|
|
bitmap |= BitmapValue((char*)lhs.ptr);
|
|
}
|
|
|
|
if (rhs.len == 0) {
|
|
bitmap &= *reinterpret_cast<BitmapValue*>(rhs.ptr);
|
|
} else {
|
|
bitmap &= BitmapValue((char*)rhs.ptr);
|
|
}
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_to_string(FunctionContext* ctx, const StringVal& input) {
|
|
if (input.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
std::string str;
|
|
if (input.len == 0) {
|
|
str = reinterpret_cast<BitmapValue*>(input.ptr)->to_string();
|
|
} else {
|
|
BitmapValue bitmap((char*)input.ptr);
|
|
str = bitmap.to_string();
|
|
}
|
|
return AnyValUtil::from_string_temp(ctx, str);
|
|
}
|
|
|
|
StringVal BitmapFunctions::bitmap_from_string(FunctionContext* ctx, const StringVal& input) {
|
|
if (input.is_null) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
std::vector<uint64_t> bits;
|
|
if (!SplitStringAndParse({(const char*)input.ptr, input.len}, ",", &safe_strtou64, &bits)) {
|
|
return StringVal::null();
|
|
}
|
|
|
|
BitmapValue bitmap(bits);
|
|
return serialize(ctx, &bitmap);
|
|
}
|
|
|
|
BooleanVal BitmapFunctions::bitmap_contains(FunctionContext* ctx, const StringVal& src, const BigIntVal& input) {
|
|
if (src.is_null || input.is_null) {
|
|
return BooleanVal::null();
|
|
}
|
|
|
|
if (src.len == 0) {
|
|
auto bitmap = reinterpret_cast<BitmapValue*>(src.ptr);
|
|
return { bitmap->contains(input.val) };
|
|
}
|
|
|
|
BitmapValue bitmap((char*)src.ptr);
|
|
return { bitmap.contains(input.val) };
|
|
}
|
|
|
|
BooleanVal BitmapFunctions::bitmap_has_any(FunctionContext* ctx, const StringVal& lhs, const StringVal& rhs) {
|
|
if (lhs.is_null || rhs.is_null) {
|
|
return BooleanVal::null();
|
|
}
|
|
|
|
BitmapValue bitmap;
|
|
if (lhs.len == 0) {
|
|
bitmap |= *reinterpret_cast<BitmapValue*>(lhs.ptr);
|
|
} else {
|
|
bitmap |= BitmapValue((char*)lhs.ptr);
|
|
}
|
|
|
|
if (rhs.len == 0) {
|
|
bitmap &= *reinterpret_cast<BitmapValue*>(rhs.ptr);
|
|
} else {
|
|
bitmap &= BitmapValue((char*)rhs.ptr);
|
|
}
|
|
|
|
return { bitmap.cardinality() != 0 };
|
|
}
|
|
|
|
template void BitmapFunctions::bitmap_update_int<TinyIntVal>(
|
|
FunctionContext* ctx, const TinyIntVal& src, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_update_int<SmallIntVal>(
|
|
FunctionContext* ctx, const SmallIntVal& src, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_update_int<IntVal>(
|
|
FunctionContext* ctx, const IntVal& src, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_update_int<BigIntVal>(
|
|
FunctionContext* ctx, const BigIntVal& src, StringVal* dst);
|
|
|
|
template void BitmapFunctions::bitmap_intersect_init<int8_t, TinyIntVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<int16_t, SmallIntVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<int32_t, IntVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<int64_t, BigIntVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<__int128, LargeIntVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<float, FloatVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<double, DoubleVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<DateTimeValue, DateTimeVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<DecimalV2Value, DecimalV2Val>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_init<StringValue, StringVal>(
|
|
FunctionContext* ctx, StringVal* dst);
|
|
|
|
|
|
template void BitmapFunctions::bitmap_intersect_update<int8_t, TinyIntVal>(
|
|
FunctionContext* ctx, const StringVal& src, const TinyIntVal& key,
|
|
int num_key, const TinyIntVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<int16_t, SmallIntVal>(
|
|
FunctionContext* ctx, const StringVal& src, const SmallIntVal& key,
|
|
int num_key, const SmallIntVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<int32_t, IntVal>(
|
|
FunctionContext* ctx, const StringVal& src, const IntVal& key,
|
|
int num_key, const IntVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<int64_t, BigIntVal>(
|
|
FunctionContext* ctx, const StringVal& src, const BigIntVal& key,
|
|
int num_key, const BigIntVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<__int128, LargeIntVal>(
|
|
FunctionContext* ctx, const StringVal& src, const LargeIntVal& key,
|
|
int num_key, const LargeIntVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<float, FloatVal>(
|
|
FunctionContext* ctx, const StringVal& src, const FloatVal& key,
|
|
int num_key, const FloatVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<double, DoubleVal>(
|
|
FunctionContext* ctx, const StringVal& src, const DoubleVal& key,
|
|
int num_key, const DoubleVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<DateTimeValue, DateTimeVal>(
|
|
FunctionContext* ctx, const StringVal& src, const DateTimeVal& key,
|
|
int num_key, const DateTimeVal* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<DecimalV2Value, DecimalV2Val>(
|
|
FunctionContext* ctx, const StringVal& src, const DecimalV2Val& key,
|
|
int num_key, const DecimalV2Val* keys, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_update<StringValue, StringVal>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal& key,
|
|
int num_key, const StringVal* keys, const StringVal* dst);
|
|
|
|
|
|
template void BitmapFunctions::bitmap_intersect_merge<int8_t>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<int16_t>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<int32_t>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<int64_t>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<__int128>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<float>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<double>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<DateTimeValue>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<DecimalV2Value>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
template void BitmapFunctions::bitmap_intersect_merge<StringValue>(
|
|
FunctionContext* ctx, const StringVal& src, const StringVal* dst);
|
|
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<int8_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<int16_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<int32_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<int64_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<__int128>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<float>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<double>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<DateTimeValue>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<DecimalV2Value>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template StringVal BitmapFunctions::bitmap_intersect_serialize<StringValue>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<int8_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<int16_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<int32_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<int64_t>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<__int128>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<float>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<double>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<DateTimeValue>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<DecimalV2Value>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
template BigIntVal BitmapFunctions::bitmap_intersect_finalize<StringValue>(
|
|
FunctionContext* ctx, const StringVal& src);
|
|
|
|
}
|