18
18
package org .apache .ignite .internal .processors .query .h2 .sql ;
19
19
20
20
import java .util .HashSet ;
21
+ import java .util .Objects ;
21
22
import java .util .Set ;
22
23
import org .apache .ignite .IgniteLogger ;
23
24
import org .apache .ignite .internal .processors .query .h2 .opt .GridH2Table ;
25
+ import org .jetbrains .annotations .Nullable ;
24
26
25
27
/**
26
28
* Traverse over query AST to find info about partitioned table usage.
@@ -44,6 +46,9 @@ class SqlAstTraverser {
44
46
/** Whether query has joins between replicated and partitioned tables. */
45
47
private boolean hasOuterJoinReplicatedPartitioned ;
46
48
49
+ /** */
50
+ private @ Nullable MixedModeCachesJoinIssue hasOuterJoinMixedCacheModeIssue ;
51
+
47
52
/** Whether top-level table is replicated. */
48
53
private boolean isRootTableReplicated ;
49
54
@@ -86,6 +91,11 @@ public boolean hasReplicatedWithPartitionedAndSubQuery() {
86
91
return (isRootTableReplicated && hasSubQueries && hasPartitionedTables );
87
92
}
88
93
94
+ /** */
95
+ public @ Nullable MixedModeCachesJoinIssue hasOuterJoinMixedCacheModeIssue () {
96
+ return hasOuterJoinMixedCacheModeIssue ;
97
+ }
98
+
89
99
/**
90
100
* Traverse AST while join operation isn't found. Check it if found.
91
101
*
@@ -168,8 +178,24 @@ else if (ast instanceof GridSqlTable)
168
178
if (left == null || right == null )
169
179
return ;
170
180
171
- if (join .isLeftOuter () && !left .isPartitioned () && right .isPartitioned ())
172
- hasOuterJoinReplicatedPartitioned = true ;
181
+ if (join .isLeftOuter () && !left .isPartitioned () && right .isPartitioned ()) {
182
+ if (left .cacheContext ().affinity ().partitions () != right .cacheContext ().affinity ().partitions ()) {
183
+ hasOuterJoinMixedCacheModeIssue = new MixedModeCachesJoinIssue ("Cache [cacheName=" + left .cacheName () +
184
+ ", partitionsCount=" + left .cacheContext ().affinity ().partitions () +
185
+ "] can`t be joined with [cacheName=" + right .cacheName () +
186
+ ", partitionsCount=" + right .cacheContext ().affinity ().partitions () +
187
+ "] due to different affinity configuration. Join between PARTITIONED and REPLICATED caches is possible "
188
+ + "only with the same partitions number configuration." );
189
+ }
190
+ // the only way to compare predicate classes, not work for different class loaders.
191
+ else if (!Objects .equals (className (left .cacheInfo ().config ().getNodeFilter ()), className (right .cacheInfo ().config ()
192
+ .getNodeFilter ()))) {
193
+ hasOuterJoinMixedCacheModeIssue = new MixedModeCachesJoinIssue ("Cache [cacheName=" + left .cacheName () + "] "
194
+ + "can`t be joined with [cacheName=" + right .cacheName () + "] due to different node filters configuration." );
195
+ }
196
+ else
197
+ hasOuterJoinReplicatedPartitioned = true ;
198
+ }
173
199
174
200
// Skip check if at least one of tables isn't partitioned.
175
201
if (!(left .isPartitioned () && right .isPartitioned ()))
@@ -179,6 +205,11 @@ else if (ast instanceof GridSqlTable)
179
205
checkPartitionedJoin (join , where , left , right , log );
180
206
}
181
207
208
+ /** Object class name. */
209
+ @ Nullable private static String className (@ Nullable Object obj ) {
210
+ return obj != null ? obj .getClass ().getName () : null ;
211
+ }
212
+
182
213
/**
183
214
* Checks whether an AST contains valid join operation between partitioned tables.
184
215
* Join condition should be an equality operation of affinity keys of tables. Conditions can be splitted between
@@ -242,7 +273,7 @@ private String getAlias(GridSqlElement el) {
242
273
private Set <String > affKeys (boolean pk , GridH2Table tbl ) {
243
274
Set <String > affKeys = new HashSet <>();
244
275
245
- // User explicitly specify an affinity key. Otherwise use primary key.
276
+ // User explicitly specify an affinity key. Otherwise, use primary key.
246
277
if (!pk )
247
278
affKeys .add (tbl .getAffinityKeyColumn ().columnName );
248
279
else {
@@ -279,7 +310,7 @@ private boolean checkPartitionedCondition(GridSqlElement condition,
279
310
if (GridSqlOperationType .EQUAL == op .operationType ())
280
311
checkEqualityOperation (op , leftTbl , leftAffKeys , pkLeft , rightTbl , rightAffKeys , pkRight );
281
312
282
- // Check affinity condition is covered fully. If true then return. Otherwise go deeper.
313
+ // Check affinity condition is covered fully. If true then return. Otherwise, go deeper.
283
314
if (affinityCondIsCovered (leftAffKeys , rightAffKeys ))
284
315
return true ;
285
316
@@ -342,4 +373,29 @@ private void checkEqualityOperation(GridSqlOperation equalOp,
342
373
private boolean affinityCondIsCovered (Set <String > leftAffKeys , Set <String > rightAffKeys ) {
343
374
return leftAffKeys .isEmpty () && rightAffKeys .isEmpty ();
344
375
}
376
+
377
+ /** Mixed cache mode join issues. */
378
+ static class MixedModeCachesJoinIssue {
379
+ /** */
380
+ private final boolean err ;
381
+
382
+ /** */
383
+ private final String msg ;
384
+
385
+ /** Constructor. */
386
+ MixedModeCachesJoinIssue (String errMsg ) {
387
+ err = true ;
388
+ msg = errMsg ;
389
+ }
390
+
391
+ /** Return {@code true} if error present. */
392
+ boolean error () {
393
+ return err ;
394
+ }
395
+
396
+ /** Return appropriate error message. */
397
+ String errorMessage () {
398
+ return msg ;
399
+ }
400
+ }
345
401
}
0 commit comments