blob: 43ef097871755c71e9a35e87cc09894610db3543 [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 <cmath>
#include <tuple>
#include <fstream>
//#include <boost/lexical_cast.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include "dbcommon/common/vector-transformer.h"
#include "dbcommon/common/vector.h"
#include "dbcommon/common/vector/decimal-vector.h"
#include "dbcommon/common/vector/fixed-length-vector.h"
#include "dbcommon/common/vector/timestamp-vector.h"
#include "dbcommon/function/decimal-function.h"
#include "dbcommon/function/function.h"
#include "dbcommon/function/typecast-func.cg.h"
#include "dbcommon/type/decimal.h"
#include "dbcommon/type/type-util.h"
#include "dbcommon/utils/macro.h"
// clang-format off
// [[[cog
#if false
from cog import out, outl
import sys, os
python_path = os.path.dirname(cog.inFile) + "/../python"
python_path = os.path.abspath(python_path)
sys.path.append(python_path)
from code_generator import *
cog.outl("""
/*
* DO NOT EDIT!"
* This file is generated from : %s
*/
""" % cog.inFile)
#endif
// ]]]
// [[[end]]]
// clang-format on
namespace dbcommon {
class TypeCast {
public:
template <typename TP, typename TR>
static Datum castType(Datum *params, uint64_t size, bool isExplicit = false);
template <typename TP, typename TR, bool isExplicit = false>
static Datum castTypeToInteger(Datum *params, uint64_t size);
template <typename TR>
static Datum castDecimalToFloatType(Datum *params, uint64_t size);
template <typename TP>
static Datum castFloatTypeToDecimal(Datum *params, uint64_t size);
private:
template <typename TP, typename TR>
static Datum valCastType(TP a, bool isExplicit);
template <typename TP, typename TR>
static Datum vecCastType(Vector *rvec, const Vector *vec, bool isExplicit);
template <typename TR>
static Datum valCastDecimalToIntegerType(DecimalVar *param);
template <typename TR>
static Datum vecCastDecimalToIntegerType(Vector *rvec, Vector *vec);
template <typename TR>
static Datum valCastDecimalToFloatType(DecimalVar *param);
template <typename TR>
static Datum vecCastDecimalToFloatType(Vector *rvec, Vector *vec);
template <typename TP>
static Datum vecCastFloatTypeToDecimal(Vector *rvec, Vector *vec);
};
// function for operator cast type
template <typename TP, typename TR>
Datum TypeCast::castType(Datum *params, uint64_t size, bool isExplicit) {
assert(size == 2 && "invalid input");
Object *para = DatumGetValue<Object *>(params[1]);
Vector *vec = dynamic_cast<Vector *>(para);
if (!vec) {
auto rval = DatumGetValue<Scalar *>(params[0]);
TP val = DatumGetValue<TP>(DatumGetValue<Scalar *>(params[1])->value);
rval->value = valCastType<TP, TR>(val, isExplicit);
return CreateDatum(rval);
} else {
auto *rvec = DatumGetValue<Vector *>(params[0]);
return vecCastType<TP, TR>(rvec, vec, isExplicit);
}
}
template <typename TP, typename TR>
bool isOverflow(TP val) {
if (val > std::numeric_limits<TR>::max() ||
val < std::numeric_limits<TR>::min()) {
return true;
}
return false;
}
template <typename TP, typename TR, bool isExplicit>
Datum TypeCast::castTypeToInteger(Datum *params, uint64_t size) {
assert(size == 2 && "invalid input");
Object *para = params[1];
if (!dynamic_cast<Vector *>(para)) {
Scalar *retScalar = params[0];
Scalar *srcScalar = params[1];
if (srcScalar->isnull) {
retScalar->isnull = true;
} else {
TP src = srcScalar->value;
if (isExplicit) {
if (isOverflow<TP, TR>(src)) {
LOG_ERROR(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, "%s out of range",
TypeUtil::instance()
->getTypeEntryById(TypeMapping<TR>::type)
->name.c_str());
}
}
retScalar->isnull = false;
retScalar->value = CreateDatum(static_cast<TR>(rint(src)));
}
} else {
Vector *retVector = params[0];
Vector *srcVector = params[1];
FixedSizeTypeVectorRawData<TP> src(srcVector);
retVector->resize(src.plainSize, src.sel, src.nulls);
FixedSizeTypeVectorRawData<TR> ret(retVector);
if (isExplicit) {
bool castError = false;
auto checkOverflow = [&](uint64_t plainIdx) {
castError |= isOverflow<TP, TR>(src.values[plainIdx]);
};
dbcommon::transformVector(ret.plainSize, ret.sel, ret.nulls,
checkOverflow);
if (castError)
LOG_ERROR(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, "%s out of range",
TypeUtil::instance()
->getTypeEntryById(retVector->getTypeKind())
->name.c_str());
}
auto castToInteger = [&](uint64_t plainIdx) {
ret.values[plainIdx] = static_cast<TR>(rint(src.values[plainIdx]));
};
dbcommon::transformVector(ret.plainSize, ret.sel, ret.nulls, castToInteger);
}
return params[0];
}
template <typename TP, typename TR>
Datum TypeCast::valCastType(TP val, bool isExplicit) {
if (isExplicit) {
if (!isOverflow<TP, TR>(val)) {
TR res = static_cast<TR>(val);
return CreateDatum(res);
} else {
LOG_ERROR(ERRCODE_INTERNAL_ERROR, "typecast value out of range!");
}
} else {
return CreateDatum(static_cast<TR>(val));
}
}
template <typename TP, typename TR>
Datum TypeCast::vecCastType(Vector *rvec, const Vector *vec, bool isExplicit) {
const TP *v = reinterpret_cast<const TP *>(vec->getValue());
auto sel = vec->getSelected();
bool hasNull = vec->hasNullValue();
rvec->setHasNull(hasNull);
uint64_t sz = vec->getNumOfRows();
const uint64_t plainSize = vec->getNumOfRowsPlain();
dbcommon::ByteBuffer &rDataBuf = *rvec->getValueBuffer();
rDataBuf.resize(plainSize * sizeof(TR));
TR *__restrict__ rdata = reinterpret_cast<TR *>(rDataBuf.data());
char *__restrict__ rnull;
if (hasNull) {
dbcommon::BoolBuffer &rNullBuf = *rvec->getNullBuffer();
rNullBuf.resize(plainSize);
rnull = rNullBuf.getChars();
}
if (sel) {
rvec->setSelected(sel, true);
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
if (isExplicit) {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
if (!isOverflow<TP, TR>(v[index])) {
rdata[index] = static_cast<TR>(v[index]);
rnull[index] = nulls[index];
} else {
LOG_ERROR(ERRCODE_INTERNAL_ERROR, "typecast value out of range!");
}
}
} else {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
rdata[index] = static_cast<TR>(v[index]);
rnull[index] = nulls[index];
}
}
} else {
if (isExplicit) {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
if (!isOverflow<TP, TR>(v[index])) {
rdata[index] = static_cast<TR>(v[index]);
} else {
LOG_ERROR(ERRCODE_INTERNAL_ERROR, "typecast value out of range!");
}
}
} else {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
rdata[index] = static_cast<TR>(v[index]);
}
}
}
} else {
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
if (isExplicit) {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
if (!isOverflow<TP, TR>(v[i])) {
rdata[i] = static_cast<TR>(v[i]);
rnull[i] = nulls[i];
} else {
LOG_ERROR(ERRCODE_INTERNAL_ERROR, "typecast value out of range!");
}
}
} else {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
rdata[i] = static_cast<TR>(v[i]);
rnull[i] = nulls[i];
}
}
} else {
if (isExplicit) {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
if (!isOverflow<TP, TR>(v[i])) {
rdata[i] = static_cast<TR>(v[i]);
} else {
LOG_ERROR(ERRCODE_INTERNAL_ERROR, "typecast value out of range!");
}
}
} else {
#pragma clang loop unroll(full)
for (uint64_t i = 0; i < sz; ++i) {
rdata[i] = static_cast<TR>(v[i]);
}
}
}
}
return CreateDatum(rvec);
}
template <typename TR>
Datum TypeCast::castDecimalToFloatType(Datum *params, uint64_t size) {
assert(size == 2 && "invalid input");
Object *para = DatumGetValue<Object *>(params[1]);
Vector *vec = dynamic_cast<Vector *>(para);
if (!vec) {
Scalar *ret = params[0];
Scalar *scalar = params[1];
ret->isnull = scalar->isnull;
if (!scalar->isnull) {
DecimalVar *val = DatumGetValue<DecimalVar *>(scalar->value);
ret->value = valCastDecimalToFloatType<TR>(val);
}
return CreateDatum(ret);
} else {
auto *rvec = DatumGetValue<Vector *>(params[0]);
return vecCastDecimalToFloatType<TR>(rvec, vec);
}
}
template <typename TP>
inline DecimalVar floatToDecimal(TP in) {
int64_t scale = 0;
while (true) {
if (scale >= 13) {
break;
}
if (abs(in - static_cast<int64_t>(in)) > 1e-8) {
in *= 10.0;
++scale;
} else {
break;
}
}
Int128 int128 = static_cast<int64_t>(in);
return DecimalVar(int128.getHighBits(), int128.getLowBits(), scale);
}
template <typename TP>
Datum TypeCast::castFloatTypeToDecimal(Datum *params, uint64_t size) {
assert(size == 2 && "invalid input");
Object *para = DatumGetValue<Object *>(params[1]);
Vector *vec = dynamic_cast<Vector *>(para);
if (!vec) {
Scalar *retScalar = params[0];
Scalar *srcScalar = params[1];
if (srcScalar->isnull) {
retScalar->isnull = true;
} else {
retScalar->isnull = false;
DecimalVar *ret = retScalar->allocateValue<DecimalVar>();
TP val = DatumGetValue<TP>(srcScalar->value);
*ret = floatToDecimal(val);
}
return CreateDatum(retScalar);
} else {
auto *rvec = DatumGetValue<Vector *>(params[0]);
return vecCastFloatTypeToDecimal<TP>(rvec, vec);
}
}
template <typename TR>
bool isDecimalOverflow(std::string val) {
boost::multiprecision::cpp_int mval(val);
if (mval > std::numeric_limits<TR>::max() ||
mval < std::numeric_limits<TR>::min()) {
return true;
}
return false;
}
template <int64_t n>
constexpr uint64_t res2() {
return 2 * res2<n - 1>();
}
template <>
constexpr uint64_t res2<1>() {
return 2;
}
template <typename TR>
inline TR decimalToFloat(int64_t highbits, uint64_t lowbits, int64_t scale) {
TR exp[] = {
1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0,
10000000000000000.0,
100000000000000000.0,
1000000000000000000.0,
10000000000000000000.0,
100000000000000000000.0,
};
Int128 int128(highbits, lowbits);
int128.abs();
TR fval =
static_cast<TR>(int128.getHighBits()) * static_cast<TR>(res2<64>()) +
static_cast<TR>(int128.getLowBits());
if (scale <= 20)
fval /= exp[scale];
else
for (int32_t i = 0; i < scale; ++i) fval /= 10.0;
return highbits < 0 ? -fval : fval;
}
template <typename TR>
Datum TypeCast::valCastDecimalToFloatType(DecimalVar *param) {
return CreateDatum(static_cast<TR>(
decimalToFloat<TR>(param->highbits, param->lowbits, param->scale)));
}
template <typename TR>
Datum TypeCast::vecCastDecimalToFloatType(Vector *rvec, Vector *vec) {
auto sel = vec->getSelected();
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());
bool hasNull = vec->hasNullValue();
rvec->setHasNull(hasNull);
uint64_t sz = vec->getNumOfRows();
const uint64_t plainSize = vec->getNumOfRowsPlain();
dbcommon::ByteBuffer &rDataBuf = *rvec->getValueBuffer();
rDataBuf.resize(plainSize * sizeof(TR));
TR *__restrict__ rdata = reinterpret_cast<TR *>(rDataBuf.data());
char *__restrict__ rnull;
if (hasNull) {
dbcommon::BoolBuffer *rNullBuf = rvec->getNullBuffer();
rvec->getNullBuffer()->resize(plainSize);
rnull = rNullBuf->getChars();
}
if (sel) {
rvec->setSelected(sel, true);
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
rnull[index] = nulls[index];
if (rnull[index]) {
rdata[index] = 0;
} else {
rdata[index] =
decimalToFloat<TR>(hval[index], lval[index], sval[index]);
}
}
} else {
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
rdata[index] =
decimalToFloat<TR>(hval[index], lval[index], sval[index]);
}
}
} else {
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
for (uint64_t i = 0; i < sz; ++i) {
rnull[i] = nulls[i];
if (rnull[i]) {
rdata[i] = 0;
} else {
rdata[i] = decimalToFloat<TR>(hval[i], lval[i], sval[i]);
}
}
} else {
for (uint64_t i = 0; i < sz; ++i) {
rdata[i] = decimalToFloat<TR>(hval[i], lval[i], sval[i]);
}
}
}
return CreateDatum(rvec);
}
template <typename TP>
Datum TypeCast::vecCastFloatTypeToDecimal(Vector *rvec, Vector *vec) {
const TP *v = reinterpret_cast<const TP *>(vec->getValue());
auto sel = vec->getSelected();
bool hasNull = vec->hasNullValue();
rvec->setHasNull(hasNull);
uint64_t sz = vec->getNumOfRows();
const uint64_t plainSize = vec->getNumOfRowsPlain();
DecimalVector *dvec = dynamic_cast<DecimalVector *>(rvec);
dbcommon::ByteBuffer *rLowbitDataBuf = dvec->getValueBuffer();
rLowbitDataBuf->resize(plainSize * sizeof(uint64_t));
uint64_t *rLowbit = reinterpret_cast<uint64_t *>(rLowbitDataBuf->data());
dbcommon::ByteBuffer *rHighbitDataBuf = dvec->getAuxiliaryValueBuffer();
rHighbitDataBuf->resize(plainSize * sizeof(int64_t));
int64_t *rHighbit = reinterpret_cast<int64_t *>(rHighbitDataBuf->data());
dbcommon::ByteBuffer *rScaleDataBuf = dvec->getScaleValueBuffer();
rScaleDataBuf->resize(plainSize * sizeof(int64_t));
int64_t *rScales = reinterpret_cast<int64_t *>(rScaleDataBuf->data());
char *__restrict__ rnull;
if (hasNull) {
dbcommon::BoolBuffer &rNullBuf = *rvec->getNullBuffer();
rNullBuf.resize(plainSize);
rnull = rNullBuf.getChars();
}
char buffer[DBL_DIG + 100];
if (sel) {
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
rnull[index] = nulls[index];
if (!rnull[index]) {
DecimalVar decValtmp = floatToDecimal(v[index]);
rLowbit[index] = decValtmp.lowbits;
rHighbit[index] = decValtmp.highbits;
rScales[index] = decValtmp.scale;
}
}
} else {
for (uint64_t i = 0; i < sz; ++i) {
auto index = (*sel)[i];
DecimalVar decValtmp = floatToDecimal(v[index]);
rLowbit[index] = decValtmp.lowbits;
rHighbit[index] = decValtmp.highbits;
rScales[index] = decValtmp.scale;
}
}
} else {
if (hasNull) {
const char *__restrict__ nulls = vec->getNullBuffer()->getChars();
for (uint64_t i = 0; i < sz; ++i) {
rnull[i] = nulls[i];
if (!rnull[i]) {
DecimalVar decValtmp = floatToDecimal(v[i]);
rLowbit[i] = decValtmp.lowbits;
rHighbit[i] = decValtmp.highbits;
rScales[i] = decValtmp.scale;
}
}
} else {
for (uint64_t i = 0; i < sz; ++i) {
DecimalVar decValtmp = floatToDecimal(v[i]);
rLowbit[i] = decValtmp.lowbits;
rHighbit[i] = decValtmp.highbits;
rScales[i] = decValtmp.scale;
}
}
}
if (auto sel = vec->getSelected()) {
rvec->setSelected(sel, true);
}
return CreateDatum(rvec);
}
template <typename TR>
Datum boolToInt(Datum *params, uint64_t size) {
auto cast = [](ByteBuffer &buf, bool val) -> TR {
return static_cast<TR>(val);
};
return one_param_bind<TR, bool>(params, size, cast);
}
template <typename TP>
Datum intToBool(Datum *params, uint64_t size) {
assert(size == 2);
Object *para = DatumGetValue<Object *>(params[1]);
if (dynamic_cast<Vector *>(para)) {
SelectList *retSelectlist = params[0];
Vector *srcVector = params[1];
FixedSizeTypeVectorRawData<TP> src(srcVector);
uint64_t counter = 0;
retSelectlist->setNulls(src.plainSize, src.sel, retSelectlist->getNulls(),
src.nulls);
SelectList::value_type *ret = retSelectlist->begin();
auto cast = [&](uint64_t plainIdx) {
if (src.values[plainIdx]) {
ret[counter++] = plainIdx;
}
};
dbcommon::transformVector(src.plainSize, src.sel, src.nulls, cast);
retSelectlist->resize(counter);
} else {
Scalar *retScalar = params[0];
Scalar *srcScalar = params[1];
retScalar->clear();
if (srcScalar->isnull) {
retScalar->isnull = true;
} else {
retScalar->isnull = false;
TP val = srcScalar->value;
retScalar->value = CreateDatum<bool>(val ? true : false);
}
}
return params[0];
}
Datum bool_to_int2(Datum *params, uint64_t size) {
return boolToInt<int16_t>(params, size);
}
Datum bool_to_int4(Datum *params, uint64_t size) {
return boolToInt<int32_t>(params, size);
}
Datum bool_to_int8(Datum *params, uint64_t size) {
return boolToInt<int64_t>(params, size);
}
Datum int2_to_bool(Datum *params, uint64_t size) {
return intToBool<int16_t>(params, size);
}
Datum int4_to_bool(Datum *params, uint64_t size) {
return intToBool<int32_t>(params, size);
}
Datum int8_to_bool(Datum *params, uint64_t size) {
return intToBool<int64_t>(params, size);
}
// [[[cog
#if false
def generate_typecast_with_rettype_def(optype, typemap):
typeList = sorted(typemap.keys())
for i in range(len(typeList)):
for j in xrange(len(typeList)):
if typeList[i] in DECIMAL_TYPE.keys():
rettype = typemap[typeList[j]].symbol
paramtype = typemap[typeList[i]].symbol
funcImpl = "decimal_to_%s" % (typemap[typeList[j]].name)
if typeList[j] in FLOAT_TYPES.keys():
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castDecimalToFloatType<%s>(params, size);
}
""" % (funcImpl, optype, rettype))
elif typeList[j] in DECIMAL_TYPE.keys():
rettype = typemap[typeList[j]].symbol
paramtype = typemap[typeList[i]].symbol
funcImpl = "%s_to_decimal" % (typemap[typeList[i]].name)
if typeList[i] in FLOAT_TYPES.keys():
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castFloatTypeToDecimal<%s>(params, size);
}
""" % (funcImpl, optype, paramtype))
elif i < j:
rettype = typemap[typeList[j]].symbol
paramtype = typemap[typeList[i]].symbol
funcImpl = "%s_to_%s" % (typemap[typeList[i]].name, typemap[typeList[j]].name)
if typeList[j] in INT_TYPES.keys():
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castTypeToInteger<%s, %s>(params, size);
}
""" % (funcImpl, optype, paramtype, rettype))
else:
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castType<%s, %s>(params, size);
}
""" % (funcImpl, optype, paramtype, rettype))
elif i > j:
rettype = typemap[typeList[j]].symbol
paramtype = typemap[typeList[i]].symbol
funcImpl = "%s_to_%s" % (typemap[typeList[i]].name, typemap[typeList[j]].name)
if typeList[j] in INT_TYPES.keys():
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castTypeToInteger<%s, %s, true>(params, size);
}
""" % (funcImpl, optype, paramtype, rettype))
else:
cog.outl("""
Datum %s (Datum *params, uint64_t size) {
return %s::castType<%s, %s>(params, size);
}
""" % (funcImpl, optype, paramtype, rettype))
#endif
// ]]]
// [[[end]]]
// [[[cog
#if false
cog.outl("//%s:%d" % (cog.inFile,cog.firstLineNum))
generate_typecast_with_rettype_def("TypeCast", NUMERIC_AND_DECIMAL_TYPES)
#endif
// ]]]
// [[[end]]]
Datum char_to_string(Datum *params, uint64_t size) { return params[1]; }
} // namespace dbcommon