Skip to content

Commit 0ac6c9e

Browse files
committed
YQL-19747: Support table aliases
commit_hash:6d67ec1fa5023083debd89aaa99950019ca37c90
1 parent 93d0e40 commit 0ac6c9e

File tree

11 files changed

+176
-20
lines changed

11 files changed

+176
-20
lines changed

yql/essentials/sql/v1/complete/analysis/global/column.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ namespace NSQLComplete {
5656

5757
class TInferenceVisitor: public SQLv1Antlr4BaseVisitor {
5858
public:
59+
std::any visitNamed_single_source(SQLv1::Named_single_sourceContext* ctx) override {
60+
SQLv1::Single_sourceContext* singleSource = ctx->single_source();
61+
if (singleSource == nullptr) {
62+
return {};
63+
}
64+
65+
std::any any = visit(singleSource);
66+
if (!any.has_value()) {
67+
return {};
68+
}
69+
TColumnContext context = std::move(std::any_cast<TColumnContext>(any));
70+
71+
TMaybe<TString> alias = GetAlias(ctx);
72+
if (alias.Empty()) {
73+
return context;
74+
}
75+
76+
return Renamed(std::move(context), *alias);
77+
}
78+
5979
std::any visitTable_ref(SQLv1::Table_refContext* ctx) override {
6080
TString cluster = GetId(ctx->cluster_expr()).GetOrElse("");
6181

@@ -66,10 +86,27 @@ namespace NSQLComplete {
6686

6787
return TColumnContext{
6888
.Tables = {
69-
{.Cluster = std::move(cluster), .Path = std::move(*path)},
89+
TTableId{std::move(cluster), std::move(*path)},
7090
},
7191
};
7292
}
93+
94+
private:
95+
TMaybe<TString> GetAlias(SQLv1::Named_single_sourceContext* ctx) const {
96+
TMaybe<TString> alias = GetId(ctx->an_id());
97+
alias = alias.Defined() ? alias : GetId(ctx->an_id_as_compat());
98+
return alias;
99+
}
100+
101+
TColumnContext Renamed(TColumnContext context, TString alias) {
102+
Y_ENSURE(!alias.empty());
103+
104+
for (TAliased<TTableId>& table : context.Tables) {
105+
table.Alias = alias;
106+
}
107+
108+
return context;
109+
}
73110
};
74111

75112
class TVisitor: public TSQLv1NarrowingVisitor {

yql/essentials/sql/v1/complete/analysis/global/global.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515

1616
namespace NSQLComplete {
1717

18+
TVector<TTableId> TColumnContext::TablesWithAlias(TStringBuf alias) const {
19+
if (alias.empty()) {
20+
return TVector<TTableId>(Tables.begin(), Tables.end());
21+
}
22+
23+
auto filtered = NFuncTools::Filter([&](const auto& x) { return x.Alias == alias; }, Tables);
24+
return TVector<TTableId>(filtered.begin(), filtered.end());
25+
}
26+
1827
class TErrorStrategy: public antlr4::DefaultErrorStrategy {
1928
public:
2029
antlr4::Token* singleTokenDeletion(antlr4::Parser* /* recognizer */) override {
@@ -116,6 +125,12 @@ namespace NSQLComplete {
116125

117126
} // namespace NSQLComplete
118127

128+
template <>
129+
void Out<NSQLComplete::TAliased<NSQLComplete::TTableId>>(IOutputStream& out, const NSQLComplete::TAliased<NSQLComplete::TTableId>& value) {
130+
Out<NSQLComplete::TTableId>(out, value);
131+
out << " AS " << value.Alias;
132+
}
133+
119134
template <>
120135
void Out<NSQLComplete::TColumnContext>(IOutputStream& out, const NSQLComplete::TColumnContext& value) {
121136
out << "TColumnContext { ";

yql/essentials/sql/v1/complete/analysis/global/global.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <util/generic/maybe.h>
99
#include <util/generic/string.h>
1010
#include <util/generic/vector.h>
11+
#include <util/generic/hash.h>
1112

1213
namespace NSQLComplete {
1314

@@ -16,8 +17,28 @@ namespace NSQLComplete {
1617
TString Cluster;
1718
};
1819

20+
template <std::regular T>
21+
struct TAliased: T {
22+
TString Alias;
23+
24+
TAliased(TString alias, T value)
25+
: T(std::move(value))
26+
, Alias(std::move(alias))
27+
{
28+
}
29+
30+
TAliased(T value)
31+
: T(std::move(value))
32+
{
33+
}
34+
35+
friend bool operator==(const TAliased& lhs, const TAliased& rhs) = default;
36+
};
37+
1938
struct TColumnContext {
20-
TVector<TTableId> Tables;
39+
TVector<TAliased<TTableId>> Tables;
40+
41+
TVector<TTableId> TablesWithAlias(TStringBuf alias) const;
2142

2243
friend bool operator==(const TColumnContext& lhs, const TColumnContext& rhs) = default;
2344
};

yql/essentials/sql/v1/complete/analysis/global/global_ut.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,23 @@ Y_UNIT_TEST_SUITE(GlobalAnalysisTests) {
105105

106106
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
107107

108-
TColumnContext expected = {.Tables = {{"plato", "Input"}}};
108+
TColumnContext expected = {.Tables = {TTableId{"plato", "Input"}}};
109109
UNIT_ASSERT_VALUES_EQUAL(ctx.Column, expected);
110110
}
111111
{
112112
TString query = "SELECT # FROM plato.`//home/input`";
113113

114114
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
115115

116-
TColumnContext expected = {.Tables = {{"plato", "//home/input"}}};
116+
TColumnContext expected = {.Tables = {TTableId{"plato", "//home/input"}}};
117+
UNIT_ASSERT_VALUES_EQUAL(ctx.Column, expected);
118+
}
119+
{
120+
TString query = "SELECT # FROM plato.Input AS x";
121+
122+
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
123+
124+
TColumnContext expected = {.Tables = {TAliased<TTableId>("x", TTableId{"plato", "Input"})}};
117125
UNIT_ASSERT_VALUES_EQUAL(ctx.Column, expected);
118126
}
119127
}

yql/essentials/sql/v1/complete/analysis/local/local.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ namespace NSQLComplete {
107107
result.Hint = HintMatch(candidates);
108108
result.Object = ObjectMatch(context, candidates);
109109
result.Cluster = ClusterMatch(context, candidates);
110-
result.Column = ColumnMatch(candidates);
110+
result.Column = ColumnMatch(context, candidates);
111111
result.Binding = BindingMatch(candidates);
112112

113113
return result;
@@ -322,8 +322,19 @@ namespace NSQLComplete {
322322
return cluster;
323323
}
324324

325-
bool ColumnMatch(const TC3Candidates& candidates) const {
326-
return AnyOf(candidates.Rules, RuleAdapted(IsLikelyColumnStack));
325+
TMaybe<TLocalSyntaxContext::TColumn> ColumnMatch(
326+
const TCursorTokenContext& context, const TC3Candidates& candidates) const {
327+
if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyColumnStack))) {
328+
return Nothing();
329+
}
330+
331+
TLocalSyntaxContext::TColumn column;
332+
if (TMaybe<TRichParsedToken> begin;
333+
(begin = context.MatchCursorPrefix({"ID_PLAIN", "DOT"})) ||
334+
(begin = context.MatchCursorPrefix({"ID_PLAIN", "DOT", ""}))) {
335+
column.Table = begin->Base->Content;
336+
}
337+
return column;
327338
}
328339

329340
bool BindingMatch(const TC3Candidates& candidates) const {

yql/essentials/sql/v1/complete/analysis/local/local.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,18 @@ namespace NSQLComplete {
4848
}
4949
};
5050

51+
struct TColumn {
52+
TString Table;
53+
};
54+
5155
TKeywords Keywords;
5256
TMaybe<TPragma> Pragma;
5357
bool Type = false;
5458
TMaybe<TFunction> Function;
5559
TMaybe<THint> Hint;
5660
TMaybe<TObject> Object;
5761
TMaybe<TCluster> Cluster;
58-
bool Column = false;
62+
TMaybe<TColumn> Column;
5963
bool Binding = false;
6064
TEditRange EditRange;
6165
};

yql/essentials/sql/v1/complete/core/name.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <util/generic/string.h>
4+
#include <util/generic/hash.h>
45

56
namespace NSQLComplete {
67

@@ -17,3 +18,10 @@ namespace NSQLComplete {
1718
};
1819

1920
} // namespace NSQLComplete
21+
22+
template <>
23+
struct THash<NSQLComplete::TTableId> {
24+
inline size_t operator()(const NSQLComplete::TTableId& x) const {
25+
return THash<std::tuple<TString, TString>>()(std::tie(x.Cluster, x.Path));
26+
}
27+
};

yql/essentials/sql/v1/complete/name/service/name_service.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ namespace NSQLComplete {
7070
struct TConstraints {
7171
TVector<TTableId> Tables;
7272
};
73+
74+
TTableId Table;
7375
};
7476

7577
struct TBindingName: TIndentifier {

yql/essentials/sql/v1/complete/name/service/schema/name_service.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace NSQLComplete {
1818
.Apply(ToListNameResponse);
1919
}
2020

21-
if (request.Constraints.Column) {
21+
if (request.Constraints.Column && !request.Constraints.Column->Tables.empty()) {
2222
Y_ENSURE(request.Constraints.Column->Tables.size() == 1, "Not Implemented");
2323
TTableId table = request.Constraints.Column->Tables[0];
2424
return Schema_
@@ -28,7 +28,9 @@ namespace NSQLComplete {
2828
.ColumnPrefix = request.Prefix,
2929
.ColumnsLimit = request.Limit,
3030
})
31-
.Apply(ToDescribeNameResponse);
31+
.Apply([table = std::move(table)](auto f) {
32+
return ToDescribeNameResponse(std::move(f), std::move(table));
33+
});
3234
}
3335

3436
return NThreading::MakeFuture<TNameResponse>({});
@@ -96,13 +98,16 @@ namespace NSQLComplete {
9698
return name;
9799
}
98100

99-
static TNameResponse ToDescribeNameResponse(NThreading::TFuture<TDescribeTableResponse> f) {
100-
TDescribeTableResponse table = f.ExtractValue();
101+
static TNameResponse ToDescribeNameResponse(
102+
NThreading::TFuture<TDescribeTableResponse> f,
103+
TTableId table) {
104+
TDescribeTableResponse info = f.ExtractValue();
101105

102106
TNameResponse response;
103-
for (TString& column : table.Columns) {
107+
for (TString& column : info.Columns) {
104108
TColumnName name;
105109
name.Indentifier = std::move(column);
110+
name.Table = table;
106111
response.RankedNames.emplace_back(std::move(name));
107112
}
108113
return response;

yql/essentials/sql/v1/complete/sql_complete.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ namespace NSQLComplete {
6868

6969
return MakeUnionNameService(std::move(children), MakeDummyRanking())
7070
->Lookup(std::move(request))
71-
.Apply([this, input, context = std::move(context)](auto f) {
72-
return ToCompletion(input, context, f.ExtractValue());
71+
.Apply([this, input, context = std::move(context), global = std::move(global)](auto f) {
72+
return ToCompletion(input, std::move(context), global, f.ExtractValue());
7373
});
7474
}
7575

@@ -148,7 +148,7 @@ namespace NSQLComplete {
148148

149149
if (context.Column && global.Column) {
150150
request.Constraints.Column = TColumnName::TConstraints();
151-
request.Constraints.Column->Tables = std::move(global.Column->Tables);
151+
request.Constraints.Column->Tables = global.Column->TablesWithAlias(context.Column->Table);
152152
}
153153

154154
return request;
@@ -157,10 +157,11 @@ namespace NSQLComplete {
157157
TCompletion ToCompletion(
158158
TCompletionInput input,
159159
TLocalSyntaxContext context,
160+
const TGlobalContext& global,
160161
TNameResponse response) const {
161162
TCompletion completion = {
162163
.CompletedToken = GetCompletedToken(input, context.EditRange),
163-
.Candidates = Convert(std::move(response.RankedNames), std::move(context)),
164+
.Candidates = Convert(std::move(response.RankedNames), std::move(context), global),
164165
};
165166

166167
if (response.NameHintLength) {
@@ -175,16 +176,33 @@ namespace NSQLComplete {
175176
return completion;
176177
}
177178

178-
static TVector<TCandidate> Convert(TVector<TGenericName> names, TLocalSyntaxContext context) {
179+
static TVector<TCandidate> Convert(
180+
TVector<TGenericName> names,
181+
TLocalSyntaxContext context,
182+
const TGlobalContext& global) {
179183
TVector<TCandidate> candidates;
180184
candidates.reserve(names.size());
181185
for (auto& name : names) {
182-
candidates.emplace_back(Convert(std::move(name), context));
186+
candidates.emplace_back(Convert(std::move(name), context, global));
183187
}
184188
return candidates;
185189
}
186190

187-
static TCandidate Convert(TGenericName name, TLocalSyntaxContext& context) {
191+
// TODO(YQL-19747): extract to a separate file
192+
static TCandidate Convert(
193+
TGenericName name,
194+
TLocalSyntaxContext& context,
195+
const TGlobalContext& global) {
196+
// TODO(YQL-19747): support multiple aliases for a single table
197+
THashMap<TTableId, TString> aliasByTable;
198+
global.Column.Transform([&](auto&& column) {
199+
aliasByTable.reserve(column.Tables.size());
200+
for (const auto& table : column.Tables) {
201+
aliasByTable[table] = table.Alias;
202+
}
203+
return std::monostate();
204+
});
205+
188206
return std::visit([&](auto&& name) -> TCandidate {
189207
using T = std::decay_t<decltype(name)>;
190208

@@ -241,6 +259,12 @@ namespace NSQLComplete {
241259
}
242260

243261
if constexpr (std::is_base_of_v<TColumnName, T>) {
262+
const TString& alias = aliasByTable.at(name.Table);
263+
if (context.Column->Table.empty() && !alias.empty()) {
264+
name.Indentifier.prepend('.');
265+
name.Indentifier.prepend(alias);
266+
}
267+
244268
return {ECandidateKind::ColumnName, std::move(name.Indentifier)};
245269
}
246270

0 commit comments

Comments
 (0)