functions: add char function as mysql behavior

This commit is contained in:
sundy-li 2019-10-25 18:43:52 +08:00
parent b808172e91
commit 538b77c123
6 changed files with 101 additions and 1 deletions

View File

@ -25,6 +25,7 @@ void registerFunctionsCoding(FunctionFactory & factory)
factory.registerFunction<FunctionUUIDStringToNum>();
factory.registerFunction<FunctionHex>();
factory.registerFunction<FunctionUnhex>();
factory.registerFunction<FunctionChar>(FunctionFactory::CaseInsensitive);
factory.registerFunction<FunctionBitmaskToArray>();
factory.registerFunction<FunctionToIPv4>();
factory.registerFunction<FunctionToIPv6>();

View File

@ -1276,6 +1276,97 @@ public:
}
};
class FunctionChar : public IFunction
{
public:
static constexpr auto name = "char";
static FunctionPtr create(const Context &) { return std::make_shared<FunctionChar>(); }
String getName() const override
{
return name;
}
bool isVariadic() const override { return true; }
bool isInjective(const Block &) override { return true; }
size_t getNumberOfArguments() const override { return 0; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{
if (arguments.empty())
throw Exception("Number of arguments for function " + getName() + " can't be " + toString(arguments.size())
+ ", should be at least 1", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
for (const auto & arg : arguments)
{
WhichDataType which(arg);
if (!(which.isInt() || which.isUInt() || which.isFloat()))
throw Exception("Illegal type " + arg->getName() + " of argument of function " + getName()
+ ", must be Int, UInt or Float number",
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
return std::make_shared<DataTypeString>();
}
bool useDefaultImplementationForConstants() const override { return true; }
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
{
const size_t rows = block.getByPosition(arguments[0]).column.get()->size();
auto col_str = ColumnString::create();
ColumnString::Chars & out_vec = col_str->getChars();
ColumnString::Offsets & out_offsets = col_str->getOffsets();
const auto size_per_row = arguments.size() + 1;
out_vec.resize(size_per_row * rows);
out_offsets.resize(rows);
for (size_t row = 0; row < rows; ++row)
{
out_offsets[row] = size_per_row + out_offsets[row - 1];
out_vec[row * size_per_row + size_per_row - 1] = '\0';
}
for (const size_t & column_idx : arguments)
{
const IColumn * column = block.getByPosition(column_idx).column.get();
if (!(executeNumber<UInt8>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<UInt16>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<UInt32>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<UInt64>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Int8>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Int16>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Int32>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Int64>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Float32>(*column, out_vec, column_idx, rows, size_per_row)
|| executeNumber<Float64>(*column, out_vec, column_idx, rows, size_per_row)))
{
throw Exception{"Illegal column " + block.getByPosition(column_idx).column->getName()
+ " of first argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN};
}
}
block.getByPosition(result).column = std::move(col_str);
}
private:
template <typename T>
bool executeNumber(const IColumn & src_data, ColumnString::Chars & out_vec, const size_t & column_idx, const size_t & rows, const size_t & size_per_row)
{
const ColumnVector<T> * src_data_concrete = checkAndGetColumn<ColumnVector<T>>(&src_data);
if (!src_data_concrete)
{
return false;
}
for (size_t row = 0; row < rows; ++row)
{
out_vec[row * size_per_row + column_idx] = static_cast<char>(src_data_concrete->getInt(row));
}
return true;
}
};
class FunctionBitmaskToArray : public IFunction
{

View File

@ -125,4 +125,4 @@ CREATE TABLE addresses(addr String) ENGINE = Memory;
INSERT INTO addresses(addr) VALUES ('00000000000000000000FFFFC1FC110A'), ('00000000000000000000FFFF4D583737'), ('00000000000000000000FFFF7F000001');
SELECT cutIPv6(toFixedString(unhex(addr), 16), 0, 3) FROM addresses ORDER BY addr ASC;
DROP TABLE addresses;
DROP TABLE addresses;

View File

@ -0,0 +1,2 @@
ABCDabcdefg
ABC

View File

@ -0,0 +1,3 @@
/* char function */
SELECT char(65, 66.1, 67.2, 68.3, 97.4, 98.5, 99.6, 100.7, 101.0, 102.0, 103.0);
SELECT char(65 + 256, 66 + 1024, 66 + 1024 + 1);

View File

@ -1,5 +1,8 @@
# Encoding functions
## char
Accepts multiple arguments of `Number` types. Returns a string, each char of the results corresponds to the ascii character of the input numbers. It'll cast the first byte from the number, if the byte overflows the range of ascii(which is 127), it returns an unrecognized character(<28>).
## hex
Accepts arguments of types: `String`, `unsigned integer`, `Date`, or `DateTime`. Returns a string containing the argument's hexadecimal representation. Uses uppercase letters `A-F`. Does not use `0x` prefixes or `h` suffixes. For strings, all bytes are simply encoded as two hexadecimal numbers. Numbers are converted to big endian ("human readable") format. For numbers, older zeros are trimmed, but only by entire bytes. For example, `hex (1) = '01'`. `Date` is encoded as the number of days since the beginning of the Unix epoch. `DateTime` is encoded as the number of seconds since the beginning of the Unix epoch.