blob: 5fe89096202c8a1296133cf5dd8e27fdf9a797dd [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.
*/
#ifndef DBCOMMON_SRC_DBCOMMON_FUNCTION_FUNCTION_H_
#define DBCOMMON_SRC_DBCOMMON_FUNCTION_FUNCTION_H_
#include "dbcommon/common/vector-transformer.h"
#include "dbcommon/common/vector/decimal-vector.h"
namespace dbcommon {
// Here, I am going to draft the blueprint on how these template function and
// callable object work together to construct a dbcommon::Function.
//
// There are six basic elements:
// 1. C++ POD and ByteBuffer
// actual physical unit that specify how to retrieve raw data, which
// could be int32_t, int64_t, text, Timestamp, DecimalVar and etc.
//
// 2. callable object
// operate on C++ POD and ByteBuffer, which works like that in
// Postgres
//
// 3. n-ary_param_bind
// delegate specific function according to input type's combination
// of n-ary Cartesian power of {Vector, Scalar}
//
// 4. Vector/Scalar and their corresponding VectorRawData/ScalarRawData
// used by delegated function to retrieve specific raw data according
// to the deduced {Vector, Scalar} combination and POD parameterized
// type
//
// 5. func_bind
// use VectorRawData/ScalarRawData's setter and getter to bind
// callable object over the raw data iterator
//
// 6. transformVector
// apply callable object when iterate over the raw data
//
// Typically, the elements that needed to be taken into count for users is 1, 2,
// and 3.
//
// Take DEMO_FUNCTION as an example, which capitalizes these basic elements.
//
// User specifies 2 parameterized type, calls one_param_bind and provides a
// callable object, which is a lambda function that takes matching argument type
// and return matching return type according the the specified parameterized
// type.
//
// Datum DEME_FUNCTION(Datum *params, uint64_t size) {
// auto CALLABLE_OBJECT = [](ByteBuffer &buf, PARA_TYPE1 str) -> RETURN_TYPE {
// buf.resize(buf.size() + str.length);
// memcpy(buf.tail() - str.length, str.val, str.length);
// return RETURN_TYPE(nullptr, str.length);
// };
// return ONE_PARAM_BIND<RETURN_TYPE, PARA_TYPE1>(params, size,
// CALLABLE_OBJECT);
// }
//
// The most tricky thing among these elements is ByteBuffer, which is a special
// use for supporting memory allocation for variable length data type, i.e.
// text.
template <class Type>
struct VectorRawData {
VectorRawData<Type>(Vector *in) : vec(in) {}
Type get(uint64_t plainIdx) { return vec.values[plainIdx]; }
void set(uint64_t plainIdx, Type val) { vec.values[plainIdx] = val; }
FixedSizeTypeVectorRawData<Type> vec;
};
template <>
struct VectorRawData<text> {
VectorRawData<text>(Vector *in) : vec(in) {}
text get(uint64_t plainIdx) {
return text(vec.valptrs[plainIdx], vec.lengths[plainIdx]);
}
void set(uint64_t plainIdx, text val) { vec.lengths[plainIdx] = val.length; }
VariableSizeTypeVectorRawData vec;
};
template <>
struct VectorRawData<DecimalVar> {
VectorRawData<DecimalVar>(Vector *in) : vec(in) {}
DecimalVar get(uint64_t plainIdx) {
return DecimalVar(vec.hightbits[plainIdx], vec.lowbits[plainIdx],
vec.scales[plainIdx]);
}
void set(uint64_t plainIdx, DecimalVar val) {
vec.hightbits[plainIdx] = val.highbits;
vec.lowbits[plainIdx] = val.lowbits;
vec.scales[plainIdx] = val.scale;
}
DecimalVectorRawData vec;
};
template <>
struct VectorRawData<Timestamp> {
VectorRawData<Timestamp>(Vector *in) : vec(in) {}
Timestamp get(uint64_t plainIdx) {
return Timestamp(vec.seconds[plainIdx], vec.nanoseconds[plainIdx]);
}
void set(uint64_t plainIdx, Timestamp val) {
vec.seconds[plainIdx] = val.second;
vec.nanoseconds[plainIdx] = val.nanosecond;
}
TimestampVectorRawData vec;
};
template <>
struct VectorRawData<IntervalVar> {
VectorRawData<IntervalVar>(Vector *in) : vec(in) {}
IntervalVar get(uint64_t plainIdx) {
return IntervalVar(vec.timeOffsets[plainIdx], vec.days[plainIdx],
vec.months[plainIdx]);
}
void set(uint64_t plainIdx, IntervalVar val) {
vec.timeOffsets[plainIdx] = val.timeOffset;
vec.days[plainIdx] = val.day;
vec.months[plainIdx] = val.month;
}
IntervalVectorRawData vec;
};
template <class Type>
struct ScalarRawData {
ScalarRawData<Type>(Scalar *in) : scalar(in) {}
Type get() { return scalar->value; }
void set(Type val) { scalar->value = CreateDatum<Type>(val); }
private:
Scalar *scalar;
};
template <>
struct ScalarRawData<text> {
ScalarRawData<text>(Scalar *in) : scalar(in) {}
text get() { return text(scalar->value, scalar->length); }
void set(text val) {
scalar->value = CreateDatum(scalar->getValueBuffer()->data());
scalar->length = val.length;
}
private:
Scalar *scalar;
};
template <>
struct ScalarRawData<DecimalVar> {
ScalarRawData<DecimalVar>(Scalar *in) : scalar(in) {}
DecimalVar get() { return *DatumGetValue<DecimalVar *>(scalar->value); }
void set(DecimalVar val) { scalar->length = sizeof(DecimalVar); }
private:
Scalar *scalar;
};
template <>
struct ScalarRawData<Timestamp> {
ScalarRawData<Timestamp>(Scalar *in) : scalar(in) {}
Timestamp get() {
Timestamp *val = DatumGetValue<Timestamp *>(scalar->value);
return *val;
}
void set(Timestamp ts) {
Timestamp *val = scalar->allocateValue<Timestamp>();
val->second = ts.second;
val->nanosecond = ts.nanosecond;
scalar->value = CreateDatum<Timestamp *>(val);
scalar->length = sizeof(Timestamp);
}
private:
Scalar *scalar;
};
template <>
struct ScalarRawData<IntervalVar> {
ScalarRawData<IntervalVar>(Scalar *in) : scalar(in) {}
IntervalVar get() {
IntervalVar *val = DatumGetValue<IntervalVar *>(scalar->value);
return *val;
}
void set(IntervalVar interval) {
IntervalVar *val = scalar->allocateValue<IntervalVar>();
val->timeOffset = interval.timeOffset;
val->day = interval.day;
val->month = interval.month;
scalar->value = CreateDatum<IntervalVar *>(val);
scalar->length = sizeof(IntervalVar);
}
private:
Scalar *scalar;
};
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_VectorVectorVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Vector *para2Vector = params[2];
Vector *para3Vector = params[3];
para1Vector->trim();
para2Vector->trim();
para3Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
VectorRawData<ParaType2> para2(para2Vector);
VectorRawData<ParaType3> para3(para3Vector);
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls,
para2.vec.nulls, para3.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get(plainIdx), para3.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_VectorVectorScalar(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Vector *para2Vector = params[2];
Scalar *para3Scalar = params[3];
para1Vector->trim();
para2Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
VectorRawData<ParaType2> para2(para2Vector);
ScalarRawData<ParaType3> para3(para3Scalar);
if (para3Scalar->isnull) {
retVector->resize(para1.vec.plainSize, para1.vec.sel, true);
} else {
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls,
para2.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get(plainIdx), para3.get()));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_VectorScalarVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Scalar *para2Scalar = params[2];
Vector *para3Vector = params[3];
para1Vector->trim();
para3Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
ScalarRawData<ParaType2> para2(para2Scalar);
VectorRawData<ParaType3> para3(para3Vector);
if (para2Scalar->isnull) {
retVector->resize(para1.vec.plainSize, para1.vec.sel, true);
} else {
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls,
para3.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get(), para3.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_VectorScalarScalar(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Scalar *para2Scalar = params[2];
Scalar *para3Scalar = params[3];
para1Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
ScalarRawData<ParaType2> para2(para2Scalar);
ScalarRawData<ParaType3> para3(para3Scalar);
if (para2Scalar->isnull || para3Scalar->isnull) {
retVector->resize(para1.vec.plainSize, para1.vec.sel, true);
} else {
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get(), para3.get()));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_ScalarVectorVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Scalar *para1Scalar = params[1];
Vector *para2Vector = params[2];
Vector *para3Vector = params[3];
para2Vector->trim();
para3Vector->trim();
ScalarRawData<ParaType1> para1(para1Scalar);
VectorRawData<ParaType2> para2(para2Vector);
VectorRawData<ParaType3> para3(para3Vector);
if (para1Scalar->isnull) {
retVector->resize(para2.vec.plainSize, para2.vec.sel, true);
} else {
retVector->resize(para2.vec.plainSize, para2.vec.sel, para2.vec.nulls,
para3.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(),
para2.get(plainIdx), para3.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_ScalarVectorScalar(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Scalar *para1Scalar = params[1];
Vector *para2Vector = params[2];
Scalar *para3Scalar = params[3];
para2Vector->trim();
ScalarRawData<ParaType1> para1(para1Scalar);
VectorRawData<ParaType2> para2(para2Vector);
ScalarRawData<ParaType3> para3(para3Scalar);
if (para1Scalar->isnull || para3Scalar->isnull) {
retVector->resize(para2.vec.plainSize, para2.vec.sel, true);
} else {
retVector->resize(para2.vec.plainSize, para2.vec.sel, para2.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(),
para2.get(plainIdx), para3.get()));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_ScalarScalarVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Scalar *para1Scalar = params[1];
Scalar *para2Scalar = params[2];
Vector *para3Vector = params[3];
para3Vector->trim();
ScalarRawData<ParaType1> para1(para1Scalar);
ScalarRawData<ParaType2> para2(para2Scalar);
VectorRawData<ParaType3> para3(para3Vector);
if (para1Scalar->isnull || para2Scalar->isnull) {
retVector->resize(para3.vec.plainSize, para3.vec.sel, true);
} else {
retVector->resize(para3.vec.plainSize, para3.vec.sel, para3.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(),
para2.get(), para3.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
inline Datum transform_ScalarScalarScalar(Datum *params, uint64_t size,
FunctionProto func) {
Scalar *retScalar = params[0];
Scalar *para1Scalar = params[1];
Scalar *para2Scalar = params[2];
Scalar *para3Scalar = params[3];
if (para1Scalar->isnull || para2Scalar->isnull || para3Scalar->isnull) {
retScalar->isnull = true;
} else {
retScalar->isnull = false;
ScalarRawData<RetType> ret(retScalar);
ScalarRawData<ParaType1> para1(para1Scalar);
ScalarRawData<ParaType2> para2(para2Scalar);
ScalarRawData<ParaType3> para3(para3Scalar);
retScalar->getValueBuffer()->clear();
ret.set(func(*retScalar->getValueBuffer(), para1.get(), para2.get(),
para3.get()));
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
typename ParaType3, class FunctionProto>
Datum three_params_bind(Datum *params, uint64_t size, FunctionProto func) {
Object *para1 = DatumGetValue<Object *>(params[1]);
Object *para2 = DatumGetValue<Object *>(params[2]);
Object *para3 = DatumGetValue<Object *>(params[3]);
Vector *vec1 = dynamic_cast<Vector *>(para1);
Vector *vec2 = dynamic_cast<Vector *>(para2);
Vector *vec3 = dynamic_cast<Vector *>(para3);
if (vec1) {
if (vec2) {
if (vec3) {
return transform_VectorVectorVector<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
} else {
return transform_VectorVectorScalar<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
}
} else {
if (vec3) {
return transform_VectorScalarVector<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
} else {
return transform_VectorScalarScalar<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
}
}
} else {
if (vec2) {
if (vec3) {
return transform_ScalarVectorVector<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
} else {
return transform_ScalarVectorScalar<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
}
} else {
if (vec3) {
return transform_ScalarScalarVector<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
} else {
return transform_ScalarScalarScalar<RetType, ParaType1, ParaType2,
ParaType3>(params, size, func);
}
}
}
}
template <typename RetType, typename ParaType1, typename ParaType2,
class FunctionProto>
inline Datum transform_VectorVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Vector *para2Vector = params[2];
para1Vector->trim();
para2Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
VectorRawData<ParaType2> para2(para2Vector);
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls,
para2.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
class FunctionProto>
inline Datum transform_VectorScalar(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *para1Vector = params[1];
Scalar *para2Scalar = params[2];
para1Vector->trim();
VectorRawData<ParaType1> para1(para1Vector);
ScalarRawData<ParaType2> para2(para2Scalar);
if (para2Scalar->isnull) {
retVector->resize(para1.vec.plainSize, para1.vec.sel, true);
} else {
retVector->resize(para1.vec.plainSize, para1.vec.sel, para1.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(plainIdx),
para2.get()));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
class FunctionProto>
inline Datum transform_ScalarVector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Scalar *para1Scalar = params[1];
Vector *para2Vector = params[2];
para2Vector->trim();
ScalarRawData<ParaType1> para1(para1Scalar);
VectorRawData<ParaType2> para2(para2Vector);
if (para1Scalar->isnull) {
retVector->resize(para2.vec.plainSize, para2.vec.sel, true);
} else {
retVector->resize(para2.vec.plainSize, para2.vec.sel, para2.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para1.get(),
para2.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
class FunctionProto>
inline Datum transform_ScalarScalar(Datum *params, uint64_t size,
FunctionProto func) {
Scalar *retScalar = params[0];
Scalar *para1Scalar = params[1];
Scalar *para2Scalar = params[2];
if (para1Scalar->isnull || para2Scalar->isnull) {
retScalar->isnull = true;
} else {
retScalar->isnull = false;
ScalarRawData<RetType> ret(retScalar);
ScalarRawData<ParaType1> para1(para1Scalar);
ScalarRawData<ParaType2> para2(para2Scalar);
retScalar->getValueBuffer()->clear();
ret.set(func(*retScalar->getValueBuffer(), para1.get(), para2.get()));
}
return params[0];
}
template <typename RetType, typename ParaType1, typename ParaType2,
class FunctionProto>
Datum two_params_bind(Datum *params, uint64_t size, FunctionProto func) {
Object *paraL = DatumGetValue<Object *>(params[1]);
Vector *vecL = dynamic_cast<Vector *>(paraL);
Object *paraR = DatumGetValue<Object *>(params[2]);
Vector *vecR = dynamic_cast<Vector *>(paraR);
if (vecL) {
if (vecR) {
return transform_VectorVector<RetType, ParaType1, ParaType2>(params, size,
func);
} else {
return transform_VectorScalar<RetType, ParaType1, ParaType2>(params, size,
func);
}
} else {
if (vecR) {
return transform_ScalarVector<RetType, ParaType1, ParaType2>(params, size,
func);
} else {
return transform_ScalarScalar<RetType, ParaType1, ParaType2>(params, size,
func);
}
}
}
template <typename RetType, typename ParaType, class FunctionProto>
inline Datum transform_Vector(Datum *params, uint64_t size,
FunctionProto func) {
Vector *retVector = params[0];
Vector *paraVector = params[1];
paraVector->trim();
VectorRawData<ParaType> para(paraVector);
retVector->resize(para.vec.plainSize, para.vec.sel, para.vec.nulls);
VectorRawData<RetType> ret(retVector);
auto func_bind = [&](uint64_t plainIdx) {
ret.set(plainIdx, func(*retVector->getValueBuffer(), para.get(plainIdx)));
};
transformVector(ret.vec.plainSize, ret.vec.sel, ret.vec.nulls, func_bind);
retVector->computeValPtrs();
return params[0];
}
template <typename RetType, typename ParaType, class FunctionProto>
inline Datum transform_Scalar(Datum *params, uint64_t size,
FunctionProto func) {
Scalar *retScalar = params[0];
Scalar *paraScalar = params[1];
if (paraScalar->isnull) {
retScalar->isnull = true;
} else {
retScalar->isnull = false;
ScalarRawData<ParaType> para(paraScalar);
ScalarRawData<RetType> ret(retScalar);
retScalar->getValueBuffer()->clear();
ret.set(func(*retScalar->getValueBuffer(), para.get()));
}
return params[0];
}
template <typename RetType, typename ParaType, class FunctionProto>
Datum one_param_bind(Datum *params, uint64_t size, FunctionProto func) {
Object *para = DatumGetValue<Object *>(params[1]);
if (dynamic_cast<Vector *>(para)) {
return transform_Vector<RetType, ParaType>(params, size, func);
} else {
return transform_Scalar<RetType, ParaType>(params, size, func);
}
}
} // namespace dbcommon
#endif // DBCOMMON_SRC_DBCOMMON_FUNCTION_FUNCTION_H_