/* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2019 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // $Id: treenode.h 9635 2013-06-19 21:42:30Z bwilkinson $ /** @file */ #pragma once #include #include #include #include #include #include #include #include #include #include "calpontsystemcatalog.h" #include "exceptclasses.h" #include "dataconvert.h" #include "columnwidth.h" #include "mcs_decimal.h" #include "mcs_int64.h" #include "numericliteral.h" #include "nullstring.h" namespace messageqcpp { class ByteStream; } namespace rowgroup { class Row; } /** * Namespace */ namespace execplan { typedef execplan::CalpontSystemCatalog::ColType Type; typedef datatypes::Decimal IDB_Decimal; using IncludeSet = std::unordered_set; /** * @brief IDB_Regex struct * */ #ifdef POSIX_REGEX typedef regex_t IDB_Regex; #else typedef std::regex IDB_Regex; #endif typedef IDB_Regex CNX_Regex; typedef boost::shared_ptr SP_IDB_Regex; typedef SP_IDB_Regex SP_CNX_Regex; /** Trim trailing 0 from val. All insignificant zeroes to the right of the * decimal point are removed. Also, the decimal point is not included on * whole numbers. It works like %g flag with printf, but always print * double value in fixed-point notation. * * @parm val valid double value in fixed-point notation from printf %f. * No format validation is perfomed in this function. * @parm length length of the buffer val */ inline std::string removeTrailing0(char* val, uint32_t length) { char* ptr = val; int64_t i = 0; bool decimal_point = false; for (; i < length; i++, ptr++) { if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { continue; } if (*ptr == '.') { decimal_point = true; continue; } *ptr = 0; break; } if (decimal_point) { for (i = i - 1; i >= 0; i--) { if (val[i] == '0') { val[i] = 0; } else if (val[i] == '.') { val[i] = 0; break; } else { break; } } } return std::string(val); } /** * @brief Result type added for F&E framework * */ struct Result { Result() : intVal(0) , uintVal(0) , origIntVal(0) , dummy(0) , doubleVal(0) , longDoubleVal(0) , floatVal(0) , boolVal(false) , strVal() , decimalVal(IDB_Decimal()) , valueConverted(false) { } int64_t intVal; uint64_t uintVal; uint64_t origIntVal; // clear up the memory following origIntVal to make sure null terminated string // when converting origIntVal uint64_t dummy; double doubleVal; long double longDoubleVal; float floatVal; bool boolVal; utils::NullString strVal; IDB_Decimal decimalVal; bool valueConverted; }; /** * @brief An abstract class to represent a node data on the expression tree * */ class TreeNode { public: TreeNode(); TreeNode(const TreeNode& rhs); virtual ~TreeNode(); virtual const std::string data() const = 0; virtual void data(const std::string data) = 0; virtual const std::string toString() const = 0; virtual TreeNode* clone() const = 0; /** * Interface for serialization */ /** @brief Convert *this to a stream of bytes * * Convert *this to a stream of bytes. * @param b The ByteStream to add *this to. */ virtual void serialize(messageqcpp::ByteStream& b) const = 0; /** @brief Construct a TreeNode from a stream of bytes * * Construct a TreeNode from a stream of bytes. * @param b The ByteStream to parse * @return The newly allocated TreeNode */ virtual void unserialize(messageqcpp::ByteStream& b) = 0; /** @brief Do a deep, strict (as opposed to semantic) equivalence test * * Do a deep, strict (as opposed to semantic) equivalence test. * @return true iff every member of t is a duplicate copy of every member of this; false otherwise */ virtual bool operator==(const TreeNode* t) const = 0; /** @brief Do a deep, strict (as opposed to semantic) equivalence test * * Do a deep, strict (as opposed to semantic) equivalence test. * @return false iff every member of t is a duplicate copy of every member of this; true otherwise */ virtual bool operator!=(const TreeNode* t) const = 0; virtual std::string toCppCode(IncludeSet& includes) const = 0; // derivedTable mutator and accessor virtual const std::string& derivedTable() const { return fDerivedTable; } virtual void derivedTable(const std::string& derivedTable) { fDerivedTable = derivedTable; } // must to be implented by treenode that could potentially belong to // one single derived table virtual void setDerivedTable() { fDerivedTable = ""; } virtual TreeNode* derivedRefCol() const { return fDerivedRefCol; } virtual void derivedRefCol(TreeNode* derivedRefCol) { fDerivedRefCol = derivedRefCol; } virtual uint64_t refCount() const { return fRefCount; } virtual void refCount(const uint64_t refCount) { fRefCount = refCount; } // the inc and dec functions areparm[n]->data() used by connector single thread. virtual void decRefCount() { fRefCount--; } virtual void incRefCount() { fRefCount++; } /*********************************************************************** * F&E framework * ***********************************************************************/ virtual const utils::NullString& getStrVal(rowgroup::Row& row, bool& isNull) { isNull = isNull || fResult.strVal .isNull(); // XXX: NullString returns isNull, we should remove that parameter altogether. return fResult.strVal; } virtual int64_t getIntVal(rowgroup::Row& row, bool& isNull) { return fResult.intVal; } virtual uint64_t getUintVal(rowgroup::Row& row, bool& isNull) { return fResult.uintVal; } datatypes::TUInt64Null toTUInt64Null(rowgroup::Row& row) { bool isNull = false; uint64_t val = getUintVal(row, isNull); return datatypes::TUInt64Null(val, isNull); } datatypes::TSInt64Null toTSInt64Null(rowgroup::Row& row) { bool isNull = false; int64_t val = getIntVal(row, isNull); return datatypes::TSInt64Null(val, isNull); } virtual float getFloatVal(rowgroup::Row& row, bool& isNull) { return fResult.floatVal; } virtual double getDoubleVal(rowgroup::Row& row, bool& isNull) { return fResult.doubleVal; } virtual long double getLongDoubleVal(rowgroup::Row& row, bool& isNull) { return fResult.longDoubleVal; } virtual IDB_Decimal getDecimalVal(rowgroup::Row& row, bool& isNull) { return fResult.decimalVal; } virtual bool getBoolVal(rowgroup::Row& row, bool& isNull) { return fResult.boolVal; } virtual int32_t getDateIntVal(rowgroup::Row& row, bool& isNull) { return fResult.intVal; } virtual int64_t getDatetimeIntVal(rowgroup::Row& row, bool& isNull) { return fResult.intVal; } virtual int64_t getTimestampIntVal(rowgroup::Row& row, bool& isNull) { return fResult.intVal; } virtual int64_t getTimeIntVal(rowgroup::Row& row, bool& isNull) { return fResult.intVal; } virtual void evaluate(rowgroup::Row& row, bool& isNull) { } inline bool getBoolVal(); inline const utils::NullString& getStrVal(const long timeZone); inline int64_t getIntVal(); inline uint64_t getUintVal(); inline float getFloatVal(); inline double getDoubleVal(); inline long double getLongDoubleVal(); inline IDB_Decimal getDecimalVal(); inline int32_t getDateIntVal(); inline int64_t getDatetimeIntVal(long timeZone = 0); inline int64_t getTimestampIntVal(); inline int64_t getTimeIntVal(); virtual const execplan::CalpontSystemCatalog::ColType& resultType() const { return fResultType; } virtual execplan::CalpontSystemCatalog::ColType& resultType() { return fResultType; } virtual void resultType(const execplan::CalpontSystemCatalog::ColType& resultType); virtual void operationType(const Type& type) { fOperationType = type; } virtual const execplan::CalpontSystemCatalog::ColType& operationType() const { return fOperationType; } // result mutator and accessor. for speical functor to set for optimization. virtual void result(const Result& result) { fResult = result; } virtual const Result& result() const { return fResult; } uint32_t charsetNumber() const { return fResultType.charsetNumber; } void charsetNumber(uint32_t cnum) { fResultType.charsetNumber = cnum; fOperationType.charsetNumber = cnum; } protected: Result fResult; execplan::CalpontSystemCatalog::ColType fResultType; // mapped from mysql data type execplan::CalpontSystemCatalog::ColType fOperationType; // operator type, could be different from the result type // double's range is +/-1.7E308 with at least 15 digits of precision char tmp[312]; // for conversion use // @bug5635 If any item involved in this filter belongs to a derived table, // the derived table alias is added to the reference vector. std::string fDerivedTable; uint64_t fRefCount; TreeNode* fDerivedRefCol; private: // default okay // TreeNode& operator=(const TreeNode& rhs); }; inline bool TreeNode::getBoolVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: if (fResultType.colWidth <= 8) return (atoi((char*)(&fResult.origIntVal)) != 0); idbassert(fResult.strVal.str()); return (atoi(fResult.strVal.str()) != 0); case CalpontSystemCatalog::VARCHAR: if (fResultType.colWidth <= 7) return (atoi((char*)(&fResult.origIntVal)) != 0); idbassert(fResult.strVal.str()); return (atoi(fResult.strVal.str()) != 0); // FIXME: Huh??? case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: if (fResultType.colWidth <= 7) return (atoi((char*)(&fResult.origIntVal)) != 0); idbassert(fResult.strVal.str()); return (atoi(fResult.strVal.str()) != 0); case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::INT: case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIMESTAMP: case CalpontSystemCatalog::TIME: return (fResult.intVal != 0); case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::UINT: return (fResult.uintVal != 0); case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return (fResult.floatVal != 0); case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return (fResult.doubleVal != 0); case CalpontSystemCatalog::LONGDOUBLE: return (fResult.longDoubleVal != 0); case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) return (fResult.decimalVal.s128Value != 0); else return (fResult.decimalVal.value != 0); default: throw logging::InvalidConversionExcept("TreeNode::getBoolVal: Invalid conversion."); } return fResult.boolVal; } inline const utils::NullString& TreeNode::getStrVal(const long timeZone) { switch (fResultType.colDataType) { case CalpontSystemCatalog::VARCHAR: if (fResultType.colWidth <= 7) { const char* intAsChar = (const char*)(&fResult.origIntVal); fResult.strVal.assign((const uint8_t*)intAsChar, strlen(intAsChar)); } break; case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARBINARY: // XXX: TODO: we don't have varbinary support now, but it may be // handled just like varchar. case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: if (fResultType.colWidth <= 8) { const char* intAsChar = (const char*)(&fResult.origIntVal); fResult.strVal.assign((const uint8_t*)intAsChar, strlen(intAsChar)); } break; case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::INT: { #ifndef __LP64__ snprintf(tmp, 20, "%lld", fResult.intVal); #else snprintf(tmp, 20, "%ld", fResult.intVal); #endif fResult.strVal.assign(std::string(tmp)); break; } case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::UINT: { #ifndef __LP64__ snprintf(tmp, 20, "%llu", fResult.uintVal); #else snprintf(tmp, 20, "%lu", fResult.uintVal); #endif fResult.strVal.assign(std::string(tmp)); break; } case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: { if ((fabs(fResult.floatVal) > (1.0 / IDB_pow[4])) && (fabs(fResult.floatVal) < (float)IDB_pow[6])) { snprintf(tmp, 312, "%f", fResult.floatVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { // MCOL-299 Print scientific with 5 mantissa and no + sign for exponent int exponent = (int)floor(log10(fabs(fResult.floatVal))); // This will round down the exponent double base = fResult.floatVal * pow(10, -1.0 * exponent); if (std::isnan(exponent) || std::isnan(base)) { snprintf(tmp, 312, "%f", fResult.floatVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { snprintf(tmp, 312, "%.5f", base); std::string tmpCat(removeTrailing0(tmp, 312)); snprintf(tmp, 312, "e%02d", exponent); tmpCat += tmp; fResult.strVal.assign(tmpCat); } // snprintf(tmp, 312, "%e.5", fResult.floatVal); // fResult.strVal = tmp; } break; } case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: { if ((fabs(fResult.doubleVal) > (1.0 / IDB_pow[13])) && (fabs(fResult.doubleVal) < (float)IDB_pow[15])) { snprintf(tmp, 312, "%f", fResult.doubleVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { // MCOL-299 Print scientific with 9 mantissa and no + sign for exponent int exponent = (int)floor(log10(fabs(fResult.doubleVal))); // This will round down the exponent double base = fResult.doubleVal * pow(10, -1.0 * exponent); if (std::isnan(exponent) || std::isnan(base)) { snprintf(tmp, 312, "%f", fResult.doubleVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { snprintf(tmp, 312, "%.9f", base); std::string tmpCat(removeTrailing0(tmp, 312)); snprintf(tmp, 312, "e%02d", exponent); tmpCat += tmp; fResult.strVal.assign(tmpCat); } // snprintf(tmp, 312, "%e", fResult.doubleVal); // fResult.strVal = tmp; } break; } case CalpontSystemCatalog::LONGDOUBLE: { if ((fabsl(fResult.longDoubleVal) > (1.0 / IDB_pow[13])) && (fabsl(fResult.longDoubleVal) < (float)IDB_pow[15])) { snprintf(tmp, 312, "%Lf", fResult.longDoubleVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { // MCOL-299 Print scientific with 9 mantissa and no + sign for exponent int exponent = (int)floorl(log10(fabsl(fResult.longDoubleVal))); // This will round down the exponent long double base = fResult.longDoubleVal * pow(10, -1.0 * exponent); if (std::isnan(exponent) || std::isnan(base)) { snprintf(tmp, 312, "%Lf", fResult.longDoubleVal); fResult.strVal.assign(removeTrailing0(tmp, 312)); } else { snprintf(tmp, 312, "%.14Lf", base); std::string tmpCat = removeTrailing0(tmp, 312); snprintf(tmp, 312, "e%02d", exponent); tmpCat += tmp; fResult.strVal.assign(tmpCat); } // snprintf(tmp, 312, "%e", fResult.doubleVal); // fResult.strVal = tmp; } break; } case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) { // Explicit path for TSInt128 decimals with low precision fResult.strVal = fResult.decimalVal.toNullString(true); } else { fResult.strVal = fResult.decimalVal.toNullString(false); } break; } case CalpontSystemCatalog::DATE: { dataconvert::DataConvert::dateToString(fResult.intVal, tmp, 255); fResult.strVal.assign(std::string(tmp)); break; } case CalpontSystemCatalog::DATETIME: { dataconvert::DataConvert::datetimeToString(fResult.intVal, tmp, 255, fResultType.precision); fResult.strVal.assign(std::string(tmp)); break; } case CalpontSystemCatalog::TIMESTAMP: { dataconvert::DataConvert::timestampToString(fResult.intVal, tmp, 255, timeZone, fResultType.precision); fResult.strVal.assign(std::string(tmp)); break; } case CalpontSystemCatalog::TIME: { dataconvert::DataConvert::timeToString(fResult.intVal, tmp, 255, fResultType.precision); fResult.strVal.assign(std::string(tmp)); break; } default: throw logging::InvalidConversionExcept("TreeNode::getStrVal: Invalid conversion."); } return fResult.strVal; } inline int64_t TreeNode::getIntVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: { if (fResultType.colWidth <= 8) { return fResult.intVal; } datatypes::DataCondition cnverr; literal::Converter cnv(fResult.strVal.safeString(""), cnverr); return cnv.toSInt(cnverr); } case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: { if (fResultType.colWidth <= 7) return fResult.intVal; datatypes::DataCondition cnverr; literal::Converter cnv(fResult.strVal.safeString(""), cnverr); return cnv.toSInt(cnverr); } case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: return fResult.intVal; case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: return fResult.uintVal; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return (int64_t)fResult.floatVal; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return (int64_t)fResult.doubleVal; case CalpontSystemCatalog::LONGDOUBLE: return (int64_t)fResult.longDoubleVal; case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: return fResult.decimalVal.toSInt64Round(); case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIMESTAMP: case CalpontSystemCatalog::TIME: return fResult.intVal; default: throw logging::InvalidConversionExcept("TreeNode::getIntVal: Invalid conversion."); } return fResult.intVal; } inline uint64_t TreeNode::getUintVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: { datatypes::DataCondition cnverr; literal::Converter cnv(fResult.strVal.safeString(""), cnverr); if (datatypes::DataCondition::Code(cnverr) != 0) { cerr << "error in unsigned int conversion from '" << fResult.strVal.safeString() << "'"; } return cnv.toXIntPositive(cnverr); } case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: return fResult.intVal; case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: return fResult.uintVal; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return (uint64_t)fResult.floatVal; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return (uint64_t)fResult.doubleVal; case CalpontSystemCatalog::LONGDOUBLE: return (uint64_t)fResult.longDoubleVal; case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: return fResult.decimalVal.toUInt64Round(); case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIMESTAMP: case CalpontSystemCatalog::TIME: return fResult.intVal; default: throw logging::InvalidConversionExcept("TreeNode::getIntVal: Invalid conversion."); } return fResult.intVal; } inline float TreeNode::getFloatVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: if (fResultType.colWidth <= 8) return atof((char*)(&fResult.origIntVal)); idbassert(fResult.strVal.str()); return atof(fResult.strVal.str()); case CalpontSystemCatalog::VARCHAR: if (fResultType.colWidth <= 7) return atof((char*)(&fResult.origIntVal)); idbassert(fResult.strVal.str()); return atof(fResult.strVal.str()); // FIXME: ??? case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: if (fResultType.colWidth <= 7) return atof((char*)(&fResult.origIntVal)); idbassert(fResult.strVal.str()); return atof(fResult.strVal.str()); case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: return (float)fResult.intVal; case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: return (float)fResult.uintVal; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return fResult.floatVal; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return (float)fResult.doubleVal; case CalpontSystemCatalog::LONGDOUBLE: return (float)fResult.doubleVal; case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) { return static_cast(fResult.decimalVal); } else { return (float)fResult.decimalVal.decimal64ToXFloat(); } } case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIMESTAMP: case CalpontSystemCatalog::TIME: return (float)fResult.intVal; default: throw logging::InvalidConversionExcept("TreeNode::getFloatVal: Invalid conversion."); } return fResult.floatVal; } inline double TreeNode::getDoubleVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: if (fResultType.colWidth <= 8) return strtod((char*)(&fResult.origIntVal), nullptr); idbassert(fResult.strVal.str()); return strtod(fResult.strVal.str(), nullptr); case CalpontSystemCatalog::VARCHAR: if (fResultType.colWidth <= 7) return strtod((char*)(&fResult.origIntVal), nullptr); idbassert(fResult.strVal.str()); return strtod(fResult.strVal.str(), nullptr); // FIXME: ??? case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: if (fResultType.colWidth <= 7) return strtod((char*)(&fResult.origIntVal), nullptr); // idbassert(fResult.strVal.str()); return strtod(fResult.strVal.safeString("").c_str(), nullptr); case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: return (double)fResult.intVal; case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: return (double)fResult.uintVal; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return (double)fResult.floatVal; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return fResult.doubleVal; case CalpontSystemCatalog::LONGDOUBLE: return (double)fResult.longDoubleVal; case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) { return static_cast(fResult.decimalVal); } else { return fResult.decimalVal.decimal64ToXFloat(); } } case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIMESTAMP: case CalpontSystemCatalog::TIME: return (double)fResult.intVal; default: throw logging::InvalidConversionExcept("TreeNode::getDoubleVal: Invalid conversion."); } return fResult.doubleVal; } inline long double TreeNode::getLongDoubleVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: if (fResultType.colWidth <= 8) return strtold((char*)(&fResult.origIntVal), nullptr); idbassert(fResult.strVal.str()); return strtold(fResult.strVal.str(), nullptr); case CalpontSystemCatalog::VARCHAR: if (fResultType.colWidth <= 7) return strtold((char*)(&fResult.origIntVal), nullptr); idbassert(fResult.strVal.str()); return strtold(fResult.strVal.str(), nullptr); // FIXME: ??? case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: case CalpontSystemCatalog::TEXT: if (fResultType.colWidth <= 7) return strtold((char*)(&fResult.origIntVal), nullptr); idbassert(fResult.strVal.str()); return strtold(fResult.strVal.str(), nullptr); case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::TINYINT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: return (long double)fResult.intVal; case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UTINYINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: return (long double)fResult.uintVal; case CalpontSystemCatalog::FLOAT: case CalpontSystemCatalog::UFLOAT: return (long double)fResult.floatVal; case CalpontSystemCatalog::DOUBLE: case CalpontSystemCatalog::UDOUBLE: return (long double)fResult.doubleVal; case CalpontSystemCatalog::LONGDOUBLE: return (long double)fResult.longDoubleVal; case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: { if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH) { return static_cast(fResult.decimalVal); } else { return fResult.decimalVal.decimal64ToXFloat(); } } case CalpontSystemCatalog::DATE: case CalpontSystemCatalog::DATETIME: case CalpontSystemCatalog::TIME: return (long double)fResult.intVal; default: throw logging::InvalidConversionExcept("TreeNode::getDoubleVal: Invalid conversion."); } return fResult.doubleVal; } inline IDB_Decimal TreeNode::getDecimalVal() { switch (fResultType.colDataType) { case CalpontSystemCatalog::CHAR: case CalpontSystemCatalog::VARCHAR: case CalpontSystemCatalog::TEXT: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: non-support conversion from string"); case CalpontSystemCatalog::VARBINARY: case CalpontSystemCatalog::BLOB: throw logging::InvalidConversionExcept( "TreeNode::getDecimalVal: non-support conversion from binary string"); case CalpontSystemCatalog::BIGINT: case CalpontSystemCatalog::MEDINT: case CalpontSystemCatalog::INT: case CalpontSystemCatalog::SMALLINT: case CalpontSystemCatalog::TINYINT: { idbassert(fResultType.scale == 0); fResult.decimalVal = IDB_Decimal(fResult.intVal, 0, fResultType.precision, fResult.intVal); break; } case CalpontSystemCatalog::UBIGINT: case CalpontSystemCatalog::UMEDINT: case CalpontSystemCatalog::UINT: case CalpontSystemCatalog::USMALLINT: case CalpontSystemCatalog::UTINYINT: { idbassert(fResultType.scale == 0); fResult.decimalVal = IDB_Decimal((int64_t)fResult.uintVal, 0, fResultType.precision, fResult.uintVal); break; } case CalpontSystemCatalog::LONGDOUBLE: { long double dlScaled = fResult.longDoubleVal; if (fResultType.scale > 0) { dlScaled = fResult.longDoubleVal * pow((double)10.0, fResultType.scale); } if ((dlScaled > (long double)INT64_MAX) || (dlScaled < (long double)(INT64_MIN))) { datatypes::TFloat128 temp((float128_t)dlScaled); fResult.decimalVal = IDB_Decimal(0, fResultType.scale, fResultType.precision, static_cast(temp)); } else { int64_t val = (int64_t)lroundl(dlScaled); fResult.decimalVal = IDB_Decimal(val, fResultType.scale, fResultType.precision, val); } break; } case CalpontSystemCatalog::DATE: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion from date."); case CalpontSystemCatalog::DATETIME: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion from datetime."); case CalpontSystemCatalog::TIMESTAMP: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion from timestamp."); case CalpontSystemCatalog::TIME: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion from time."); case CalpontSystemCatalog::FLOAT: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: non-support conversion from float"); case CalpontSystemCatalog::UFLOAT: throw logging::InvalidConversionExcept( "TreeNode::getDecimalVal: non-support conversion from float unsigned"); case CalpontSystemCatalog::DOUBLE: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: non-support conversion from double"); case CalpontSystemCatalog::UDOUBLE: throw logging::InvalidConversionExcept( "TreeNode::getDecimalVal: non-support conversion from double unsigned"); case CalpontSystemCatalog::DECIMAL: case CalpontSystemCatalog::UDECIMAL: return fResult.decimalVal; default: throw logging::InvalidConversionExcept("TreeNode::getDecimalVal: Invalid conversion."); } return fResult.decimalVal; } inline int64_t TreeNode::getDatetimeIntVal(long timeZone) { if (fResultType.colDataType == execplan::CalpontSystemCatalog::DATE) return (fResult.intVal & 0x00000000FFFFFFC0LL) << 32; else if (fResultType.colDataType == execplan::CalpontSystemCatalog::TIME) { dataconvert::Time tt; int day = 0; void* ttp = static_cast(&tt); memcpy(ttp, &fResult.intVal, 8); // Note, this should probably be current date +/- time if ((tt.hour > 23) && (!tt.is_neg)) { day = tt.hour / 24; tt.hour = tt.hour % 24; } else if ((tt.hour < 0) || (tt.is_neg)) { tt.hour = 0; } dataconvert::DateTime dt(0, 0, day, tt.hour, tt.minute, tt.second, tt.msecond); memcpy(&fResult.intVal, &dt, 8); return fResult.intVal; } else if (fResultType.colDataType == execplan::CalpontSystemCatalog::DATETIME) // return (fResult.intVal & 0xFFFFFFFFFFF00000LL); return (fResult.intVal); else if (fResultType.colDataType == execplan::CalpontSystemCatalog::TIMESTAMP) { dataconvert::TimeStamp timestamp(fResult.intVal); int64_t seconds = timestamp.second; dataconvert::MySQLTime m_time; dataconvert::gmtSecToMySQLTime(seconds, m_time, timeZone); dataconvert::DateTime dt(m_time.year, m_time.month, m_time.day, m_time.hour, m_time.minute, m_time.second, timestamp.msecond); memcpy(&fResult.intVal, &dt, 8); return fResult.intVal; } else return getIntVal(); } inline int64_t TreeNode::getTimestampIntVal() { if (fResultType.colDataType == execplan::CalpontSystemCatalog::TIMESTAMP) return fResult.intVal; else return getIntVal(); } inline int64_t TreeNode::getTimeIntVal() { if (fResultType.colDataType == execplan::CalpontSystemCatalog::DATETIME) { dataconvert::DateTime dt; memcpy((int64_t*)(&dt), &fResult.intVal, 8); dataconvert::Time tt(0, dt.hour, dt.minute, dt.second, dt.msecond, false); memcpy(&fResult.intVal, &tt, 8); return fResult.intVal; } else if (fResultType.colDataType == execplan::CalpontSystemCatalog::TIME) return (fResult.intVal); else return getIntVal(); } inline int32_t TreeNode::getDateIntVal() { if (fResultType.colDataType == execplan::CalpontSystemCatalog::DATETIME) return (((int32_t)(fResult.intVal >> 32) & 0xFFFFFFC0) | 0x3E); else if (fResultType.colDataType == execplan::CalpontSystemCatalog::DATE) return ((fResult.intVal & 0xFFFFFFC0) | 0x3E); else return getIntVal(); } typedef boost::shared_ptr STNP; /** * Operations */ std::ostream& operator<<(std::ostream& output, const TreeNode& rhs); } // namespace execplan