aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/sql/settings/partitioning.cpp
blob: 2075e51027b616e20e1accab01c580a9a6798b0e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include "partitioning.h"
#include <yql/essentials/providers/common/provider/yql_provider_names.h>
#include <library/cpp/json/json_reader.h>
#include <util/generic/is_in.h>
#include <util/string/builder.h>

namespace NSQLTranslation {
namespace {

TString ParsePartitionedByBinding(const TString& name, const TString& value, TVector<TString>& columns) {
    using namespace NJson;
    TJsonValue json;
    bool throwOnError = false;
    if (!ReadJsonTree(value, &json, throwOnError)) {
        return TStringBuilder() << "Binding setting " << name << " is not a valid JSON";
    }

    const TJsonValue::TArray* arr = nullptr;
    if (!json.GetArrayPointer(&arr)) {
        return TStringBuilder() << "Binding setting " << name << ": expecting array";
    }

    if (arr->empty()) {
        return TStringBuilder() << "Binding setting " << name << ": expecting non-empty array";
    }

    for (auto& item : *arr) {
        TString str;
        if (!item.GetString(&str)) {
            return TStringBuilder() << "Binding setting " << name << ": expecting non-empty array of strings";
        }
        columns.push_back(std::move(str));
    }

    return {};
}

}

TString ExtractBindingInfo(const TTranslationSettings& settings, const TString& binding, TBindingInfo& result) {
    auto pit = settings.Bindings.find(binding);

    if (pit == settings.Bindings.end()) {
        return TStringBuilder() << "Table binding `" << binding << "` is not defined";
    }

    const auto& bindSettings = pit->second;

    if (!IsIn({NYql::S3ProviderName, NYql::PqProviderName}, bindSettings.ClusterType)) {
        return TStringBuilder() << "Cluster type " << bindSettings.ClusterType << " is not supported for table bindings";
    }
    result.ClusterType = bindSettings.ClusterType;

    // ordered map ensures AST stability
    TMap<TString, TString> kvs(bindSettings.Settings.begin(), bindSettings.Settings.end());
    auto pullSettingOrFail = [&](const TString& name, TString& value) -> TString {
        auto it = kvs.find(name);
        if (it == kvs.end()) {
            return TStringBuilder() << name << " is not found for " << binding;
        }
        value = it->second;
        kvs.erase(it);
        return {};
    };

    if (const auto& error = pullSettingOrFail("cluster", result.Cluster)) {
        return error;
    }
    if (const auto& error = pullSettingOrFail("path", result.Path)) {
        return error;
    }

    if (auto it = kvs.find("schema"); it != kvs.end()) {
        result.Schema = it->second;
        kvs.erase(it);
    }

    if (auto it = kvs.find("partitioned_by"); it != kvs.end()) {
        TVector<TString> columns;
        if (const auto& error = ParsePartitionedByBinding(it->first, it->second, columns)) {
            return error;
        }
        result.Attributes.emplace("partitionedby", std::move(columns));
        kvs.erase(it);
    }

    for (auto& [key, value] : kvs) {
        if (key.empty()) {
            return "Attribute should not be empty";
        }
        result.Attributes.emplace(key, TVector<TString>{value});
    }

    return {};
}

}  // namespace NSQLTranslation