diff --git a/dbcon/execplan/predicateoperator.h b/dbcon/execplan/predicateoperator.h index 08f0c40cf..b35680ffc 100644 --- a/dbcon/execplan/predicateoperator.h +++ b/dbcon/execplan/predicateoperator.h @@ -114,6 +114,8 @@ private: template inline bool numericCompare(result_t op1, result_t op2); inline bool strCompare(const std::string& op1, const std::string& op2); + // MCOL-1559 + inline bool strTrimCompare(const std::string& op1, const std::string& op2); }; inline bool PredicateOperator::getBoolVal(rowgroup::Row& row, bool& isNull, ReturnedColumn* lop, ReturnedColumn* rop) @@ -457,20 +459,16 @@ inline bool PredicateOperator::getBoolVal(rowgroup::Row& row, bool& isNull, Retu return !ret; } - // MCOL-1559 - std::string val1 = lop->getStrVal(row, isNull); if (isNull) return false; - std::string val2 = rop->getStrVal(row, isNull); + const std::string& val1 = lop->getStrVal(row, isNull); if (isNull) return false; - boost::trim_right_if(val1, boost::is_any_of(" ")); - boost::trim_right_if(val2, boost::is_any_of(" ")); + return strTrimCompare(val1, rop->getStrVal(row, isNull)) && !isNull; - return strCompare(val1, val2); - } + } //FIXME: ??? case execplan::CalpontSystemCatalog::VARBINARY: @@ -553,6 +551,37 @@ inline bool PredicateOperator::strCompare(const std::string& op1, const std::str } } +inline bool PredicateOperator::strTrimCompare(const std::string& op1, const std::string& op2) +{ + switch (fOp) + { + case OP_EQ: + return funcexp::utf8::idb_strtrimcoll(op1, op2) == 0; + + case OP_NE: + return funcexp::utf8::idb_strtrimcoll(op1, op2) != 0; + + case OP_GT: + return funcexp::utf8::idb_strtrimcoll(op1, op2) > 0; + + case OP_GE: + return funcexp::utf8::idb_strtrimcoll(op1, op2) >= 0; + + case OP_LT: + return funcexp::utf8::idb_strtrimcoll(op1, op2) < 0; + + case OP_LE: + return funcexp::utf8::idb_strtrimcoll(op1, op2) <= 0; + + default: + { + std::ostringstream oss; + oss << "Non support predicate operation: " << fOp; + throw logging::InvalidOperationExcept(oss.str()); + } + } +} + std::ostream& operator<<(std::ostream& os, const PredicateOperator& rhs); } diff --git a/utils/funcexp/utils_utf8.h b/utils/funcexp/utils_utf8.h index 6f5cb26a8..878f7aee7 100644 --- a/utils/funcexp/utils_utf8.h +++ b/utils/funcexp/utils_utf8.h @@ -130,6 +130,81 @@ int idb_strcoll(const char* str1, const char* str2) return strcoll(str1, str2); } +// MCOL-1559 Add a trimmed version of strcoll +// We want to compare str1 and str2 ignoring any trailing whitespace +// without making a copy of the strings (performance hit). +// I can't find any library that does this while paying attention to +// Locale. string::compare can be used to compare substrings, but +// it's a byte by byte compare. +// We find the last real character, and if a space is following, we +// temporarily replace it with a NULL, do the compare, and restore the +// original value to that spot. +// WARNING: This is not thread safe. It temporarily modifies the +// strings and assumes it is free to do so. +inline +int idb_strtrimcoll(const std::string& str1, const std::string& str2) +{ + const std::string whitespaces (" \t\f\v\n\r"); + int rtn = 0; + char orig1; + char orig2; + char* s1 = NULL; + char* s2 = NULL; + + // Set found1 to the first whitespace char in str1 + std::size_t found1 = str1.find_last_not_of(whitespaces); + if (found1 == std::string::npos) // Either the string is empty or all whitespace. + { + if (strlen(str1) > 0) // Is all whitespace + found1 = 0; // First whitespace position + } + else + { + if (strlen(str1) > found1+1) + ++found1; // move to the first whitespace position + else + found1 = std::string::npos; // No trailing whitespace + } + // Save the value at found1 and set to NULL + if (found1 != std::string::npos) + { + s1 = &const_cast(str1)[found1]; + orig1 = *s1; + *s1 = 0; + } + + // Set found2 to the first whitespace char in str2 + std::size_t found2 = str2.find_last_not_of(whitespaces); + if (found2 == std::string::npos) // Either the string is empty or all whitespace. + { + if (strlen(str2) > 0) // Is all whitespace + found2 = 0; // First whitespace position + } + else + { + if (strlen(str2) > found2+1) + ++found2; // move to the first whitespace position + else + found2 = std::string::npos; // No trailing whitespace + } + // Save the value at found2 and set to NULL + if (found2 != std::string::npos) + { + s2 = &const_cast(str2)[found2]; + orig2 = *s2; + *s2 = 0; + } + + // Compare the trimmed strings + rtn = idb_strcoll(str1.c_str(), str2.c_str()); + + // Restore the whitespace + if (s1) + *s1 = orig1; + if (s2) + *s2 = orig2; + return rtn; +} // BUG 5241 // Infinidb specific mbstowcs(). This will handle both windows and unix platforms