#pragma once #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } namespace Conditional { namespace { /// This class provides type-independent access to the values of a numeric branch /// (then, else) column. Returned values have the type TResult. template class NumericSource { public: virtual TResult get(size_t i) const = 0; virtual ~NumericSource() = default; }; template using NumericSourcePtr = std::unique_ptr >; template using NumericSources = std::vector >; /// Column type-specific implementation of NumericSource. template class NumericSourceImpl; template class NumericSourceImpl final : public NumericSource { public: NumericSourceImpl(const Block & block, const ColumnNumbers & args, const Branch & br) { size_t index = br.index; const ColumnPtr & col = block.getByPosition(args[index]).column; const auto * const_col = typeid_cast *>(&*col); if (const_col == nullptr) throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR}; data = const_col->getData(); } NumericSourceImpl(const NumericSourceImpl &) = delete; NumericSourceImpl & operator=(const NumericSourceImpl &) = delete; NumericSourceImpl(NumericSourceImpl &&) = default; NumericSourceImpl & operator=(NumericSourceImpl &&) = default; TResult get(size_t i) const override { return static_cast(data); }; private: TType data; }; template class NumericSourceImpl final : public NumericSource { public: NumericSourceImpl(const Block & block, const ColumnNumbers & args, const Branch & br) : data_array{initDataArray(block, args, br)} { } NumericSourceImpl(const NumericSourceImpl &) = delete; NumericSourceImpl & operator=(const NumericSourceImpl &) = delete; NumericSourceImpl(NumericSourceImpl &&) = default; NumericSourceImpl & operator=(NumericSourceImpl &&) = default; TResult get(size_t i) const override { return static_cast(data_array[i]); }; private: static const PaddedPODArray & initDataArray(const Block & block, const ColumnNumbers & args, const Branch & br) { size_t index = br.index; const ColumnPtr & col = block.getByPosition(args[index]).column; const auto * vec_col = typeid_cast *>(&*col); if (vec_col == nullptr) throw Exception{"Internal error", ErrorCodes::LOGICAL_ERROR}; return vec_col->getData(); } private: const PaddedPODArray & data_array; }; /// Create a numeric column accessor if TType is the type registered /// in the specified branch info. template class NumericSourceCreator final { public: static bool execute(NumericSourcePtr & source, const Block & block, const ColumnNumbers & args, const Branch & br) { auto type_name = br.type->getName(); if (TypeName::get() == type_name) { if (br.is_const) source = std::make_unique >(block, args, br); else source = std::make_unique >(block, args, br); return true; } else return false; } }; } /// Processing of multiIf in the case of scalar numeric types. template class NumericEvaluator final { public: static void perform(const Branches & branches, Block & block, const ColumnNumbers & args, size_t result, NullMapBuilder & builder) { const CondSources conds = createConds(block, args); const NumericSources sources = createNumericSources(block, args, branches); size_t row_count = conds[0].getSize(); PaddedPODArray & res = createSink(block, result, row_count); if (builder) builder.init(args); for (size_t cur_row = 0; cur_row < row_count; ++cur_row) { bool has_triggered_cond = false; size_t cur_source = 0; for (const auto & cond : conds) { if (cond.get(cur_row)) { res[cur_row] = sources[cur_source]->get(cur_row); if (builder) builder.update(args[branches[cur_source].index], cur_row); has_triggered_cond = true; break; } ++cur_source; } if (!has_triggered_cond) { res[cur_row] = sources.back()->get(cur_row); if (builder) builder.update(args[branches.back().index], cur_row); } } } private: /// Create the result column. static PaddedPODArray & createSink(Block & block, size_t result, size_t size) { std::shared_ptr> col_res = std::make_shared>(); block.getByPosition(result).column = col_res; typename ColumnVector::Container_t & vec_res = col_res->getData(); vec_res.resize(size); return vec_res; } /// Create accessors for condition values. static CondSources createConds(const Block & block, const ColumnNumbers & args) { CondSources conds; conds.reserve(getCondCount(args)); for (size_t i = firstCond(); i < elseArg(args); i = nextCond(i)) conds.emplace_back(block, args, i); return conds; } /// Create accessors for branch values. static NumericSources createNumericSources(const Block & block, const ColumnNumbers & args, const Branches & branches) { NumericSources sources; sources.reserve(branches.size()); for (const auto & br : branches) { NumericSourcePtr source; if (! (NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br) || NumericSourceCreator::execute(source, block, args, br))) throw CondException{CondErrorCodes::NUMERIC_EVALUATOR_ILLEGAL_ARGUMENT, toString(br.index)}; sources.push_back(std::move(source)); } return sources; } }; /// Processing of multiIf in the case of an invalid return type. template <> class NumericEvaluator { public: /// For the meaning of the builder parameter, see the FunctionMultiIf::perform() declaration. static void perform(const Branches & branches, Block & block, const ColumnNumbers & args, size_t result, NullMapBuilder & builder) { throw Exception{"Internal logic error", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT}; } }; } }