| /* |
| * 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/typecast-texttonum-func.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <limits> |
| #include <stack> |
| #include <string> |
| #include <typeinfo> |
| |
| #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/variable-length-vector.h" |
| #include "dbcommon/function/arithmetic-function.h" |
| #include "dbcommon/function/decimal-function.h" |
| #include "dbcommon/function/function.h" |
| #include "dbcommon/type/decimal.h" |
| #include "dbcommon/type/type-util.h" |
| #include "dbcommon/utils/macro.h" |
| #include "dbcommon/utils/string-util.h" |
| #include "dbcommon/utils/timezone-util.h" |
| |
| namespace dbcommon { |
| |
| template <typename TP> |
| Datum text_to_Float(Datum *params, uint64_t size) { |
| assert(size == 2 && "invalid input"); |
| Object *para = params[1]; |
| |
| auto sendErroLog = [](const char *&srcbufferFrontPtrtemp, |
| int64_t &strLength) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "invalid input syntax for type %s: \"%*.*s\"", pgTypeName<TP>(), |
| strLength, strLength, srcbufferFrontPtrtemp); |
| }; |
| auto textTypeTonumeric = [&sendErroLog](int64_t &strLength, |
| const char *srcbufferPtr, |
| TP &resval) { |
| const char *srcbufferBackPtrtemp = srcbufferPtr + strLength; |
| const char *srcbufferFrontPtrtemp = srcbufferPtr; |
| if ((*srcbufferPtr < '0' || *srcbufferPtr > '9') && *srcbufferPtr != '-') { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| uint64_t isNegative = (*srcbufferPtr == '-'); |
| if (isNegative) { |
| ++srcbufferPtr; |
| } |
| |
| resval = 0; |
| const char *pdot = nullptr; |
| const char *pe = nullptr; |
| for (const char *ptemp = srcbufferPtr; ptemp < srcbufferBackPtrtemp; |
| ++ptemp) { |
| if (*ptemp == '.') { |
| pdot = ptemp; |
| } |
| if (*ptemp == 'e' || *ptemp == 'E') { |
| pe = ptemp; |
| } |
| } |
| |
| if (pe == srcbufferPtr || (pe < pdot && pe && pdot) || |
| (pe && *(pe + 1) != '+' && *(pe + 1) != '-' && |
| (*(pe + 1) < '0' || *(pe + 1) > '9'))) { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| for (const char *ptemp = srcbufferPtr; ptemp < srcbufferBackPtrtemp; |
| ++ptemp) { |
| if ((*ptemp < '0' || *ptemp > '9') && ptemp != pdot && ptemp != pe && |
| ptemp != pe + 1) { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| } |
| |
| const char *ptempend = pdot ? pdot : (pe ? pe : srcbufferBackPtrtemp); |
| if (isNegative) { |
| for (const char *ptemp = srcbufferPtr; ptemp < ptempend; ++ptemp) { |
| resval = resval * 10 - (*ptemp - '0'); |
| } |
| } else { |
| for (const char *ptemp = srcbufferPtr; ptemp < ptempend; ++ptemp) { |
| resval = resval * 10 + (*ptemp - '0'); |
| } |
| } |
| |
| if (pdot) { |
| TP tempval = 0; |
| if (isNegative) { |
| for (const char *ptemp = pe ? pe - 1 : srcbufferBackPtrtemp - 1; |
| ptemp > pdot; --ptemp) { |
| tempval = tempval / 10 - ((TP)(*ptemp - '0')) / 10; |
| } |
| } else { |
| for (const char *ptemp = pe ? pe - 1 : srcbufferBackPtrtemp - 1; |
| ptemp > pdot; --ptemp) { |
| tempval = tempval / 10 + ((TP)(*ptemp - '0')) / 10; |
| } |
| } |
| resval += tempval; |
| } |
| |
| if (pe) { |
| uint64_t isExNegative = (*(++pe) == '-'); |
| if (*pe < '0' || *pe > '9') { |
| ++pe; |
| } |
| uint64_t exval = 0; |
| for (; pe < srcbufferBackPtrtemp; ++pe) { |
| exval = exval * 10 + (*pe - '0'); |
| } |
| if (!isExNegative) { |
| for (; exval > 0; --exval) { |
| resval *= 10; |
| } |
| } else { |
| for (; exval > 0; --exval) { |
| resval /= 10; |
| } |
| } |
| } |
| }; |
| |
| auto textToFloat = [&textTypeTonumeric](ByteBuffer &buf, text in) -> TP { |
| TP resval; |
| textTypeTonumeric(in.length, in.val, resval); |
| return resval; |
| }; |
| |
| return one_param_bind<TP, text>(params, size, textToFloat); |
| } |
| |
| DecimalVar stringToDecimal(const char *srcbufferPtr, int64_t strLength) { |
| auto sendErroLog = [](const char *&srcbufferFrontPtrtemp, |
| int64_t &strLength) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "invalid input syntax for type %s: \"%*.*s\"", |
| pgTypeName<DecimalVar>(), static_cast<int32_t>(strLength), |
| static_cast<int32_t>(strLength), srcbufferFrontPtrtemp); |
| }; |
| |
| const char *srcbufferBackPtrtemp = srcbufferPtr + strLength; |
| const char *srcbufferFrontPtrtemp = srcbufferPtr; |
| if ((*srcbufferPtr < '0' || *srcbufferPtr > '9') && *srcbufferPtr != '-' && |
| *srcbufferPtr != '.') { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| bool isNegative = (*srcbufferPtr == '-'); |
| if (isNegative) { |
| ++srcbufferPtr; |
| } |
| |
| const char *pdot = nullptr; |
| const char *pe = nullptr; |
| for (const char *ptemp = srcbufferPtr; ptemp < srcbufferBackPtrtemp; |
| ++ptemp) { |
| if (*ptemp == '.') { |
| pdot = ptemp; |
| } |
| if (*ptemp == 'e' || *ptemp == 'E') { |
| pe = ptemp; |
| } |
| } |
| |
| if (pe == srcbufferPtr || (pe < pdot && pe && pdot) || |
| (pe && *(pe + 1) != '+' && *(pe + 1) != '-')) { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| for (const char *ptemp = srcbufferPtr; ptemp < srcbufferBackPtrtemp; |
| ++ptemp) { |
| if ((*ptemp < '0' || *ptemp > '9') && ptemp != pdot && ptemp != pe && |
| ptemp != pe + 1) { |
| sendErroLog(srcbufferFrontPtrtemp, strLength); |
| } |
| } |
| Int128 intVal(0); |
| const char *ptempend = pdot ? pdot : (pe ? pe : srcbufferBackPtrtemp); |
| const char *ptempend1 = |
| ptempend - srcbufferPtr < 20 ? ptempend : srcbufferPtr + 19; |
| uint64_t int64val = 0; |
| for (const char *ptemp = srcbufferPtr; ptemp < ptempend1; ++ptemp) { |
| int64val = int64val * 10 + *ptemp - '0'; |
| } |
| intVal = Int128(0, int64val); |
| if (ptempend1 < ptempend) { |
| for (const char *ptemp = ptempend1; ptemp < ptempend; ++ptemp) { |
| intVal *= Int128(10); |
| intVal += Int128(*ptemp - '0'); |
| } |
| } |
| int64_t dotNum = 0; |
| if (pdot) { |
| const char *pend = pe ? pe : srcbufferBackPtrtemp; |
| if (ptempend - srcbufferPtr < 20) { |
| int64_t rest = 20 - (ptempend - srcbufferPtr); |
| const char *ptempend2 = |
| pend - (pdot + 1) < rest ? pend : pdot + 1 + rest - 1; |
| for (const char *ptemp = pdot + 1; ptemp < ptempend2; ++ptemp) { |
| int64val = int64val * 10 + *ptemp - '0'; |
| } |
| intVal = Int128(0, int64val); |
| if (ptempend2 < pend) { |
| for (const char *ptemp = ptempend2; ptemp < pend; ++ptemp) { |
| intVal *= Int128(10); |
| intVal += Int128(*ptemp - '0'); |
| } |
| } |
| } else { |
| for (const char *ptemp = pdot + 1; ptemp < pend; ++ptemp) { |
| intVal *= Int128(10); |
| intVal += Int128(*ptemp - '0'); |
| } |
| } |
| dotNum = (pend - 1) - pdot; |
| } |
| if (isNegative) { |
| intVal.negate(); |
| } |
| int64_t exval = 0; |
| if (pe) { |
| uint64_t isExNegative = *(pe + 1) == '-'; |
| for (const char *ptemp = pe + 2; ptemp < srcbufferBackPtrtemp; ++ptemp) { |
| exval = exval * 10 + (*ptemp - '0'); |
| } |
| exval = isExNegative ? -exval : exval; |
| } |
| int64_t scale = dotNum - exval; |
| DecimalVar resVal = |
| DecimalVar(intVal.getHighBits(), intVal.getLowBits(), scale); |
| return scale < 0 ? resVal.cast(0) : resVal; |
| } |
| |
| Datum textToDecimal(Datum *params, uint64_t size) { |
| assert(size == 2 && "invalid input"); |
| Object *para = params[1]; |
| |
| auto strToDecimal = [](ByteBuffer &buf, Text in) -> DecimalVar { |
| int64_t strLength = in.length; |
| const char *srcbufferPtr = in.val; |
| return stringToDecimal(srcbufferPtr, strLength); |
| }; |
| return one_param_bind<DecimalVar, Text>(params, size, strToDecimal); |
| } |
| |
| Datum toNumber(Datum *params, uint64_t size) { |
| assert(size == 3 && "invalid input"); |
| |
| auto strToDecimal = [](ByteBuffer &buf, Text inStr, |
| Text inMod) -> DecimalVar { |
| // In all cases, Text 's length is determined by its length rather than '\0'. |
| #define NEXTCHAR(ptr, end) \ |
| while (ptr < end && (++ptr) != end) { \ |
| if (*ptr != ' ') break; \ |
| } |
| #define LASTCHAR(ptr) \ |
| while (*(--ptr) == ' ') { \ |
| } |
| int64_t strLength = inStr.length; |
| const char *strFrontPtr = inStr.val; |
| const char *strBackPtr = strFrontPtr + strLength; |
| int64_t modLength = inMod.length; |
| const char *modFrontPtr = inMod.val; |
| const char *modBackPtr = modFrontPtr + modLength; |
| |
| int32_t numOfS = 0; |
| int32_t numOfMI = 0; |
| int32_t numOfDot = 0; |
| int32_t numOfPR = 0; |
| int32_t numOfPL = 0; |
| int32_t dotNeg = 0; |
| int32_t prNeg = 0; |
| int32_t precision = 0; |
| bool afterDot = false; |
| Int128 intVal = 0; |
| uint64_t int64Val = 0; |
| int64_t scale = 0; |
| int64_t num = 0; |
| const char *ptempMod = modFrontPtr; |
| const char *ptempNum = strFrontPtr; |
| while (ptempMod < modBackPtr) { |
| if (*ptempMod == 'E' || *ptempMod == 'e') { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "\"E\" is not supported for function \"to_char\""); |
| } |
| if (*ptempMod == 's' || *ptempMod == 'S') { |
| ++numOfS; |
| if (numOfS > 1) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" twice for function \"to_char\""); |
| } |
| if (numOfS + numOfMI > 1) { |
| LOG_ERROR( |
| ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" and \"MI\" together for function \"to_char\""); |
| } |
| if (numOfPL) { |
| LOG_ERROR( |
| ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" and \"PL\" together for function \"to_char\""); |
| } |
| if (numOfPR) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" and \"PR\"/\"PL\"/\"MI\"/\"SG\" together " |
| "for function \"to_char\""); |
| } |
| NEXTCHAR(ptempMod, modBackPtr); |
| continue; |
| } |
| if (*ptempMod == 'f' || *ptempMod == 'F') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr && (*ptempMod == 'm' || *ptempMod == 'M')) { |
| NEXTCHAR(ptempMod, modBackPtr); |
| continue; |
| } |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } else if (*ptempMod == 't' || *ptempMod == 'T') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr && (*ptempMod == 'h' || *ptempMod == 'H')) { |
| NEXTCHAR(ptempMod, modBackPtr); |
| continue; |
| } |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| |
| if (*ptempMod == 'm' || *ptempMod == 'M') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr) { |
| if (*ptempMod == 'i' || *ptempMod == 'I') { |
| ++numOfMI; |
| if (numOfS && numOfMI) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" and \"MI\" together for function " |
| "\"to_char\""); |
| } |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (numOfMI > 1) NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| } |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| if (*ptempMod == 'd' || *ptempMod == 'D' || *ptempMod == '.') { |
| ++numOfDot; |
| if (numOfDot > 1) { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "multiple decimal points for function \"to_char\""); |
| } |
| if (ptempNum < strBackPtr && *ptempNum != '.') { |
| std::string tmpNum; |
| for (const char *tmp = strFrontPtr; tmp < strBackPtr; ++tmp) { |
| if (*tmp == '.') break; |
| if (*tmp > '0' && *tmp < '9') tmpNum.push_back(*tmp); |
| } |
| LOG_ERROR( |
| ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "A field with precision %d, scale 0 must round to an absolute " |
| "value less than 10^%d. Rounded overflowing value: %s", |
| precision, precision, tmpNum.c_str()); |
| } else { |
| afterDot = true; |
| NEXTCHAR(ptempNum, strBackPtr); |
| NEXTCHAR(ptempMod, modBackPtr); |
| continue; |
| } |
| } |
| if (*ptempMod == 'r' || *ptempMod == 'R') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr) { |
| if (*ptempMod == 'n' || *ptempMod == 'N') { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "\"RN\" not supported with function \"to_number\""); |
| } |
| } |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| if (*ptempMod == 'p' || *ptempMod == 'P') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr) { |
| if (*ptempMod == 'l' || *ptempMod == 'L') { |
| ++numOfPL; |
| if (numOfS) |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"S\" and \"PL\" together for function " |
| "\"to_char\""); |
| NEXTCHAR(ptempMod, modBackPtr); |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| if (*ptempMod == 'r' || *ptempMod == 'R') { |
| ++numOfPR; |
| if (numOfS) |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" " |
| "together for function \"to_char\""); |
| NEXTCHAR(ptempMod, modBackPtr); |
| if (ptempMod < modBackPtr && (*ptempMod == '0' || *ptempMod == '9')) |
| LOG_ERROR( |
| ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "\"%d\" must be ahead of \"PR\" for function \"to_char\"", |
| *ptempMod - '0'); |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| } |
| NEXTCHAR(ptempMod, modBackPtr); |
| NEXTCHAR(ptempNum, strBackPtr); |
| continue; |
| } |
| |
| if (*ptempMod != '0' && *ptempMod != '9') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| NEXTCHAR(ptempNum, strBackPtr); |
| } else { |
| if (ptempNum >= strBackPtr) { |
| NEXTCHAR(ptempMod, modBackPtr); |
| continue; |
| } |
| if (*ptempNum == '.') { |
| afterDot = true; |
| for (; ptempMod < modBackPtr; ++ptempMod) { |
| if (*ptempMod == 'D' || *ptempMod == 'd' || *ptempMod == '.') { |
| NEXTCHAR(ptempMod, modBackPtr); |
| break; |
| } |
| } |
| NEXTCHAR(ptempNum, strBackPtr); |
| if (ptempNum < strBackPtr && *ptempNum == '-') dotNeg = 1; |
| } else if (*ptempNum < '0' || *ptempNum > '9') { |
| NEXTCHAR(ptempNum, strBackPtr); |
| } else { |
| if (afterDot) ++scale; |
| num++; |
| if (num < 20) { |
| int64Val = int64Val * 10 + *ptempNum - '0'; |
| intVal = Int128(0, int64Val); |
| } else { |
| intVal *= Int128(10); |
| intVal += Int128(*ptempNum - '0'); |
| } |
| if (!afterDot) ++precision; |
| NEXTCHAR(ptempNum, strBackPtr); |
| NEXTCHAR(ptempMod, modBackPtr); |
| } |
| } |
| } |
| |
| if (((dotNeg || *(strBackPtr - 1) == '-') && (numOfS || numOfMI)) || |
| *strFrontPtr == '-' || (*strFrontPtr == '<' && numOfPR)) |
| intVal.negate(); |
| return DecimalVar(intVal.getHighBits(), intVal.getLowBits(), scale); |
| }; |
| return two_params_bind<DecimalVar, Text, Text>(params, size, strToDecimal); |
| } |
| |
| template <typename TP> |
| Datum text_to_Integer(Datum *params, uint64_t size) { |
| assert(size == 2 && "invalid input"); |
| Object *para = params[1]; |
| |
| auto textTypeToNumeric = [](uint32_t &strLength, const char *srcBufferPtr, |
| TP &tempval1) { |
| const char *srcbufferBackPtrtemp = srcBufferPtr + strLength; |
| const char *srcbufferFrontPtrtemp = srcBufferPtr; |
| uint64_t isNegative = (*srcBufferPtr == '-'); |
| if (isNegative) { |
| ++srcBufferPtr; |
| } |
| for (const char *ptemp = srcBufferPtr; ptemp < srcbufferBackPtrtemp; |
| ++ptemp) { |
| if (*ptemp < '0' || *ptemp > '9') { |
| LOG_ERROR(ERRCODE_INVALID_TEXT_REPRESENTATION, |
| "invalid input syntax for integer: \"%*.*s\"", |
| isNegative ? strLength - 1 : strLength, |
| isNegative ? strLength - 1 : strLength, srcBufferPtr); |
| } |
| } |
| |
| uint64_t longVal = 0; |
| const char *ptemp = srcBufferPtr; |
| for (; ptemp < srcbufferBackPtrtemp; ++ptemp) { |
| longVal = longVal * 10 + (*ptemp - '0'); |
| } |
| |
| if ((isNegative && longVal - 1 > std::numeric_limits<TP>::max()) || |
| (!isNegative && longVal > std::numeric_limits<TP>::max())) { |
| LOG_ERROR(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, |
| "value \"%*.*s\" is out of range for type %s", strLength, |
| strLength, srcbufferFrontPtrtemp, pgTypeName<TP>()); |
| } |
| |
| tempval1 = |
| isNegative ? -static_cast<TP>(longVal) : static_cast<TP>(longVal); |
| }; |
| |
| if (dynamic_cast<Vector *>(para)) { |
| Vector *retVector = params[0]; |
| Vector *srcVector = params[1]; |
| VariableSizeTypeVectorRawData src(srcVector); |
| retVector->resize(src.plainSize, src.sel, src.nulls); |
| FixedSizeTypeVectorRawData<TP> ret(retVector); |
| auto srcBuffer = srcVector->getValueBuffer(); |
| char *srcbufferPtr = srcBuffer->data(); |
| |
| auto textToNumeric = [&](uint64_t plainIdx) { |
| uint32_t strlen = src.lengths[plainIdx]; |
| TP &tempval1 = ret.values[plainIdx]; |
| textTypeToNumeric(strlen, src.valptrs[plainIdx], tempval1); |
| }; |
| dbcommon::transformVector(ret.plainSize, ret.sel, ret.nulls, textToNumeric); |
| retVector->computeValPtrs(); |
| } else { |
| Scalar *retScalar = params[0]; |
| Scalar *srcScalar = params[1]; |
| if (srcScalar->isnull) { |
| retScalar->isnull = true; |
| } else { |
| retScalar->isnull = false; |
| char *srcbufferPtr = srcScalar->value; |
| uint32_t strlen = srcScalar->length; |
| TP val = 0; |
| textTypeToNumeric(strlen, srcbufferPtr, val); |
| retScalar->value = CreateDatum<TP>(val); |
| } |
| } |
| return params[0]; |
| } |
| |
| Datum text_to_int2(Datum *params, uint64_t size) { |
| return text_to_Integer<int16_t>(params, size); |
| } |
| Datum text_to_int4(Datum *params, uint64_t size) { |
| return text_to_Integer<int32_t>(params, size); |
| } |
| Datum text_to_int8(Datum *params, uint64_t size) { |
| return text_to_Integer<int64_t>(params, size); |
| } |
| Datum text_to_float4(Datum *params, uint64_t size) { |
| return text_to_Float<float>(params, size); |
| } |
| Datum text_to_float8(Datum *params, uint64_t size) { |
| return text_to_Float<double>(params, size); |
| } |
| |
| Datum intervalToText(Datum *params, uint64_t size) { |
| auto inttotext = [](char *&ptr, uint32_t val) { |
| if (val == 0) { |
| *(ptr++) = '0'; |
| return; |
| } |
| char str[] = "0123456789"; |
| uint32_t tempval = val; |
| std::vector<char> tempvec; |
| while (tempval >= 10) { |
| tempval /= 10; |
| ++ptr; |
| } |
| char *ptemp = ptr++; |
| while (val > 0) { |
| *(ptemp--) = str[val % 10]; |
| val /= 10; |
| } |
| }; |
| |
| auto intervalCastText = [&inttotext](ByteBuffer &buf, |
| IntervalVar in) -> text { |
| int32_t iyear, imonth, iday; |
| iyear = in.month / MONTHS_PER_YEAR; |
| imonth = in.month % MONTHS_PER_YEAR; |
| iday = in.day; |
| |
| int32_t ihour, iminute, isecond, imsecond; |
| ihour = in.timeOffset / USECS_PER_HOUR; |
| in.timeOffset -= ihour * USECS_PER_HOUR; |
| iminute = in.timeOffset / USECS_PER_MINUTE; |
| in.timeOffset -= iminute * USECS_PER_MINUTE; |
| isecond = in.timeOffset / USECS_PER_SEC; |
| imsecond = in.timeOffset - (isecond * USECS_PER_SEC); |
| |
| uint32_t lenBefore = buf.size(); |
| buf.resize(lenBefore + 128); |
| char *pStart = buf.data() + lenBefore; |
| char *ptemp = buf.data() + lenBefore; |
| bool isBeforeNeg = false; |
| bool isFirst = false; |
| if (iyear) { |
| if (iyear < 0) |
| *(ptemp++) = '-'; |
| else if (isBeforeNeg) |
| *(ptemp++) = '+'; |
| isBeforeNeg = (iyear < 0); |
| isFirst = true; |
| inttotext(ptemp, abs(iyear)); |
| *(ptemp++) = ' '; |
| memcpy(ptemp, "year", 4); |
| ptemp += 4; |
| if (iyear > 1) *(ptemp++) = 's'; |
| } |
| if (imonth) { |
| if (isFirst) *(ptemp++) = ' '; |
| isFirst = true; |
| if (imonth < 0) |
| *(ptemp++) = '-'; |
| else if (isBeforeNeg) |
| *(ptemp++) = '+'; |
| isBeforeNeg = (imonth < 0); |
| inttotext(ptemp, abs(imonth)); |
| *(ptemp++) = ' '; |
| memcpy(ptemp, "month", 5); |
| ptemp += 5; |
| if (imonth > 1) *(ptemp++) = 's'; |
| } |
| if (iday) { |
| if (isFirst) *(ptemp++) = ' '; |
| isFirst = true; |
| if (iday < 0) |
| *(ptemp++) = '-'; |
| else if (isBeforeNeg) |
| *(ptemp++) = '+'; |
| isBeforeNeg = (iday < 0); |
| inttotext(ptemp, abs(iday)); |
| *(ptemp++) = ' '; |
| memcpy(ptemp, "day", 3); |
| ptemp += 3; |
| if (abs(iday) > 1) *(ptemp++) = 's'; |
| } |
| if (ihour || iminute || isecond || imsecond) { |
| if (isFirst) *(ptemp++) = ' '; |
| isFirst = true; |
| if (ihour < 0 || iminute < 0 || isecond < 0 || imsecond < 0) |
| *(ptemp++) = '-'; |
| else if (isBeforeNeg) |
| *(ptemp++) = '+'; |
| ihour = abs(ihour); |
| iminute = abs(iminute); |
| isecond = abs(isecond); |
| imsecond = abs(imsecond); |
| if (ihour < 10) *(ptemp++) = '0'; |
| inttotext(ptemp, ihour); |
| *(ptemp++) = ':'; |
| if (iminute < 10) *(ptemp++) = '0'; |
| inttotext(ptemp, iminute); |
| *(ptemp++) = ':'; |
| if (isecond < 10) *(ptemp++) = '0'; |
| inttotext(ptemp, isecond); |
| |
| if (imsecond) { |
| int64_t power_of_ten = 100000; |
| *(ptemp++) = '.'; |
| while (imsecond / power_of_ten == 0) { |
| *(ptemp++) = '0'; |
| power_of_ten /= 10; |
| } |
| while (imsecond % 10 == 0) { |
| imsecond /= 10; |
| } |
| inttotext(ptemp, imsecond); |
| } |
| } |
| int32_t curLen = ptemp - pStart; |
| buf.resize(lenBefore + curLen); |
| |
| return text(nullptr, curLen); |
| }; |
| |
| return one_param_bind<text, IntervalVar>(params, size, intervalCastText); |
| } |
| |
| } // namespace dbcommon |