1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-30 19:23:07 +03:00

MCOL-4044: Add oracle mode functions.

This commit is contained in:
benthompson15
2021-04-21 16:07:42 -05:00
parent 1f46baa980
commit 870d672efb
20 changed files with 2624 additions and 0 deletions

View File

@ -3,6 +3,7 @@ include_directories( ${ENGINE_COMMON_INCLUDES} )
########### next target ###############
# func_decode_oracle.cpp
set(funcexp_LIB_SRCS
functor.cpp
@ -20,6 +21,7 @@ set(funcexp_LIB_SRCS
func_char_length.cpp
func_coalesce.cpp
func_concat.cpp
func_concat_oracle.cpp
func_concat_ws.cpp
func_conv.cpp
func_crc32.cpp
@ -31,6 +33,7 @@ set(funcexp_LIB_SRCS
func_dayofweek.cpp
func_dayofyear.cpp
func_decode.cpp
func_decode_oracle.cpp
func_div.cpp
func_elt.cpp
func_encode.cpp
@ -60,6 +63,7 @@ set(funcexp_LIB_SRCS
func_length.cpp
func_lpad.cpp
func_ltrim.cpp
func_ltrim_oracle.cpp
func_makedate.cpp
func_maketime.cpp
func_math.cpp
@ -79,11 +83,13 @@ set(funcexp_LIB_SRCS
func_regexp.cpp
func_repeat.cpp
func_replace.cpp
func_replace_oracle.cpp
func_reverse.cpp
func_right.cpp
func_round.cpp
func_rpad.cpp
func_rtrim.cpp
func_rtrim_oracle.cpp
func_second.cpp
func_sec_to_time.cpp
func_sha.cpp
@ -101,6 +107,7 @@ set(funcexp_LIB_SRCS
func_timestampdiff.cpp
func_to_days.cpp
func_trim.cpp
func_trim_oracle.cpp
func_truncate.cpp
func_ucase.cpp
func_unhex.cpp

View File

@ -0,0 +1,78 @@
/* Copyright (C) 2021 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. */
#include <string>
using namespace std;
#include "functor_str.h"
#include "functioncolumn.h"
#include "utils_utf8.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "dataconvert.h"
using namespace dataconvert;
namespace funcexp
{
CalpontSystemCatalog::ColType Func_concat_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType )
{
// operation type is not used by this functor
return fp[0]->data()->resultType();
}
// Returns the string that results from concatenating the arguments.
// concat_oracle() returns NULL all arguments are NULL.
// single arguments null is replaced by "".
//
string Func_concat_oracle::getStrVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType&)
{
string ret;
string tmp;
stringValue(parm[0], row, isNull, ret);
// Oracle Mode should replace NULL with "" unless all values are NULL
if (isNull)
{
ret = "";
isNull = false;
}
// TODO: do a better job of cutting down the number re-allocations.
// look at Item_func_concat::realloc_result for ideas and use
// std::string:resize() appropriatly.
for ( unsigned int id = 1 ; id < parm.size() ; id++)
{
stringValue(parm[id], row, isNull, tmp);
if (isNull)
{
tmp = "";
isNull = false;
}
ret.append(tmp);
}
return ret;
}
} // namespace funcexp
// vim:ts=4 sw=4:

View File

@ -1,3 +1,20 @@
/* Copyright (C) 2021 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. */
#include <cstdlib>
#include <string>
using namespace std;

View File

@ -0,0 +1,585 @@
/* Copyright (C) 2021 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. */
#include <string>
//#define NDEBUG
#include <cassert>
using namespace std;
#include "functor_all.h"
#include "functioncolumn.h"
#include "predicateoperator.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "errorcodes.h"
#include "idberrorinfo.h"
#include "errorids.h"
using namespace logging;
#include "utils_utf8.h"
using namespace funcexp;
#include "collation.h"
namespace
{
using namespace funcexp;
inline uint64_t simple_case_cmp(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = 0; // index to the parm list
uint64_t n = 0; // remove expression from count of expression_i + result_i
uint64_t hasElse = (parm.size() - 1) % 2; // if 1, then ELSE exist
uint64_t whereCount = hasElse ? (parm.size() - 2) / 2 : (parm.size() - 1) / 2;
bool foundIt = false;
switch (operationColType.colDataType)
{
case execplan::CalpontSystemCatalog::TINYINT:
case execplan::CalpontSystemCatalog::SMALLINT:
case execplan::CalpontSystemCatalog::MEDINT:
case execplan::CalpontSystemCatalog::INT:
case execplan::CalpontSystemCatalog::BIGINT:
case execplan::CalpontSystemCatalog::DATE:
{
int64_t ev = parm[n]->data()->getIntVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getIntVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::DATETIME:
{
int64_t ev = parm[n]->data()->getDatetimeIntVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getDatetimeIntVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::TIMESTAMP:
{
int64_t ev = parm[n]->data()->getTimestampIntVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getTimestampIntVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::TIME:
{
int64_t ev = parm[n]->data()->getTimeIntVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getTimeIntVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::UBIGINT:
case execplan::CalpontSystemCatalog::UINT:
case execplan::CalpontSystemCatalog::UMEDINT:
case execplan::CalpontSystemCatalog::UTINYINT:
case execplan::CalpontSystemCatalog::USMALLINT:
{
uint64_t ev = parm[n]->data()->getUintVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getUintVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::CHAR:
case execplan::CalpontSystemCatalog::TEXT:
case execplan::CalpontSystemCatalog::VARCHAR:
{
const string& ev = parm[n]->data()->getStrVal(row, isNull);
if (isNull)
break;
CHARSET_INFO* cs = parm[n]->data()->resultType().getCharset();
for (i = 1; i <= whereCount; i++)
{
//BUG 5362
const string& p1 = parm[i]->data()->getStrVal(row, isNull);
if (isNull)
break;
if (cs->strnncoll(ev.c_str(), ev.length(), p1.c_str(), p1.length()) == 0)
{
foundIt = true;
break;
}
}
break;
}
case execplan::CalpontSystemCatalog::DECIMAL:
case execplan::CalpontSystemCatalog::UDECIMAL:
{
IDB_Decimal ev = parm[n]->data()->getDecimalVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getDecimalVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::DOUBLE:
case execplan::CalpontSystemCatalog::UDOUBLE:
{
double ev = parm[n]->data()->getDoubleVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getDoubleVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::FLOAT:
case execplan::CalpontSystemCatalog::UFLOAT:
{
float ev = parm[n]->data()->getFloatVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getFloatVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
case execplan::CalpontSystemCatalog::LONGDOUBLE:
{
long double ev = parm[n]->data()->getLongDoubleVal(row, isNull);
if (isNull)
break;
for (i = 1; i <= whereCount; i++)
{
if (ev == parm[i]->data()->getLongDoubleVal(row, isNull) && !isNull)
{
foundIt = true;
break;
}
else
isNull = false;
}
break;
}
default:
{
std::ostringstream oss;
oss << "case: datatype of " << execplan::colDataTypeToString(operationColType.colDataType);
throw logging::IDBExcept(oss.str(), ERR_DATATYPE_NOT_SUPPORT);
}
}
if (!foundIt && !hasElse)
isNull = true;
else if (!foundIt && hasElse && !isNull)
{
i = parm.size() - 1;
}
else if (isNull && hasElse)
// BUG 5110. Only way we can exit above with isNull == true is when ev is NULL
// if so and we have else condition we need to use it by setting i = else
{
i = parm.size() - 1;
isNull = false;
}
if (foundIt)
{
i += whereCount;
}
return i;
}
CalpontSystemCatalog::ColType caseOperationType(FunctionParm& fp,
CalpontSystemCatalog::ColType& resultType,
bool simpleCase)
{
uint64_t simple = simpleCase ? 1 : 0;
bool hasElse = (((fp.size()-simple) % 2) != 0); // if 1, then ELSE exist
uint64_t parmCount = hasElse ? (fp.size() - 2) : (fp.size() - 1);
uint64_t whereCount = hasElse ? (fp.size() - 2 + simple) / 2 : (fp.size() - 1) / 2 + simple;
bool allStringO = true;
bool allStringR = true;
FunctionParm::size_type l = fp.size() - 1; // last fp index
idbassert(fp[l]->data());
CalpontSystemCatalog::ColType oct = fp[l]->data()->resultType();
CalpontSystemCatalog::ColType rct = resultType;
bool operation = true;
for (uint64_t i = 0; i <= parmCount; i++)
{
// for SimpleCase, we return the type of the case expression,
// which will always be in position 0.
if (i == 0 && simpleCase)
{
if (fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::CHAR &&
fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::TEXT &&
fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::VARCHAR)
{
PredicateOperator op;
op.setOpType(oct, fp[i]->data()->resultType());
allStringO = false;
oct = op.operationType();
}
i += 1;
}
// operation or result type
operation = ((i > 0+simple) && (i <= whereCount));
if (fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::CHAR &&
fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::TEXT &&
fp[i]->data()->resultType().colDataType != CalpontSystemCatalog::VARCHAR)
{
// this is not a string column
PredicateOperator op;
if (operation)
{
if (!simpleCase)
{
op.setOpType(oct, fp[i]->data()->resultType());
allStringO = false;
oct = op.operationType();
}
}
// If any parm is of string type, the result type should be string. (same as if)
else if (rct.colDataType != CalpontSystemCatalog::CHAR &&
rct.colDataType != CalpontSystemCatalog::TEXT &&
rct.colDataType != CalpontSystemCatalog::VARCHAR)
{
op.setOpType(rct, fp[i]->data()->resultType());
allStringR = false;
rct = op.operationType();
}
}
else
{
// this is a string
// If any parm is of string type, the result type should be string. (same as if)
allStringR = true;
}
}
if (allStringO)
{
oct.colDataType = CalpontSystemCatalog::VARCHAR;
oct.colWidth = 255;
}
if (allStringR)
{
rct.colDataType = CalpontSystemCatalog::VARCHAR;
rct.colWidth = 255;
}
if (rct.scale != 0 && rct.colDataType == CalpontSystemCatalog::BIGINT)
rct.colDataType = CalpontSystemCatalog::DECIMAL;
if (oct.scale != 0 && oct.colDataType == CalpontSystemCatalog::BIGINT)
oct.colDataType = CalpontSystemCatalog::DECIMAL;
resultType = rct;
return oct;
}
}
namespace funcexp
{
// simple CASE:
// SELECT CASE ("expression")
// WHEN "condition1" THEN "result1"
// WHEN "condition2" THEN "result2"
// ...
// [ELSE "resultN"]
// END
//
// simple CASE parm order:
// expression condition1 condition2 ... result1 result2 ... [resultN]
//
// Note that this order changed in 10.2.14, see MCOL-1341
CalpontSystemCatalog::ColType Func_decode_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType)
{
return caseOperationType(fp, resultType, true);
}
bool Func_decode_oracle::getBoolVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return false;
ParseTree* lop = parm[i]->left();
ParseTree* rop = parm[i]->right();
if (lop && rop)
{
return (reinterpret_cast<Operator*>(parm[i]->data()))->getBoolVal(row, isNull, lop, rop);
}
return parm[i]->data()->getBoolVal(row, isNull);
}
int64_t Func_decode_oracle::getIntVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return joblist::BIGINTNULL;
return parm[i]->data()->getIntVal(row, isNull);
}
string Func_decode_oracle::getStrVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return string("");
return parm[i]->data()->getStrVal(row, isNull);
}
IDB_Decimal Func_decode_oracle::getDecimalVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return IDB_Decimal(); // need a null value for IDB_Decimal??
return parm[i]->data()->getDecimalVal(row, isNull);
}
double Func_decode_oracle::getDoubleVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return doubleNullVal();
return parm[i]->data()->getDoubleVal(row, isNull);
}
long double Func_decode_oracle::getLongDoubleVal(Row& row,
FunctionParm& parm,
bool& isNull,
CalpontSystemCatalog::ColType& operationColType)
{
uint64_t i = simple_case_cmp(row, parm, isNull, operationColType);
if (isNull)
return doubleNullVal();
return parm[i]->data()->getLongDoubleVal(row, isNull);
}
int32_t Func_decode_oracle::getDateIntVal(rowgroup::Row& row,
FunctionParm& parm,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
uint64_t i = simple_case_cmp(row, parm, isNull, op_ct);
if (isNull)
return joblist::DATENULL;
return parm[i]->data()->getDateIntVal(row, isNull);
}
int64_t Func_decode_oracle::getDatetimeIntVal(rowgroup::Row& row,
FunctionParm& parm,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
uint64_t i = simple_case_cmp(row, parm, isNull, op_ct);
if (isNull)
return joblist::DATETIMENULL;
return parm[i]->data()->getDatetimeIntVal(row, isNull);
}
int64_t Func_decode_oracle::getTimestampIntVal(rowgroup::Row& row,
FunctionParm& parm,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
uint64_t i = simple_case_cmp(row, parm, isNull, op_ct);
if (isNull)
return joblist::TIMESTAMPNULL;
return parm[i]->data()->getTimestampIntVal(row, isNull);
}
int64_t Func_decode_oracle::getTimeIntVal(rowgroup::Row& row,
FunctionParm& parm,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct)
{
uint64_t i = simple_case_cmp(row, parm, isNull, op_ct);
if (isNull)
return joblist::TIMENULL;
return parm[i]->data()->getTimeIntVal(row, isNull);
}
}

View File

@ -1,3 +1,21 @@
/* Copyright (C) 2014 InfiniDB, Inc.
Copyright (C) 2021 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. */
#include <cstdlib>
#include <string>
using namespace std;

View File

@ -0,0 +1,107 @@
/* Copyright (C) 2014 InfiniDB, Inc.
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: func_ltrim.cpp 3923 2013-06-19 21:43:06Z bwilkinson $
*
*
****************************************************************************/
#include <string>
using namespace std;
#include "functor_str.h"
#include "functioncolumn.h"
#include "utils_utf8.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "joblisttypes.h"
using namespace joblist;
#include "collation.h"
namespace funcexp
{
CalpontSystemCatalog::ColType Func_ltrim_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType)
{
// operation type is not used by this functor
return fp[0]->data()->resultType();
}
std::string Func_ltrim_oracle::getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& type)
{
CHARSET_INFO* cs = type.getCharset();
// The original string
const string& src = fp[0]->data()->getStrVal(row, isNull);
if (isNull)
return "";
if (src.empty() || src.length() == 0)
return src;
// binLen represents the number of bytes in src
size_t binLen = src.length();
const char* pos = src.c_str();
const char* end = pos + binLen;
// strLen = the number of characters in src
size_t strLen = cs->numchars(pos, end);
// The trim characters.
const string& trim = (fp.size() > 1 ? fp[1]->data()->getStrVal(row, isNull) : " ");
// binTLen represents the number of bytes in trim
size_t binTLen = trim.length();
const char* posT = trim.c_str();
// strTLen = the number of characters in trim
size_t strTLen = cs->numchars(posT, posT+binTLen);
if (strTLen == 0 || strTLen > strLen)
return src;
if (binTLen == 1)
{
// If the trim string is 1 byte, don't waste cpu for memcmp
while (pos < end && *pos == *posT)
{
++pos;
--binLen;
}
}
else
{
while (pos+binTLen <= end && memcmp(pos,posT,binTLen) == 0)
{
pos += binTLen;
binLen -= binTLen;
}
}
// Turn back to a string
std::string ret(pos, binLen);
if (binLen == 0)
{
isNull = true;
}
return ret;
}
} // namespace funcexp
// vim:ts=4 sw=4:

View File

@ -0,0 +1,178 @@
/* Copyright (C) 2021 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. */
#include <string>
using namespace std;
#include "functor_str.h"
#include "functioncolumn.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "joblisttypes.h"
using namespace joblist;
#include "collation.h"
namespace funcexp
{
CalpontSystemCatalog::ColType Func_replace_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType)
{
// operation type is not used by this functor
return fp[0]->data()->resultType();
}
std::string Func_replace_oracle::getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& ct)
{
CHARSET_INFO* cs = ct.getCharset();
const string& str = fp[0]->data()->getStrVal(row, isNull);
if (isNull)
return "";
size_t strLen = str.length();
const string& fromstr = fp[1]->data()->getStrVal(row, isNull);
if (isNull)
return "";
if (fromstr.length() == 0)
return str;
size_t fromLen = fromstr.length();
const string& tostr = fp[2]->data()->getStrVal(row, isNull);
if (isNull)
return "";
size_t toLen = tostr.length();
bool binaryCmp = (cs->state & MY_CS_BINSORT) || !cs->use_mb();
string newstr;
size_t pos = 0;
if (binaryCmp)
{
// Count the number of fromstr in strend so we can reserve buffer space.
int count = 0;
do
{
++count;
pos = str.find(fromstr, pos + fromLen);
}
while (pos != string::npos);
newstr.reserve(strLen + (count * ((int)toLen - (int)fromLen)) + 1);
uint32_t i = 0;
pos = str.find(fromstr);
if (pos == string::npos)
return str;
// Move the stuff into newstr
do
{
if (pos > i)
newstr = newstr + str.substr(i, pos - i);
newstr = newstr + tostr;
i = pos + fromLen;
pos = str.find(fromstr, i);
}
while (pos != string::npos);
newstr = newstr + str.substr(i, string::npos);
}
else
{
// UTF
const char* src = str.c_str();
const char* srcEnd = src + strLen;
const char* srchEnd = srcEnd - fromLen + 1;
const char* from = fromstr.c_str();
const char* fromEnd = from + fromLen;
const char* to = tostr.c_str();
const char* ptr = src;
char *i,*j;
size_t count = 10; // Some arbitray number to reserve some space to start.
int growlen = (int)toLen - (int)fromLen;
growlen = growlen < 1 ? 1 : growlen;
growlen *= count;
newstr.reserve(strLen + (count * growlen) + 1);
size_t maxsize = newstr.capacity();
uint32_t l;
// We don't know where byte patterns might match so
// we start at the beginning of the string and move forward
// one character at a time until we find a match. Then we can
// move the src bytes and add in the to bytes,then try again.
while (ptr < srchEnd)
{
bool found = false;
if (*ptr == *from) // If the first byte matches, maybe we have a match
{
// Do a byte by byte compare of src at that spot against from
i = const_cast<char*>(ptr) + 1;
j = const_cast<char*>(from) + 1;
found = true;
while (j != fromEnd)
{
if (*i++ != *j++)
{
found = false;
break;
}
}
}
if (found)
{
if (ptr < i)
{
int mvsize = ptr - src;
if (newstr.length() + mvsize + toLen > maxsize)
{
// We need a re-alloc
newstr.reserve(maxsize + growlen);
maxsize = newstr.capacity();
growlen *= 2;
}
newstr.append(src, ptr - src);
src += mvsize + fromLen;
ptr = src;
}
newstr.append(to, toLen);
}
else
{
// move to the next character
if ((l = my_ismbchar(cs, ptr, srcEnd))) // returns the number of bytes in the leading char or zero if one byte
ptr += l;
else
++ptr;
}
}
// Copy in the trailing src chars.
newstr.append(src, srcEnd - src);
}
return newstr;
}
} // namespace funcexp
// vim:ts=4 sw=4:

View File

@ -0,0 +1,169 @@
/* Copyright (C) 2014 InfiniDB, Inc.
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: func_rtrim.cpp 3923 2013-06-19 21:43:06Z bwilkinson $
*
*
****************************************************************************/
#include <string>
using namespace std;
#include "functor_str.h"
#include "functioncolumn.h"
#include "utils_utf8.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "joblisttypes.h"
using namespace joblist;
#include "collation.h"
namespace funcexp
{
CalpontSystemCatalog::ColType Func_rtrim_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType)
{
// operation type is not used by this functor
return fp[0]->data()->resultType();
}
std::string Func_rtrim_oracle::getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& type)
{
CHARSET_INFO* cs = type.getCharset();
// The original string
const string& src = fp[0]->data()->getStrVal(row, isNull);
if (isNull)
return "";
if (src.empty() || src.length() == 0)
return src;
// binLen represents the number of bytes in src
size_t binLen = src.length();
const char* pos = src.c_str();
const char* end = pos + binLen;
// strLen = the number of characters in src
size_t strLen = cs->numchars(pos, end);
// The trim characters.
const string& trim = (fp.size() > 1 ? fp[1]->data()->getStrVal(row, isNull) : " ");
// binTLen represents the number of bytes in trim
size_t binTLen = trim.length();
const char* posT = trim.c_str();
// strTLen = the number of characters in trim
size_t strTLen = cs->numchars(posT, posT+binTLen);
if (strTLen == 0 || strTLen > strLen)
return src;
if (binTLen == 1)
{
const char* ptr = pos;
if (cs->use_mb()) // This is a multi-byte charset
{
const char* p = pos;
uint32 l;
// Multibyte characters in the string give us alignment problems
// What we do here is skip past any multibyte characters. Whn
// don with this loop, ptr is pointing to a singlebyte char that
// is after all multibyte chars in the string, or to end.
while (ptr < end)
{
if ((l = my_ismbchar(cs, ptr, end))) // returns the number of bytes in the leading char or zero if one byte
{
ptr += l;
p = ptr;
}
else
{
++ptr;
}
}
ptr = p;
}
while (ptr < end && end[-1] == *posT)
{
--end;
--binLen;
}
}
else
{
// An uncommon case where the space character is > 1 byte
if (cs->use_mb()) // This is a multi-byte charset
{
// The problem is that the byte pattern at the end could
// match memcmp, but not be correct since the first byte compared
// may actually be a second or later byte from a previous char.
// We start at the beginning of the string and move forward
// one character at a time until we reach the end. Then we can
// safely compare and remove on character. Then back to the beginning
// and try again.
while (end - binTLen >= pos)
{
const char* p = pos;
uint32 l;
while (p + binTLen < end)
{
if ((l = my_ismbchar(cs, p, end))) // returns the number of bytes in the leading char or zero if one byte
p += l;
else
++p;
}
if (p + binTLen == end && memcmp(p,posT,binTLen) == 0)
{
end -= binTLen;
binLen -= binTLen;
}
else
{
break; // We've run out of places to look
}
}
}
else
{
// This implies we have a single byte charset and a multibyte
// space character.
// Should never get here, since rtrim only trims space characters
// Included for completeness.
while (end-binTLen >= pos && memcmp(end-binTLen,posT,binTLen) == 0)
{
end -= binTLen;
binLen -= binTLen;
}
}
}
// Turn back to a string
std::string ret(pos, binLen);
if (binLen == 0)
{
isNull = true;
}
return ret;
}
} // namespace funcexp
// vim:ts=4 sw=4:

