1#include <Functions/FunctionFactory.h>
2#include <Functions/GeoUtils.h>
3#include <Functions/FunctionHelpers.h>
4
5#include <Columns/ColumnString.h>
6#include <Columns/ColumnFixedString.h>
7#include <Columns/ColumnsNumber.h>
8#include <Columns/ColumnTuple.h>
9#include <DataTypes/DataTypeString.h>
10#include <DataTypes/DataTypeTuple.h>
11#include <DataTypes/DataTypesNumber.h>
12
13#include <string>
14
15
16namespace DB
17{
18
19namespace ErrorCodes
20{
21 extern const int ILLEGAL_COLUMN;
22}
23
24
25// geohashDecode(string) => (lon float64, lat float64)
26class FunctionGeohashDecode : public IFunction
27{
28public:
29 static constexpr auto name = "geohashDecode";
30 static FunctionPtr create(const Context &) { return std::make_shared<FunctionGeohashDecode>(); }
31
32 String getName() const override
33 {
34 return name;
35 }
36
37 size_t getNumberOfArguments() const override { return 1; }
38 bool useDefaultImplementationForConstants() const override { return true; }
39
40 DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
41 {
42 validateArgumentType(*this, arguments, 0, isStringOrFixedString, "string or fixed string");
43
44 return std::make_shared<DataTypeTuple>(
45 DataTypes{std::make_shared<DataTypeFloat64>(), std::make_shared<DataTypeFloat64>()},
46 Strings{"longitude", "latitude"});
47 }
48
49 template <typename ColumnTypeEncoded>
50 bool tryExecute(const IColumn * encoded_column, ColumnPtr & result_column)
51 {
52 const auto * encoded = checkAndGetColumn<ColumnTypeEncoded>(encoded_column);
53 if (!encoded)
54 return false;
55
56 const size_t count = encoded->size();
57
58 auto latitude = ColumnFloat64::create(count);
59 auto longitude = ColumnFloat64::create(count);
60
61 ColumnFloat64::Container & lon_data = longitude->getData();
62 ColumnFloat64::Container & lat_data = latitude->getData();
63
64 for (size_t i = 0; i < count; ++i)
65 {
66 StringRef encoded_string = encoded->getDataAt(i);
67 GeoUtils::geohashDecode(encoded_string.data, encoded_string.size, &lon_data[i], &lat_data[i]);
68 }
69
70 MutableColumns result;
71 result.emplace_back(std::move(longitude));
72 result.emplace_back(std::move(latitude));
73 result_column = ColumnTuple::create(std::move(result));
74
75 return true;
76 }
77
78 void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result, size_t /*input_rows_count*/) override
79 {
80 const IColumn * encoded = block.getByPosition(arguments[0]).column.get();
81 ColumnPtr & res_column = block.getByPosition(result).column;
82
83 if (tryExecute<ColumnString>(encoded, res_column) ||
84 tryExecute<ColumnFixedString>(encoded, res_column))
85 return;
86
87 throw Exception("Unsupported argument type:" + block.getByPosition(arguments[0]).column->getName()
88 + " of argument of function " + getName(),
89 ErrorCodes::ILLEGAL_COLUMN);
90 }
91};
92
93
94void registerFunctionGeohashDecode(FunctionFactory & factory)
95{
96 factory.registerFunction<FunctionGeohashDecode>();
97}
98
99}
100