Skip to content

Commit b4ef2d5

Browse files
committed
YQL-19747: Complete columns from JOIN
Collect tables with aliases during global analysis and send a multiple requests to a schema provider. commit_hash:51cbc40cee6cda09d5bfe256a0425e7c809c04f5
1 parent 98b1e58 commit b4ef2d5

File tree

9 files changed

+125
-29
lines changed

9 files changed

+125
-29
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ namespace NSQLComplete {
5656

5757
class TInferenceVisitor: public SQLv1Antlr4BaseVisitor {
5858
public:
59+
std::any visitJoin_source(SQLv1::Join_sourceContext* ctx) override {
60+
TColumnContext united;
61+
for (SQLv1::Flatten_sourceContext* ctx : ctx->flatten_source()) {
62+
std::any any = visit(ctx);
63+
if (!any.has_value()) {
64+
continue;
65+
}
66+
67+
TColumnContext child = std::move(std::any_cast<TColumnContext>(any));
68+
united = United(std::move(united), std::move(child));
69+
}
70+
return united;
71+
}
72+
5973
std::any visitNamed_single_source(SQLv1::Named_single_sourceContext* ctx) override {
6074
SQLv1::Single_sourceContext* singleSource = ctx->single_source();
6175
if (singleSource == nullptr) {
@@ -107,6 +121,13 @@ namespace NSQLComplete {
107121

108122
return context;
109123
}
124+
125+
static TColumnContext United(TColumnContext&& lhs, TColumnContext&& rhs) {
126+
lhs.Tables.reserve(lhs.Tables.size() + rhs.Tables.size());
127+
std::move(rhs.Tables.begin(), rhs.Tables.end(), std::back_inserter(lhs.Tables));
128+
SortUnique(lhs.Tables);
129+
return lhs;
130+
}
110131
};
111132

112133
class TVisitor: public TSQLv1NarrowingVisitor {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ namespace NSQLComplete {
1717
TString Cluster;
1818
};
1919

20-
template <std::regular T>
20+
template <class T>
21+
requires std::regular<T> &&
22+
requires(T x) { {x < x} -> std::convertible_to<bool>; }
2123
struct TAliased: T {
2224
TString Alias;
2325

@@ -32,6 +34,10 @@ namespace NSQLComplete {
3234
{
3335
}
3436

37+
friend bool operator<(const TAliased& lhs, const TAliased& rhs) {
38+
return std::tie(lhs.Alias, static_cast<const T&>(lhs)) < std::tie(rhs.Alias, static_cast<const T&>(rhs));
39+
}
40+
3541
friend bool operator==(const TAliased& lhs, const TAliased& rhs) = default;
3642
};
3743

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,27 @@ Y_UNIT_TEST_SUITE(GlobalAnalysisTests) {
126126
}
127127
}
128128

129+
Y_UNIT_TEST(Join) {
130+
IGlobalAnalysis::TPtr global = MakeGlobalAnalysis();
131+
{
132+
TString query = R"(
133+
SELECT #
134+
FROM q.a AS x, p.b, c
135+
JOIN p.d AS y ON x.key = y.key
136+
)";
137+
138+
TGlobalContext ctx = global->Analyze(SharpedInput(query), {});
139+
140+
TColumnContext expected = {
141+
.Tables = {
142+
TAliased<TTableId>("", {"", "c"}),
143+
TAliased<TTableId>("", {"p", "b"}),
144+
TAliased<TTableId>("x", {"q", "a"}),
145+
TAliased<TTableId>("y", {"p", "d"}),
146+
},
147+
};
148+
UNIT_ASSERT_VALUES_EQUAL(ctx.Column, expected);
149+
}
150+
}
151+
129152
} // Y_UNIT_TEST_SUITE(GlobalAnalysisTests)

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
#include <util/stream/output.h>
44

5+
namespace NSQLComplete {
6+
7+
bool operator<(const TTableId& lhs, const TTableId& rhs) {
8+
return std::tie(lhs.Cluster, lhs.Path) < std::tie(rhs.Cluster, rhs.Path);
9+
}
10+
11+
} // namespace NSQLComplete
12+
513
template <>
614
void Out<NSQLComplete::TTableId>(IOutputStream& out, const NSQLComplete::TTableId& value) {
715
out << value.Cluster << ".`" << value.Path << "`";

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace NSQLComplete {
1414
TString Cluster;
1515
TString Path;
1616

17+
friend bool operator<(const TTableId& lhs, const TTableId& rhs);
1718
friend bool operator==(const TTableId& lhs, const TTableId& rhs) = default;
1819
};
1920

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
namespace NSQLComplete {
1414

15+
// TODO(YQL-19747): Rename to Identifier
1516
struct TIndentifier {
1617
TString Indentifier;
1718
};

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

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include "name_service.h"
22

3+
#include <library/cpp/threading/future/wait/wait.h>
4+
#include <library/cpp/iterator/functools.h>
5+
36
namespace NSQLComplete {
47

58
namespace {
@@ -19,24 +22,47 @@ namespace NSQLComplete {
1922
}
2023

2124
if (request.Constraints.Column && !request.Constraints.Column->Tables.empty()) {
22-
Y_ENSURE(request.Constraints.Column->Tables.size() == 1, "Not Implemented");
23-
TTableId table = request.Constraints.Column->Tables[0];
24-
return Schema_
25-
->Describe({
26-
.TableCluster = table.Cluster,
27-
.TablePath = table.Path,
28-
.ColumnPrefix = request.Prefix,
29-
.ColumnsLimit = request.Limit,
30-
})
31-
.Apply([table = std::move(table)](auto f) {
32-
return ToDescribeNameResponse(std::move(f), std::move(table));
33-
});
25+
return BatchDescribe(
26+
std::move(request.Constraints.Column->Tables),
27+
request.Prefix,
28+
request.Limit);
3429
}
3530

3631
return NThreading::MakeFuture<TNameResponse>({});
3732
}
3833

3934
private:
35+
NThreading::TFuture<TNameResponse> BatchDescribe(
36+
TVector<TTableId> tables, TString prefix, ui64 limit) const {
37+
TVector<NThreading::TFuture<TDescribeTableResponse>> futures;
38+
for (const auto& table : tables) {
39+
TDescribeTableRequest request = {
40+
.TableCluster = table.Cluster,
41+
.TablePath = table.Path,
42+
.ColumnPrefix = prefix,
43+
.ColumnsLimit = limit,
44+
};
45+
futures.emplace_back(Schema_->Describe(request));
46+
}
47+
48+
return NThreading::WaitAll(futures).Apply([tables, futures](auto) mutable {
49+
TNameResponse response;
50+
51+
for (auto [table, f] : NFuncTools::Zip(tables, futures)) {
52+
TDescribeTableResponse description = f.ExtractValue();
53+
for (TString& column : description.Columns) {
54+
TColumnName name;
55+
name.Indentifier = std::move(column);
56+
name.Table = table;
57+
58+
response.RankedNames.emplace_back(std::move(name));
59+
}
60+
}
61+
62+
return response;
63+
});
64+
}
65+
4066
static TListRequest ToListRequest(TNameRequest request) {
4167
return {
4268
.Cluster = ClusterName(*request.Constraints.Object),
@@ -98,21 +124,6 @@ namespace NSQLComplete {
98124
return name;
99125
}
100126

101-
static TNameResponse ToDescribeNameResponse(
102-
NThreading::TFuture<TDescribeTableResponse> f,
103-
TTableId table) {
104-
TDescribeTableResponse info = f.ExtractValue();
105-
106-
TNameResponse response;
107-
for (TString& column : info.Columns) {
108-
TColumnName name;
109-
name.Indentifier = std::move(column);
110-
name.Table = table;
111-
response.RankedNames.emplace_back(std::move(name));
112-
}
113-
return response;
114-
}
115-
116127
ISchema::TPtr Schema_;
117128
};
118129

yql/essentials/sql/v1/complete/name/service/schema/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ SRCS(
77
PEERDIR(
88
yql/essentials/sql/v1/complete/name/object
99
yql/essentials/sql/v1/complete/name/service
10+
library/cpp/iterator
1011
)
1112

1213
END()

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
113113
"Age": {}
114114
}},
115115
"yql": { "type": "Folder", "entries": {
116-
"tutorial": { "type": "Table", "columns": {} }
116+
"tutorial": { "type": "Table", "columns": {
117+
"course": {},
118+
"room": {},
119+
"time": {}
120+
}}
117121
}}
118122
}},
119123
"saurus": { "type": "Folder", "entries": {
@@ -1117,6 +1121,26 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) {
11171121
}
11181122
}
11191123

1124+
Y_UNIT_TEST(ColumnsAtJoin) {
1125+
auto engine = MakeSqlCompletionEngineUT();
1126+
{
1127+
TString query = R"(
1128+
SELECT #
1129+
FROM example.`/people` AS ep
1130+
JOIN example.`/yql/tutorial` AS et ON 1 = 1
1131+
)";
1132+
1133+
TVector<TCandidate> expected = {
1134+
{ColumnName, "ep.Age"},
1135+
{ColumnName, "ep.Name"},
1136+
{ColumnName, "et.course"},
1137+
{ColumnName, "et.room"},
1138+
{ColumnName, "et.time"},
1139+
};
1140+
UNIT_ASSERT_VALUES_EQUAL(CompleteTop(5, engine, query), expected);
1141+
}
1142+
}
1143+
11201144
Y_UNIT_TEST(Typing) {
11211145
const auto queryUtf16 = TUtf16String::FromUtf8(
11221146
"SELECT \n"

0 commit comments

Comments
 (0)