mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
functions: add char function as mysql behavior
This commit is contained in:
parent
b808172e91
commit
538b77c123
@ -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>();
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
@ -0,0 +1,2 @@
|
||||
ABCDabcdefg
|
||||
ABC
|
3
dbms/tests/queries/0_stateless/01020_function_char.sql
Normal file
3
dbms/tests/queries/0_stateless/01020_function_char.sql
Normal 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);
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user