8080import static java .util .Objects .requireNonNull ;
8181import static org .apache .calcite .rex .RexUtil .removeCast ;
8282import static org .apache .calcite .rex .RexUtil .sargRef ;
83+ import static org .apache .calcite .sql .SqlKind .AND ;
8384import static org .apache .calcite .sql .SqlKind .EQUALS ;
8485import static org .apache .calcite .sql .SqlKind .GREATER_THAN ;
8586import static org .apache .calcite .sql .SqlKind .GREATER_THAN_OR_EQUAL ;
@@ -97,6 +98,9 @@ public class RexUtils {
9798 /** Maximum amount of search bounds tuples per scan. */
9899 public static final int MAX_SEARCH_BOUNDS_COMPLEXITY = 100 ;
99100
101+ /** Operands limit per call when expanding SEARCH/SARG operator. */
102+ public static final int SEARCH_EXPAND_OPERANDS_LIMIT = 100 ;
103+
100104 /** */
101105 public static RexNode makeCast (RexBuilder builder , RexNode node , RelDataType type ) {
102106 return TypeUtils .needCast (builder .getTypeFactory (), node .getType (), type ) ? builder .makeCast (type , node ) : node ;
@@ -879,7 +883,7 @@ public static RexNode expandSearchNullable(RexBuilder rexBuilder, @Nullable RexP
879883 RexNode op1 = call .getOperands ().get (1 );
880884
881885 if (!op0 .getType ().isNullable ())
882- return RexUtil . expandSearch (rexBuilder , program , call );
886+ return expandSearch (rexBuilder , program , call );
883887
884888 while (op1 instanceof RexLocalRef ) // Dereference local variable.
885889 op1 = requireNonNull (program , "program" ).getExprList ().get (((RexSlot )op1 ).getIndex ());
@@ -892,7 +896,7 @@ public static RexNode expandSearchNullable(RexBuilder rexBuilder, @Nullable RexP
892896 ? rexBuilder .makeLiteral (arg .nullAs .toBoolean ())
893897 : rexBuilder .makeNullLiteral (rexBuilder .getTypeFactory ().createSqlType (SqlTypeName .BOOLEAN ));
894898
895- RexNode expandedSearch = RexUtil . expandSearch (rexBuilder , program ,
899+ RexNode expandedSearch = expandSearch (rexBuilder , program ,
896900 rexBuilder .makeCall (call .getOperator (), rexBuilder .makeNotNull (op0 ), op1 ));
897901
898902 return rexBuilder .makeCall (SqlStdOperatorTable .CASE ,
@@ -902,6 +906,42 @@ public static RexNode expandSearchNullable(RexBuilder rexBuilder, @Nullable RexP
902906 );
903907 }
904908
909+ /**
910+ * Expand SEARCH/SARG with operands limit (to avoid too deep recursion on operands processing after compilation).
911+ */
912+ private static RexNode expandSearch (RexBuilder rexBuilder , @ Nullable RexProgram program , RexNode call ) {
913+ RexNode expandedSearch = RexUtil .expandSearch (rexBuilder , program , call );
914+
915+ RexShuttle groupingShuttle = new RexShuttle () {
916+ @ Override public RexNode visitCall (RexCall call ) {
917+ if (call .getOperands ().size () > SEARCH_EXPAND_OPERANDS_LIMIT
918+ && (call .getOperator ().getKind () == OR || call .getOperator ().getKind () == AND )) {
919+
920+ List <RexNode > groupedOps = new ArrayList <>();
921+ List <RexNode > grpOps = new ArrayList <>(SEARCH_EXPAND_OPERANDS_LIMIT );
922+
923+ for (int i = 0 ; i < call .getOperands ().size (); i ++) {
924+ if (i > 0 && i % SEARCH_EXPAND_OPERANDS_LIMIT == 0 ) {
925+ groupedOps .add (rexBuilder .makeCall (call .getOperator (), grpOps ));
926+
927+ grpOps = new ArrayList <>(SEARCH_EXPAND_OPERANDS_LIMIT );
928+ }
929+
930+ grpOps .add (call .getOperands ().get (i ));
931+ }
932+
933+ groupedOps .add (grpOps .size () == 1 ? grpOps .get (0 ) : rexBuilder .makeCall (call .getOperator (), grpOps ));
934+
935+ return rexBuilder .makeCall (call .getOperator (), groupedOps );
936+ }
937+
938+ return super .visitCall (call );
939+ }
940+ };
941+
942+ return expandedSearch .accept (groupingShuttle );
943+ }
944+
905945 /**
906946 * Traverse {@code node} and expand all SEARCH/SARG operators (with preceding NULLs check).
907947 *
0 commit comments