View File

@ -0,0 +1,175 @@
/* Copyright (C) 2021 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. */
#include <string>
using namespace std;
#include "functor_str.h"
#include "functioncolumn.h"
#include "utils_utf8.h"
using namespace execplan;
#include "rowgroup.h"
using namespace rowgroup;
#include "joblisttypes.h"
using namespace joblist;
#include "collation.h"
namespace funcexp
{
CalpontSystemCatalog::ColType Func_trim_oracle::operationType(FunctionParm& fp, CalpontSystemCatalog::ColType& resultType)
{
// operation type is not used by this functor
return fp[0]->data()->resultType();
}
std::string Func_trim_oracle::getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& type)
{
CHARSET_INFO* cs = type.getCharset();
// The original string
const string& src = fp[0]->data()->getStrVal(row, isNull);
if (isNull)
return "";
if (src.empty() || src.length() == 0)
return src;
// binLen represents the number of bytes in src
size_t binLen = src.length();
const char* pos = src.c_str();
const char* end = pos + binLen;
// strLen = the number of characters in src
size_t strLen = cs->numchars(pos, end);
// The trim characters.
const string& trim = (fp.size() > 1 ? fp[1]->data()->getStrVal(row, isNull) : " ");
// binTLen represents the number of bytes in trim
size_t binTLen = trim.length();
const char* posT = trim.c_str();
// strTLen = the number of characters in trim
size_t strTLen = cs->numchars(posT, posT+binTLen);
if (strTLen == 0 || strTLen > strLen)
return src;
if (binTLen == 1)
{
// If the trim string is 1 byte, don't waste cpu for memcmp
// Trim leading
while (pos < end && *pos == *posT)
{
++pos;
--binLen;
}
// Trim trailing
const char* ptr = pos;
if (cs->use_mb()) // This is a multi-byte charset
{
const char* p = pos;
uint32 l;
// Multibyte characters in the string give us alignment problems
// What we do here is skip past any multibyte characters. Whn
// don with this loop, ptr is pointing to a singlebyte char that
// is after all multibyte chars in the string, or to end.
while (ptr < end)
{
if ((l = my_ismbchar(cs, ptr, end))) // returns the number of bytes in the leading char or zero if one byte
{
ptr += l;
p = ptr;
}
else
{
++ptr;
}
}
ptr = p;
}
while (ptr < end && end[-1] == *posT)
{
--end;
--binLen;
}
}
else
{
// Trim leading is easy
while (pos+binTLen <= end && memcmp(pos,posT,binTLen) == 0)
{
pos += binTLen;
binLen -= binTLen;
}
// Trim trailing
if (cs->use_mb()) // This is a multi-byte charset
{
// The problem is that the byte pattern at the end could
// match memcmp, but not be correct since the first byte compared
// may actually be a second or later byte from a previous char.
// We start at the beginning of the string and move forward
// one character at a time until we reach the end. Then we can
// safely compare and remove one character. Then back to the beginning
// and try again.
while (end - binTLen >= pos)
{
const char* p = pos;
uint32_t l;
while (p + binTLen < end)
{
if ((l = my_ismbchar(cs, p, end))) // returns the number of bytes in the leading char or zero if one byte
p += l;
else
++p;
}
if (p + binTLen == end && memcmp(p,posT,binTLen) == 0)
{
end -= binTLen;
binLen -= binTLen;
}
else
{
break; // We've run out of places to look
}
}
}
else
{
while (end-binTLen >= pos && memcmp(end-binTLen,posT,binTLen) == 0)
{
end -= binTLen;
binLen -= binTLen;
}
}
}
// Turn back to a string
std::string ret(pos, binLen);
if (binLen == 0)
{
isNull = true;
}
return ret;
}
} // namespace funcexp
// vim:ts=4 sw=4:

