You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-08-01 06:46:55 +03:00
MCOL-271 empty strings should not be NULLs (#2794)
This patch improves handling of NULLs in textual fields in ColumnStore. Previously empty strings were considered NULLs and it could be a problem if data scheme allows for empty strings. It was also one of major reasons of behavior difference between ColumnStore and other engines in MariaDB family. Also, this patch fixes some other bugs and incorrect behavior, for example, incorrect comparison for "column <= ''" which evaluates to constant True for all purposes before this patch.
This commit is contained in:
committed by
Roman Nozdrin
parent
0ea592da80
commit
b53c231ca6
@ -40,6 +40,7 @@
|
||||
#include "mcs_decimal.h"
|
||||
#include "mcs_int64.h"
|
||||
#include "numericliteral.h"
|
||||
#include "nullstring.h"
|
||||
|
||||
namespace messageqcpp
|
||||
{
|
||||
@ -145,7 +146,7 @@ struct Result
|
||||
, longDoubleVal(0)
|
||||
, floatVal(0)
|
||||
, boolVal(false)
|
||||
, strVal("")
|
||||
, strVal()
|
||||
, decimalVal(IDB_Decimal())
|
||||
, valueConverted(false)
|
||||
{
|
||||
@ -160,7 +161,7 @@ struct Result
|
||||
long double longDoubleVal;
|
||||
float floatVal;
|
||||
bool boolVal;
|
||||
std::string strVal;
|
||||
utils::NullString strVal;
|
||||
IDB_Decimal decimalVal;
|
||||
bool valueConverted;
|
||||
};
|
||||
@ -266,8 +267,9 @@ class TreeNode
|
||||
/***********************************************************************
|
||||
* F&E framework *
|
||||
***********************************************************************/
|
||||
virtual const std::string& getStrVal(rowgroup::Row& row, bool& isNull)
|
||||
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)
|
||||
@ -331,7 +333,7 @@ class TreeNode
|
||||
}
|
||||
|
||||
inline bool getBoolVal();
|
||||
inline const std::string& getStrVal(const long timeZone);
|
||||
inline const utils::NullString& getStrVal(const long timeZone);
|
||||
inline int64_t getIntVal();
|
||||
inline uint64_t getUintVal();
|
||||
inline float getFloatVal();
|
||||
@ -409,13 +411,15 @@ inline bool TreeNode::getBoolVal()
|
||||
if (fResultType.colWidth <= 8)
|
||||
return (atoi((char*)(&fResult.origIntVal)) != 0);
|
||||
|
||||
return (atoi(fResult.strVal.c_str()) != 0);
|
||||
idbassert(fResult.strVal.str());
|
||||
return (atoi(fResult.strVal.str()) != 0);
|
||||
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
if (fResultType.colWidth <= 7)
|
||||
return (atoi((char*)(&fResult.origIntVal)) != 0);
|
||||
|
||||
return (atoi(fResult.strVal.c_str()) != 0);
|
||||
idbassert(fResult.strVal.str());
|
||||
return (atoi(fResult.strVal.str()) != 0);
|
||||
|
||||
// FIXME: Huh???
|
||||
case CalpontSystemCatalog::VARBINARY:
|
||||
@ -424,7 +428,8 @@ inline bool TreeNode::getBoolVal()
|
||||
if (fResultType.colWidth <= 7)
|
||||
return (atoi((char*)(&fResult.origIntVal)) != 0);
|
||||
|
||||
return (atoi(fResult.strVal.c_str()) != 0);
|
||||
idbassert(fResult.strVal.str());
|
||||
return (atoi(fResult.strVal.str()) != 0);
|
||||
|
||||
case CalpontSystemCatalog::BIGINT:
|
||||
case CalpontSystemCatalog::SMALLINT:
|
||||
@ -463,28 +468,28 @@ inline bool TreeNode::getBoolVal()
|
||||
return fResult.boolVal;
|
||||
}
|
||||
|
||||
inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
inline const utils::NullString& TreeNode::getStrVal(const long timeZone)
|
||||
{
|
||||
switch (fResultType.colDataType)
|
||||
{
|
||||
case CalpontSystemCatalog::CHAR:
|
||||
if (fResultType.colWidth <= 8)
|
||||
fResult.strVal = (char*)(&fResult.origIntVal);
|
||||
|
||||
break;
|
||||
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
if (fResultType.colWidth <= 7)
|
||||
fResult.strVal = (char*)(&fResult.origIntVal);
|
||||
{
|
||||
const char *intAsChar = (const char*) (&fResult.origIntVal);
|
||||
fResult.strVal.assign((const uint8_t*)intAsChar, strlen(intAsChar));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// FIXME: ???
|
||||
case CalpontSystemCatalog::VARBINARY:
|
||||
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 <= 7)
|
||||
fResult.strVal = (char*)(&fResult.origIntVal);
|
||||
if (fResultType.colWidth <= 8)
|
||||
{
|
||||
const char *intAsChar = (const char*) (&fResult.origIntVal);
|
||||
fResult.strVal.assign((const uint8_t*)intAsChar, strlen(intAsChar));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@ -499,7 +504,7 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
#else
|
||||
snprintf(tmp, 20, "%ld", fResult.intVal);
|
||||
#endif
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -514,7 +519,7 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
#else
|
||||
snprintf(tmp, 20, "%lu", fResult.uintVal);
|
||||
#endif
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -524,7 +529,7 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
if ((fabs(fResult.floatVal) > (1.0 / IDB_pow[4])) && (fabs(fResult.floatVal) < (float)IDB_pow[6]))
|
||||
{
|
||||
snprintf(tmp, 312, "%f", fResult.floatVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -535,14 +540,15 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
if (std::isnan(exponent) || std::isnan(base))
|
||||
{
|
||||
snprintf(tmp, 312, "%f", fResult.floatVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(tmp, 312, "%.5f", base);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
std::string tmpCat(removeTrailing0(tmp, 312));
|
||||
snprintf(tmp, 312, "e%02d", exponent);
|
||||
fResult.strVal += tmp;
|
||||
tmpCat += tmp;
|
||||
fResult.strVal.assign(tmpCat);
|
||||
}
|
||||
|
||||
// snprintf(tmp, 312, "%e.5", fResult.floatVal);
|
||||
@ -558,7 +564,7 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
if ((fabs(fResult.doubleVal) > (1.0 / IDB_pow[13])) && (fabs(fResult.doubleVal) < (float)IDB_pow[15]))
|
||||
{
|
||||
snprintf(tmp, 312, "%f", fResult.doubleVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -569,14 +575,15 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
if (std::isnan(exponent) || std::isnan(base))
|
||||
{
|
||||
snprintf(tmp, 312, "%f", fResult.doubleVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(tmp, 312, "%.9f", base);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
std::string tmpCat(removeTrailing0(tmp, 312));
|
||||
snprintf(tmp, 312, "e%02d", exponent);
|
||||
fResult.strVal += tmp;
|
||||
tmpCat += tmp;
|
||||
fResult.strVal.assign(tmpCat);
|
||||
}
|
||||
|
||||
// snprintf(tmp, 312, "%e", fResult.doubleVal);
|
||||
@ -592,7 +599,7 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
(fabsl(fResult.longDoubleVal) < (float)IDB_pow[15]))
|
||||
{
|
||||
snprintf(tmp, 312, "%Lf", fResult.longDoubleVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -603,14 +610,15 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
if (std::isnan(exponent) || std::isnan(base))
|
||||
{
|
||||
snprintf(tmp, 312, "%Lf", fResult.longDoubleVal);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
fResult.strVal.assign(removeTrailing0(tmp, 312));
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(tmp, 312, "%.14Lf", base);
|
||||
fResult.strVal = removeTrailing0(tmp, 312);
|
||||
std::string tmpCat = removeTrailing0(tmp, 312);
|
||||
snprintf(tmp, 312, "e%02d", exponent);
|
||||
fResult.strVal += tmp;
|
||||
tmpCat += tmp;
|
||||
fResult.strVal.assign(tmpCat);
|
||||
}
|
||||
|
||||
// snprintf(tmp, 312, "%e", fResult.doubleVal);
|
||||
@ -624,38 +632,42 @@ inline const std::string& TreeNode::getStrVal(const long timeZone)
|
||||
case CalpontSystemCatalog::UDECIMAL:
|
||||
{
|
||||
if (fResultType.colWidth == datatypes::MAXDECIMALWIDTH)
|
||||
{
|
||||
// Explicit path for TSInt128 decimals with low precision
|
||||
fResult.strVal = fResult.decimalVal.toString(true);
|
||||
fResult.strVal = fResult.decimalVal.toNullString(true);
|
||||
}
|
||||
else
|
||||
fResult.strVal = fResult.decimalVal.toString();
|
||||
{
|
||||
fResult.strVal = fResult.decimalVal.toNullString(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CalpontSystemCatalog::DATE:
|
||||
{
|
||||
dataconvert::DataConvert::dateToString(fResult.intVal, tmp, 255);
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case CalpontSystemCatalog::DATETIME:
|
||||
{
|
||||
dataconvert::DataConvert::datetimeToString(fResult.intVal, tmp, 255, fResultType.precision);
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case CalpontSystemCatalog::TIMESTAMP:
|
||||
{
|
||||
dataconvert::DataConvert::timestampToString(fResult.intVal, tmp, 255, timeZone, fResultType.precision);
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
case CalpontSystemCatalog::TIME:
|
||||
{
|
||||
dataconvert::DataConvert::timeToString(fResult.intVal, tmp, 255, fResultType.precision);
|
||||
fResult.strVal = std::string(tmp);
|
||||
fResult.strVal.assign(std::string(tmp));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -676,7 +688,7 @@ inline int64_t TreeNode::getIntVal()
|
||||
return fResult.intVal;
|
||||
}
|
||||
datatypes::DataCondition cnverr;
|
||||
literal::Converter<literal::SignedInteger> cnv(fResult.strVal, cnverr);
|
||||
literal::Converter<literal::SignedInteger> cnv(fResult.strVal.safeString(""), cnverr);
|
||||
return cnv.toSInt<int64_t>(cnverr);
|
||||
}
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
@ -688,7 +700,7 @@ inline int64_t TreeNode::getIntVal()
|
||||
return fResult.intVal;
|
||||
|
||||
datatypes::DataCondition cnverr;
|
||||
literal::Converter<literal::SignedInteger> cnv(fResult.strVal, cnverr);
|
||||
literal::Converter<literal::SignedInteger> cnv(fResult.strVal.safeString(""), cnverr);
|
||||
return cnv.toSInt<int64_t>(cnverr);
|
||||
}
|
||||
|
||||
@ -736,10 +748,10 @@ inline uint64_t TreeNode::getUintVal()
|
||||
case CalpontSystemCatalog::TEXT:
|
||||
{
|
||||
datatypes::DataCondition cnverr;
|
||||
literal::Converter<literal::UnsignedInteger> cnv(fResult.strVal, cnverr);
|
||||
literal::Converter<literal::UnsignedInteger> cnv(fResult.strVal.safeString(""), cnverr);
|
||||
if (datatypes::DataCondition::Code(cnverr) != 0)
|
||||
{
|
||||
cerr << "error in unsigned int conversion from '" << fResult.strVal << "'";
|
||||
cerr << "error in unsigned int conversion from '" << fResult.strVal.safeString() << "'";
|
||||
}
|
||||
return cnv.toXIntPositive<uint64_t>(cnverr);
|
||||
}
|
||||
@ -784,13 +796,15 @@ inline float TreeNode::getFloatVal()
|
||||
if (fResultType.colWidth <= 8)
|
||||
return atof((char*)(&fResult.origIntVal));
|
||||
|
||||
return atof(fResult.strVal.c_str());
|
||||
idbassert(fResult.strVal.str());
|
||||
return atof(fResult.strVal.str());
|
||||
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
if (fResultType.colWidth <= 7)
|
||||
return atof((char*)(&fResult.origIntVal));
|
||||
|
||||
return atof(fResult.strVal.c_str());
|
||||
idbassert(fResult.strVal.str());
|
||||
return atof(fResult.strVal.str());
|
||||
|
||||
// FIXME: ???
|
||||
case CalpontSystemCatalog::VARBINARY:
|
||||
@ -799,7 +813,8 @@ inline float TreeNode::getFloatVal()
|
||||
if (fResultType.colWidth <= 7)
|
||||
return atof((char*)(&fResult.origIntVal));
|
||||
|
||||
return atof(fResult.strVal.c_str());
|
||||
idbassert(fResult.strVal.str());
|
||||
return atof(fResult.strVal.str());
|
||||
|
||||
case CalpontSystemCatalog::BIGINT:
|
||||
case CalpontSystemCatalog::TINYINT:
|
||||
@ -852,13 +867,15 @@ inline double TreeNode::getDoubleVal()
|
||||
if (fResultType.colWidth <= 8)
|
||||
return strtod((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtod(fResult.strVal.c_str(), NULL);
|
||||
idbassert(fResult.strVal.str());
|
||||
return strtod(fResult.strVal.str(), NULL);
|
||||
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
if (fResultType.colWidth <= 7)
|
||||
return strtod((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtod(fResult.strVal.c_str(), NULL);
|
||||
idbassert(fResult.strVal.str());
|
||||
return strtod(fResult.strVal.str(), NULL);
|
||||
|
||||
// FIXME: ???
|
||||
case CalpontSystemCatalog::VARBINARY:
|
||||
@ -867,7 +884,8 @@ inline double TreeNode::getDoubleVal()
|
||||
if (fResultType.colWidth <= 7)
|
||||
return strtod((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtod(fResult.strVal.c_str(), NULL);
|
||||
//idbassert(fResult.strVal.str());
|
||||
return strtod(fResult.strVal.safeString("").c_str(), NULL);
|
||||
|
||||
case CalpontSystemCatalog::BIGINT:
|
||||
case CalpontSystemCatalog::TINYINT:
|
||||
@ -920,13 +938,15 @@ inline long double TreeNode::getLongDoubleVal()
|
||||
if (fResultType.colWidth <= 8)
|
||||
return strtold((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtold(fResult.strVal.c_str(), NULL);
|
||||
idbassert(fResult.strVal.str());
|
||||
return strtold(fResult.strVal.str(), NULL);
|
||||
|
||||
case CalpontSystemCatalog::VARCHAR:
|
||||
if (fResultType.colWidth <= 7)
|
||||
return strtold((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtold(fResult.strVal.c_str(), NULL);
|
||||
idbassert(fResult.strVal.str());
|
||||
return strtold(fResult.strVal.str(), NULL);
|
||||
|
||||
// FIXME: ???
|
||||
case CalpontSystemCatalog::VARBINARY:
|
||||
@ -935,7 +955,8 @@ inline long double TreeNode::getLongDoubleVal()
|
||||
if (fResultType.colWidth <= 7)
|
||||
return strtold((char*)(&fResult.origIntVal), NULL);
|
||||
|
||||
return strtold(fResult.strVal.c_str(), NULL);
|
||||
idbassert(fResult.strVal.str());
|
||||
return strtold(fResult.strVal.str(), NULL);
|
||||
|
||||
case CalpontSystemCatalog::BIGINT:
|
||||
case CalpontSystemCatalog::TINYINT:
|
||||
|
Reference in New Issue
Block a user