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
|