View File

@ -97,6 +97,7 @@ FuncExp::FuncExp()
fFuncMap["char_length"] = new Func_char_length(); //dlh
fFuncMap["character_length"] = new Func_char_length(); //dlh
fFuncMap["coalesce"] = new Func_coalesce();
fFuncMap["concat_operator_oracle"] = new Func_concat_oracle();
fFuncMap["concat"] = new Func_concat();
fFuncMap["concat_ws"] = new Func_concat_ws();
fFuncMap["conv"] = new Func_conv();
@ -112,6 +113,7 @@ FuncExp::FuncExp()
fFuncMap["dayofweek"] = new Func_dayofweek(); //dlh
fFuncMap["dayofyear"] = new Func_dayofyear(); //dlh
fFuncMap["decode"] = new Func_decode(); // BT
fFuncMap["decode_oracle"] = new Func_decode_oracle(); // BT
fFuncMap["degrees"] = new Func_degrees();
fFuncMap["DIV"] = new Func_div(); // MySQL use upper case for this function name
fFuncMap["elt"] = new Func_elt();
@ -156,6 +158,7 @@ FuncExp::FuncExp()
fFuncMap["lower"] = new Func_lcase(); //dlh
fFuncMap["lpad"] = new Func_lpad(); //dlh
fFuncMap["ltrim"] = new Func_ltrim(); //dlh
fFuncMap["ltrim_oracle"] = new Func_ltrim_oracle(); //dlh
fFuncMap["makedate"] = new Func_makedate();
fFuncMap["maketime"] = new Func_maketime();
fFuncMap["microsecond"] = new Func_microsecond();
@ -183,11 +186,13 @@ FuncExp::FuncExp()
fFuncMap["regexp"] = new Func_regexp(); //dlh
fFuncMap["repeat"] = new Func_repeat(); //dlh
fFuncMap["replace"] = new Func_replace(); //dlh
fFuncMap["replace_oracle"] = new Func_replace_oracle(); //dlh
fFuncMap["reverse"] = new Func_reverse(); //dlh
fFuncMap["right"] = new Func_right(); //dlh
fFuncMap["round"] = new Func_round();
fFuncMap["rpad"] = new Func_rpad(); //dlh
fFuncMap["rtrim"] = new Func_rtrim(); //dlh
fFuncMap["rtrim_oracle"] = new Func_rtrim_oracle(); //dlh
fFuncMap["second"] = new Func_second(); //dlh
fFuncMap["sec_to_time"] = new Func_sec_to_time();
fFuncMap["sha"] = new Func_sha();
@ -210,6 +215,7 @@ FuncExp::FuncExp()
fFuncMap["time_to_sec"] = new Func_time_to_sec(); //dlh
fFuncMap["to_days"] = new Func_to_days(); //dlh
fFuncMap["trim"] = new Func_trim(); //dlh
fFuncMap["trim_oracle"] = new Func_trim_oracle(); //dlh
fFuncMap["truncate"] = new Func_truncate(); //dlh
fFuncMap["ucase"] = new Func_ucase(); //dlh
fFuncMap["unhex"] = new Func_unhex();

