@@ -1203,8 +1203,8 @@ private static boolean notEqualsIsRemovableFromConjunction(NotEquals notEquals,
12031203 * 2. a == 1 OR a IN (2) becomes a IN (1, 2)
12041204 * 3. a IN (1) OR a IN (2) becomes a IN (1, 2)
12051205 *
1206- * This rule does NOT check for type compatibility as that phase has been
1207- * already be verified in the analyzer.
1206+ * By default (see {@link #shouldValidateIn()}), this rule does NOT check for type compatibility as that phase has
1207+ * already been verified in the analyzer, but this behavior can be changed by subclasses .
12081208 */
12091209 public static class CombineDisjunctionsToIn extends OptimizerExpressionRule <Or > {
12101210 public CombineDisjunctionsToIn () {
@@ -1214,7 +1214,7 @@ public CombineDisjunctionsToIn() {
12141214 @ Override
12151215 protected Expression rule (Or or ) {
12161216 Expression e = or ;
1217- // look only at equals and In
1217+ // look only at Equals and In
12181218 List <Expression > exps = splitOr (e );
12191219
12201220 Map <Expression , Set <Expression >> found = new LinkedHashMap <>();
@@ -1223,7 +1223,7 @@ protected Expression rule(Or or) {
12231223
12241224 for (Expression exp : exps ) {
12251225 if (exp instanceof Equals eq ) {
1226- // consider only equals against foldables
1226+ // consider only Equals against foldables
12271227 if (eq .right ().foldable ()) {
12281228 found .computeIfAbsent (eq .left (), k -> new LinkedHashSet <>()).add (eq .right ());
12291229 } else {
@@ -1243,10 +1243,30 @@ protected Expression rule(Or or) {
12431243 }
12441244
12451245 if (found .isEmpty () == false ) {
1246- // combine equals alongside the existing ors
1246+ // combine Equals alongside the existing ORs
12471247 final ZoneId finalZoneId = zoneId ;
12481248 found .forEach (
1249- (k , v ) -> { ors .add (v .size () == 1 ? createEquals (k , v , finalZoneId ) : createIn (k , new ArrayList <>(v ), finalZoneId )); }
1249+ (k , v ) -> {
1250+ if (v .size () == 1 ) {
1251+ ors .add (createEquals (k , v .iterator ().next (), finalZoneId ));
1252+ } else {
1253+ In in = createIn (k , new ArrayList <>(v ), finalZoneId );
1254+ // IN has its own particularities when it comes to type resolution and not all implementations
1255+ // double check the validity of an internally created IN (like the one created here). EQL is one where the IN
1256+ // implementation is like this mechanism here has been specifically created for it
1257+ if (shouldValidateIn ()) {
1258+ Expression .TypeResolution resolution = in .validateInTypes ();
1259+ if (resolution .unresolved ()) {
1260+ // if the created In is not valid, fall back to regular Equals combined with ORs
1261+ in .list ().forEach (inValue -> ors .add (createEquals (k , inValue , finalZoneId )));
1262+ } else {
1263+ ors .add (in );
1264+ }
1265+ } else {
1266+ ors .add (in );
1267+ }
1268+ }
1269+ }
12501270 );
12511271
12521272 Expression combineOr = combineOr (ors );
@@ -1261,13 +1281,17 @@ protected Expression rule(Or or) {
12611281 return e ;
12621282 }
12631283
1264- protected Equals createEquals (Expression k , Set <Expression > v , ZoneId finalZoneId ) {
1265- return new Equals (k .source (), k , v .iterator ().next (), finalZoneId );
1266- }
1267-
12681284 protected In createIn (Expression key , List <Expression > values , ZoneId zoneId ) {
12691285 return new In (key .source (), key , values , zoneId );
12701286 }
1287+
1288+ protected boolean shouldValidateIn () {
1289+ return false ;
1290+ }
1291+
1292+ private Equals createEquals (Expression key , Expression value , ZoneId finalZoneId ) {
1293+ return new Equals (key .source (), key , value , finalZoneId );
1294+ }
12711295 }
12721296
12731297 public static class PushDownAndCombineFilters extends OptimizerRule <Filter > {
0 commit comments