@@ -9,6 +9,8 @@ namespace NSQLTranslationV1 {
9
9
10
10
using namespace NSQLv1Generated ;
11
11
12
+ namespace {
13
+
12
14
bool IsColumnsOnly (const TVector<TSortSpecificationPtr>& container) {
13
15
for (const auto & elem: container) {
14
16
if (!elem->OrderExpr ->GetColumnName ()) {
@@ -18,52 +20,72 @@ bool IsColumnsOnly(const TVector<TSortSpecificationPtr>& container) {
18
20
return true ;
19
21
}
20
22
23
+ bool CollectJoinLinkSettings (TPosition pos, TJoinLinkSettings& linkSettings, TContext& ctx) {
24
+ linkSettings = {};
25
+ auto hints = ctx.PullHintForToken (pos);
26
+ for (const auto & hint: hints) {
27
+ const auto canonizedName = to_lower (hint.Name );
28
+ auto newStrategy = TJoinLinkSettings::EStrategy::Default;
29
+ if (canonizedName == " merge" ) {
30
+ newStrategy = TJoinLinkSettings::EStrategy::SortedMerge;
31
+ } else if (canonizedName == " streamlookup" ) {
32
+ newStrategy = TJoinLinkSettings::EStrategy::StreamLookup;
33
+ } else if (canonizedName == " map" ) {
34
+ newStrategy = TJoinLinkSettings::EStrategy::ForceMap;
35
+ } else if (canonizedName == " grace" ) {
36
+ newStrategy = TJoinLinkSettings::EStrategy::ForceGrace;
37
+ } else {
38
+ ctx.Warning (hint.Pos , TIssuesIds::YQL_UNUSED_HINT) << " Unsupported join strategy: " << hint.Name ;
39
+ }
40
+
41
+ if (TJoinLinkSettings::EStrategy::Default == linkSettings.Strategy ) {
42
+ linkSettings.Strategy = newStrategy;
43
+ } else if (newStrategy == linkSettings.Strategy ) {
44
+ ctx.Error () << " Duplicate join strategy hint" ;
45
+ return false ;
46
+ } else {
47
+ ctx.Error () << " Conflicting join strategy hints" ;
48
+ return false ;
49
+ }
50
+ }
51
+ return true ;
52
+ }
53
+
54
+ } // namespace
55
+
21
56
bool TSqlSelect::JoinOp (ISource* join, const TRule_join_source::TBlock3& block, TMaybe<TPosition> anyPos) {
22
57
// block: (join_op (ANY)? flatten_source join_constraint?)
23
58
// join_op:
24
59
// COMMA
25
60
// | (NATURAL)? ((LEFT (ONLY | SEMI)? | RIGHT (ONLY | SEMI)? | EXCLUSION | FULL)? (OUTER)? | INNER | CROSS) JOIN
26
61
// ;
27
62
const auto & node = block.GetRule_join_op1 ();
63
+ TString joinOp (" Inner" );
64
+ TJoinLinkSettings linkSettings;
28
65
switch (node.Alt_case ()) {
29
- case TRule_join_op::kAltJoinOp1 :
66
+ case TRule_join_op::kAltJoinOp1 : {
67
+ joinOp = " Cross" ;
68
+ if (!Ctx.AnsiImplicitCrossJoin ) {
69
+ Error () << " Cartesian product of tables is disabled. Please use "
70
+ " explicit CROSS JOIN or enable it via PRAGMA AnsiImplicitCrossJoin" ;
71
+ return false ;
72
+ }
73
+ auto alt = node.GetAlt_join_op1 ();
74
+ if (!CollectJoinLinkSettings (Ctx.TokenPosition (alt.GetToken1 ()), linkSettings, Ctx)) {
75
+ return false ;
76
+ }
30
77
Ctx.IncrementMonCounter (" sql_join_operations" , " CartesianProduct" );
31
- Error () << " Cartesian product of tables is not supported. Please use explicit CROSS JOIN " ;
32
- return false ;
78
+ break ;
79
+ }
33
80
case TRule_join_op::kAltJoinOp2 : {
34
81
auto alt = node.GetAlt_join_op2 ();
35
82
if (alt.HasBlock1 ()) {
36
83
Ctx.IncrementMonCounter (" sql_join_operations" , " Natural" );
37
84
Error () << " Natural join is not implemented yet" ;
38
85
return false ;
39
86
}
40
- TString joinOp (" Inner" );
41
- auto hints = Ctx.PullHintForToken (Ctx.TokenPosition (alt.GetToken3 ()));
42
- TJoinLinkSettings linkSettings;
43
- for (const auto & hint: hints) {
44
- const auto canonizedName = to_lower (hint.Name );
45
- auto newStrategy = TJoinLinkSettings::EStrategy::Default;
46
- if (canonizedName == " merge" ) {
47
- newStrategy = TJoinLinkSettings::EStrategy::SortedMerge;
48
- } else if (canonizedName == " streamlookup" ) {
49
- newStrategy = TJoinLinkSettings::EStrategy::StreamLookup;
50
- } else if (canonizedName == " map" ) {
51
- newStrategy = TJoinLinkSettings::EStrategy::ForceMap;
52
- } else if (canonizedName == " grace" ) {
53
- newStrategy = TJoinLinkSettings::EStrategy::ForceGrace;
54
- } else {
55
- Ctx.Warning (hint.Pos , TIssuesIds::YQL_UNUSED_HINT) << " Unsupported join strategy: " << hint.Name ;
56
- }
57
-
58
- if (TJoinLinkSettings::EStrategy::Default == linkSettings.Strategy ) {
59
- linkSettings.Strategy = newStrategy;
60
- } else if (newStrategy == linkSettings.Strategy ) {
61
- Error () << " Duplicate join strategy hint" ;
62
- return false ;
63
- } else {
64
- Error () << " Conflicting join strategy hints" ;
65
- return false ;
66
- }
87
+ if (!CollectJoinLinkSettings (Ctx.TokenPosition (alt.GetToken3 ()), linkSettings, Ctx)) {
88
+ return false ;
67
89
}
68
90
switch (alt.GetBlock2 ().Alt_case ()) {
69
91
case TRule_join_op::TAlt2::TBlock2::kAlt1 :
@@ -122,52 +144,52 @@ bool TSqlSelect::JoinOp(ISource* join, const TRule_join_source::TBlock3& block,
122
144
AltNotImplemented (" join_op" , node);
123
145
return false ;
124
146
}
125
-
126
- joinOp = NormalizeJoinOp (joinOp);
127
147
Ctx.IncrementMonCounter (" sql_features" , " Join" );
128
148
Ctx.IncrementMonCounter (" sql_join_operations" , joinOp);
129
- if (linkSettings.Strategy != TJoinLinkSettings::EStrategy::Default && joinOp == " Cross" ) {
130
- Ctx.Warning (Ctx.Pos (), TIssuesIds::YQL_UNUSED_HINT) << " Non-default join strategy will not be used for CROSS JOIN" ;
131
- linkSettings.Strategy = TJoinLinkSettings::EStrategy::Default;
132
- }
133
-
134
- TNodePtr joinKeyExpr;
135
- if (block.HasBlock4 ()) {
136
- if (joinOp == " Cross" ) {
137
- Error () << " Cross join should not have ON or USING expression" ;
138
- Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
139
- return false ;
140
- }
141
-
142
- joinKeyExpr = JoinExpr (join, block.GetBlock4 ().GetRule_join_constraint1 ());
143
- if (!joinKeyExpr) {
144
- Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
145
- return false ;
146
- }
147
- }
148
- else {
149
- if (joinOp != " Cross" ) {
150
- Error () << " Expected ON or USING expression" ;
151
- Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
152
- return false ;
153
- }
154
- }
155
-
156
- if (joinOp == " Cross" && anyPos) {
157
- Ctx.Error (*anyPos) << " ANY should not be used with Cross JOIN" ;
158
- Ctx.IncrementMonCounter (" sql_errors" , " BadJoinAny" );
159
- return false ;
160
- }
161
-
162
- Y_DEBUG_ABORT_UNLESS (join->GetJoin ());
163
- join->GetJoin ()->SetupJoin (joinOp, joinKeyExpr, linkSettings);
164
149
break ;
165
150
}
166
151
case TRule_join_op::ALT_NOT_SET:
167
152
Ctx.IncrementMonCounter (" sql_errors" , " UnknownJoinOperation2" );
168
153
AltNotImplemented (" join_op" , node);
169
154
return false ;
170
155
}
156
+ joinOp = NormalizeJoinOp (joinOp);
157
+ if (linkSettings.Strategy != TJoinLinkSettings::EStrategy::Default && joinOp == " Cross" ) {
158
+ Ctx.Warning (Ctx.Pos (), TIssuesIds::YQL_UNUSED_HINT) << " Non-default join strategy will not be used for CROSS JOIN" ;
159
+ linkSettings.Strategy = TJoinLinkSettings::EStrategy::Default;
160
+ }
161
+
162
+ TNodePtr joinKeyExpr;
163
+ if (block.HasBlock4 ()) {
164
+ if (joinOp == " Cross" ) {
165
+ Error () << " Cross join should not have ON or USING expression" ;
166
+ Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
167
+ return false ;
168
+ }
169
+
170
+ joinKeyExpr = JoinExpr (join, block.GetBlock4 ().GetRule_join_constraint1 ());
171
+ if (!joinKeyExpr) {
172
+ Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
173
+ return false ;
174
+ }
175
+ }
176
+ else {
177
+ if (joinOp != " Cross" ) {
178
+ Error () << " Expected ON or USING expression" ;
179
+ Ctx.IncrementMonCounter (" sql_errors" , " BadJoinExpr" );
180
+ return false ;
181
+ }
182
+ }
183
+
184
+ if (joinOp == " Cross" && anyPos) {
185
+ Ctx.Error (*anyPos) << " ANY should not be used with Cross JOIN" ;
186
+ Ctx.IncrementMonCounter (" sql_errors" , " BadJoinAny" );
187
+ return false ;
188
+ }
189
+
190
+ Y_DEBUG_ABORT_UNLESS (join->GetJoin ());
191
+ join->GetJoin ()->SetupJoin (joinOp, joinKeyExpr, linkSettings);
192
+
171
193
return true ;
172
194
}
173
195
0 commit comments