View File

@ -122,6 +122,65 @@ public:
execplan::CalpontSystemCatalog::ColType& op_ct);
};
class Func_decode_oracle : public Func_All
{
public:
Func_decode_oracle(): Func_All("decode_oracle") {}
virtual ~Func_decode_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
bool getBoolVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
int64_t getIntVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
double getDoubleVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
long double getLongDoubleVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
execplan::IDB_Decimal getDecimalVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
int32_t getDateIntVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
int64_t getDatetimeIntVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
int64_t getTimestampIntVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
int64_t getTimeIntVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_searched_case class
*/

View File

@ -183,6 +183,22 @@ public:
};
/** @brief Func_concat_oracle class
*/
class Func_concat_oracle : public Func_Str
{
public:
Func_concat_oracle() : Func_Str("concat_operator_oracle") {}
virtual ~Func_concat_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_substr class
*/
class Func_substr : public Func_Str
@ -333,6 +349,55 @@ public:
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_ltrim class
*/
class Func_ltrim_oracle : public Func_Str
{
public:
Func_ltrim_oracle() : Func_Str("ltrim_oracle") {}
virtual ~Func_ltrim_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_rtrim class
*/
class Func_rtrim_oracle : public Func_Str
{
public:
Func_rtrim_oracle() : Func_Str("rtrim_oracle") {}
virtual ~Func_rtrim_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_trim class
*/
class Func_trim_oracle : public Func_Str
{
public:
Func_trim_oracle() : Func_Str("trim_oracle") {}
virtual ~Func_trim_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_lpad class
*/
@ -386,6 +451,19 @@ public:
execplan::CalpontSystemCatalog::ColType& op_ct);
};
class Func_replace_oracle : public Func_Str
{
public:
Func_replace_oracle() : Func_Str("replace_oracle") {}
virtual ~Func_replace_oracle() {}
execplan::CalpontSystemCatalog::ColType operationType(FunctionParm& fp, execplan::CalpontSystemCatalog::ColType& resultType);
std::string getStrVal(rowgroup::Row& row,
FunctionParm& fp,
bool& isNull,
execplan::CalpontSystemCatalog::ColType& op_ct);
};
/** @brief Func_right class
*/