1#include <Columns/ColumnFixedString.h>
2#include <Columns/ColumnString.h>
3#include <DataTypes/DataTypeString.h>
4#include <Functions/FunctionFactory.h>
5#include <Functions/FunctionHelpers.h>
6#include <Functions/IFunctionImpl.h>
7#include <IO/WriteHelpers.h>
8#include <ext/range.h>
9
10#include <memory>
11#include <string>
12#include <vector>
13
14#include "formatString.h"
15
16namespace DB
17{
18namespace ErrorCodes
19{
20 extern const int ILLEGAL_COLUMN;
21 extern const int ILLEGAL_TYPE_OF_ARGUMENT;
22 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
23}
24
25template <typename Name>
26class FormatFunction : public IFunction
27{
28public:
29 static constexpr auto name = Name::name;
30
31 static FunctionPtr create(const Context &) { return std::make_shared<FormatFunction>(); }
32
33 String getName() const override { return name; }
34
35 bool isVariadic() const override { return true; }
36
37 size_t getNumberOfArguments() const override { return 0; }
38
39 ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {0}; }
40
41 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
42 {
43 if (arguments.empty())
44 throw Exception(
45 "Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size())
46 + ", should be at least 1",
47 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
48
49 if (arguments.size() > FormatImpl::argument_threshold)
50 throw Exception(
51 "Number of arguments for function " + getName() + " doesn't match: passed " + toString(arguments.size())
52 + ", should be at most " + std::to_string(FormatImpl::argument_threshold),
53 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
54
55 for (const auto arg_idx : ext::range(0, arguments.size()))
56 {
57 const auto arg = arguments[arg_idx].get();
58 if (!isStringOrFixedString(arg))
59 throw Exception(
60 "Illegal type " + arg->getName() + " of argument " + std::to_string(arg_idx + 1) + " of function " + getName(),
61 ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
62 }
63
64 return std::make_shared<DataTypeString>();
65 }
66
67 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t input_rows_count) override
68 {
69 const ColumnPtr & c0 = block.getByPosition(arguments[0]).column;
70 const ColumnConst * c0_const_string = typeid_cast<const ColumnConst *>(&*c0);
71
72 if (!c0_const_string)
73 throw Exception("First argument of function " + getName() + " must be constant string", ErrorCodes::ILLEGAL_COLUMN);
74
75 String pattern = c0_const_string->getValue<String>();
76
77 auto col_res = ColumnString::create();
78
79 std::vector<const ColumnString::Chars *> data(arguments.size() - 1);
80 std::vector<const ColumnString::Offsets *> offsets(arguments.size() - 1);
81 std::vector<size_t> fixed_string_N(arguments.size() - 1);
82 std::vector<String> constant_strings(arguments.size() - 1);
83
84 bool has_column_string = false;
85 bool has_column_fixed_string = false;
86 for (size_t i = 1; i < arguments.size(); ++i)
87 {
88 const ColumnPtr & column = block.getByPosition(arguments[i]).column;
89 if (const ColumnString * col = checkAndGetColumn<ColumnString>(column.get()))
90 {
91 has_column_string = true;
92 data[i - 1] = &col->getChars();
93 offsets[i - 1] = &col->getOffsets();
94 }
95 else if (const ColumnFixedString * fixed_col = checkAndGetColumn<ColumnFixedString>(column.get()))
96 {
97 has_column_fixed_string = true;
98 data[i - 1] = &fixed_col->getChars();
99 fixed_string_N[i - 1] = fixed_col->getN();
100 }
101 else if (const ColumnConst * const_col = checkAndGetColumnConstStringOrFixedString(column.get()))
102 {
103 constant_strings[i - 1] = const_col->getValue<String>();
104 }
105 else
106 throw Exception(
107 "Illegal column " + column->getName() + " of argument of function " + getName(), ErrorCodes::ILLEGAL_COLUMN);
108 }
109
110 FormatImpl::formatExecute(
111 has_column_string,
112 has_column_fixed_string,
113 std::move(pattern),
114 data,
115 offsets,
116 fixed_string_N,
117 constant_strings,
118 col_res->getChars(),
119 col_res->getOffsets(),
120 input_rows_count);
121
122 block.getByPosition(result).column = std::move(col_res);
123 }
124};
125
126
127struct NameFormat
128{
129 static constexpr auto name = "format";
130};
131using FunctionFormat = FormatFunction<NameFormat>;
132
133void registerFunctionFormat(FunctionFactory & factory)
134{
135 factory.registerFunction<FunctionFormat>();
136}
137
138}
139