#include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int ILLEGAL_TYPE_OF_ARGUMENT; } template void expandDataByMask(PaddedPODArray & data, const PaddedPODArray & mask, bool reverse, T default_value) { if (mask.size() < data.size()) throw Exception("Mask size should be no less than data size.", ErrorCodes::LOGICAL_ERROR); int from = data.size() - 1; int index = mask.size() - 1; data.resize(mask.size()); while (index >= 0) { if (mask[index] ^ reverse) { if (from < 0) throw Exception("Too many bytes in mask", ErrorCodes::LOGICAL_ERROR); data[index] = data[from]; --from; } else data[index] = default_value; --index; } if (from != -1) throw Exception("Not enough bytes in mask", ErrorCodes::LOGICAL_ERROR); } /// Explicit instantiations - not to place the implementation of the function above in the header file. #define INSTANTIATE(TYPE) \ template void expandDataByMask(PaddedPODArray &, const PaddedPODArray &, bool, TYPE); INSTANTIATE(UInt8) INSTANTIATE(UInt16) INSTANTIATE(UInt32) INSTANTIATE(UInt64) INSTANTIATE(UInt128) INSTANTIATE(UInt256) INSTANTIATE(Int8) INSTANTIATE(Int16) INSTANTIATE(Int32) INSTANTIATE(Int64) INSTANTIATE(Int128) INSTANTIATE(Int256) INSTANTIATE(Float32) INSTANTIATE(Float64) INSTANTIATE(Decimal32) INSTANTIATE(Decimal64) INSTANTIATE(Decimal128) INSTANTIATE(Decimal256) INSTANTIATE(DateTime64) INSTANTIATE(char *) #undef INSTANTIATE void expandOffsetsByMask(PaddedPODArray & offsets, const PaddedPODArray & mask, bool reverse) { if (mask.size() < offsets.size()) throw Exception("Mask size should be no less than data size.", ErrorCodes::LOGICAL_ERROR); int index = mask.size() - 1; int from = offsets.size() - 1; offsets.resize(mask.size()); UInt64 prev_offset = offsets[from]; while (index >= 0) { if (mask[index] ^ reverse) { if (from < 0) throw Exception("Too many bytes in mask", ErrorCodes::LOGICAL_ERROR); offsets[index] = offsets[from]; --from; prev_offset = offsets[from]; } else offsets[index] = prev_offset; --index; } if (from != -1) throw Exception("Not enough bytes in mask", ErrorCodes::LOGICAL_ERROR); } template bool tryExpandMaskColumnByMask(const ColumnPtr & column, const PaddedPODArray & mask, bool reverse, UInt8 default_value_for_expanding_mask) { if (const auto * col = checkAndGetColumn>(*column)) { expandDataByMask(const_cast *>(col)->getData(), mask, reverse, default_value_for_expanding_mask); return true; } return false; } void expandMaskColumnByMask(const ColumnPtr & column, const PaddedPODArray& mask, bool reverse, UInt8 default_value_for_expanding_mask) { if (const auto * col = checkAndGetColumn(column.get())) { expandMaskColumnByMask(col->getNullMapColumnPtr(), mask, reverse, 0); expandMaskColumnByMask(col->getNestedColumnPtr(), mask, reverse, default_value_for_expanding_mask); return; } if (!tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask) && !tryExpandMaskColumnByMask(column, mask, reverse, default_value_for_expanding_mask)) throw Exception("Cannot convert column " + column.get()->getName() + " to mask", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } void expandColumnByMask(const ColumnPtr & column, const PaddedPODArray& mask, bool reverse) { column->assumeMutable()->expand(mask, reverse); } template void copyMaskImpl(const PaddedPODArray& mask, PaddedPODArray & res, bool reverse, const PaddedPODArray * null_bytemap, UInt8 null_value) { if (res.size() != mask.size()) res.resize(mask.size()); for (size_t i = 0; i != mask.size(); ++i) { if (null_bytemap && (*null_bytemap)[i]) res[i] = reverse ? !null_value : null_value; else res[i] = reverse ? !mask[i]: !!mask[i]; } } template bool tryGetMaskFromColumn(const ColumnPtr column, PaddedPODArray & res, bool reverse, const PaddedPODArray * null_bytemap, UInt8 null_value) { if (const auto * col = checkAndGetColumn>(*column)) { copyMaskImpl(col->getData(), res, reverse, null_bytemap, null_value); return true; } return false; } void getMaskFromColumn(const ColumnPtr & column, PaddedPODArray & res, bool reverse, const PaddedPODArray * null_bytemap, UInt8 null_value) { if (const auto * col = checkAndGetColumn(*column)) { getMaskFromColumn(col->convertToFullColumn(), res, reverse, null_bytemap, null_value); return; } if (const auto * col = checkAndGetColumn(*column)) { res.resize_fill(col->size(), reverse ? !null_value : null_value); return; } if (const auto * col = checkAndGetColumn(*column)) { const PaddedPODArray & null_map = checkAndGetColumn(*col->getNullMapColumnPtr())->getData(); return getMaskFromColumn(col->getNestedColumnPtr(), res, reverse, &null_map, null_value); } if (const auto * col = checkAndGetColumn(*column)) return getMaskFromColumn(col->convertToFullColumn(), res, reverse, null_bytemap, null_value); if (!tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value) && !tryGetMaskFromColumn(column, res, reverse, null_bytemap, null_value)) throw Exception("Cannot convert column " + column.get()->getName() + " to mask", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT); } template void binaryMasksOperationImpl(PaddedPODArray & mask1, const PaddedPODArray & mask2, Op operation) { if (mask1.size() != mask2.size()) throw Exception("Masks have different sizes", ErrorCodes::LOGICAL_ERROR); for (size_t i = 0; i != mask1.size(); ++i) mask1[i] = operation(mask1[i], mask2[i]); } void conjunctionMasks(PaddedPODArray & mask1, const PaddedPODArray & mask2) { binaryMasksOperationImpl(mask1, mask2, [](const auto & lhs, const auto & rhs){ return lhs & rhs; }); } void disjunctionMasks(PaddedPODArray & mask1, const PaddedPODArray & mask2) { binaryMasksOperationImpl(mask1, mask2, [](const auto & lhs, const auto & rhs){ return lhs | rhs; }); } void maskedExecute(ColumnWithTypeAndName & column, const PaddedPODArray & mask, bool reverse, const UInt8 * default_value_for_expanding_mask) { const auto * column_function = checkAndGetColumn(*column.column); if (!column_function) return; auto filtered = column_function->filter(mask, -1, reverse); auto result = typeid_cast(filtered.get())->reduce(true); if (default_value_for_expanding_mask) { result.column = result.column->convertToFullColumnIfLowCardinality(); result.column = result.column->convertToFullColumnIfConst(); expandMaskColumnByMask(result.column, mask, reverse, *default_value_for_expanding_mask); } else expandColumnByMask(result.column, mask, reverse); column = std::move(result); } void executeColumnIfNeeded(ColumnWithTypeAndName & column) { const auto * column_function = checkAndGetColumn(*column.column); if (!column_function) return; column = typeid_cast(column_function)->reduce(true); } bool checkArgumentsForColumnFunction(const ColumnsWithTypeAndName & arguments) { for (const auto & arg : arguments) { if (checkAndGetColumn(*arg.column)) return true; } return false; } }