4141import static java .util .Objects .requireNonNull ;
4242
4343/**
44- * Translates a {@link RexNode} expression to a Gandiva string .
44+ * Translates a {@link RexNode} expression to Gandiva predicate tokens .
4545 */
4646class ArrowTranslator {
4747 final RexBuilder rexBuilder ;
@@ -61,13 +61,30 @@ public static ArrowTranslator create(RexBuilder rexBuilder,
6161 return new ArrowTranslator (rexBuilder , rowType );
6262 }
6363
64- List <String > translateMatch (RexNode condition ) {
65- List <RexNode > disjunctions = RelOptUtil .disjunctions (condition );
66- if (disjunctions .size () == 1 ) {
67- return translateAnd (disjunctions .get (0 ));
68- } else {
69- throw new UnsupportedOperationException ("Unsupported disjunctive condition " + condition );
64+ /** The maximum number of nodes allowed during CNF conversion.
65+ *
66+ * <p>If exceeded, {@link RexUtil#toCnf(RexBuilder, int, RexNode)} returns
67+ * the original expression unchanged, which may cause the subsequent
68+ * translation to Gandiva predicates to fail with an
69+ * {@link UnsupportedOperationException}. When invoked by the Arrow adapter
70+ * module, the exception is caught and the plan falls back to
71+ * an Enumerable convention. */
72+ private static final int MAX_CNF_NODE_COUNT = 256 ;
73+
74+ List <List <ConditionToken >> translateMatch (RexNode condition ) {
75+ // Convert to CNF; SEARCH nodes are already expanded
76+ // by ArrowFilterRule before reaching here.
77+ final RexNode cnf = RexUtil .toCnf (rexBuilder , MAX_CNF_NODE_COUNT , condition );
78+
79+ final List <List <ConditionToken >> result = new ArrayList <>();
80+ for (RexNode conjunct : RelOptUtil .conjunctions (cnf )) {
81+ final List <ConditionToken > orGroup = new ArrayList <>();
82+ for (RexNode disjunct : RelOptUtil .disjunctions (conjunct )) {
83+ orGroup .add (translateMatch2 (disjunct ));
84+ }
85+ result .add (orGroup );
7086 }
87+ return result ;
7188 }
7289
7390 /**
@@ -93,34 +110,14 @@ private static Object literalValue(RexLiteral literal) {
93110 }
94111 }
95112
96- /**
97- * Translate a conjunctive predicate to a SQL string.
98- *
99- * @param condition A conjunctive predicate
100- *
101- * @return SQL string for the predicate
102- */
103- private List <String > translateAnd (RexNode condition ) {
104- List <String > predicates = new ArrayList <>();
105- for (RexNode node : RelOptUtil .conjunctions (condition )) {
106- if (node .getKind () == SqlKind .SEARCH ) {
107- final RexNode node2 = RexUtil .expandSearch (rexBuilder , null , node );
108- predicates .addAll (translateMatch (node2 ));
109- } else {
110- predicates .add (translateMatch2 (node ));
111- }
112- }
113- return predicates ;
114- }
115-
116113 /**
117114 * Translates a binary or unary relation.
118115 *
119116 * @param node A RexNode that always evaluates to a boolean expression.
120117 * Currently, this method is only called from translateAnd.
121- * @return The translated SQL string for the relation.
118+ * @return The translated condition token for the relation.
122119 */
123- private String translateMatch2 (RexNode node ) {
120+ private ConditionToken translateMatch2 (RexNode node ) {
124121 switch (node .getKind ()) {
125122 case EQUALS :
126123 return translateBinary ("equal" , "=" , (RexCall ) node );
@@ -144,7 +141,7 @@ private String translateMatch2(RexNode node) {
144141 return translateUnary ("isnotfalse" , (RexCall ) node );
145142 case INPUT_REF :
146143 final RexInputRef inputRef = (RexInputRef ) node ;
147- return fieldNames .get (inputRef .getIndex ()) + " istrue" ;
144+ return ConditionToken . unary ( fieldNames .get (inputRef .getIndex ()), " istrue") ;
148145 case NOT :
149146 return translateUnary ("isfalse" , (RexCall ) node );
150147 default :
@@ -156,10 +153,10 @@ private String translateMatch2(RexNode node) {
156153 * Translates a call to a binary operator, reversing arguments if
157154 * necessary.
158155 */
159- private String translateBinary (String op , String rop , RexCall call ) {
156+ private ConditionToken translateBinary (String op , String rop , RexCall call ) {
160157 final RexNode left = call .operands .get (0 );
161158 final RexNode right = call .operands .get (1 );
162- @ Nullable String expression = translateBinary2 (op , left , right );
159+ @ Nullable ConditionToken expression = translateBinary2 (op , left , right );
163160 if (expression != null ) {
164161 return expression ;
165162 }
@@ -171,7 +168,8 @@ private String translateBinary(String op, String rop, RexCall call) {
171168 }
172169
173170 /** Translates a call to a binary operator. Returns null on failure. */
174- private @ Nullable String translateBinary2 (String op , RexNode left , RexNode right ) {
171+ private @ Nullable ConditionToken translateBinary2 (String op , RexNode left ,
172+ RexNode right ) {
175173 if (right .getKind () != SqlKind .LITERAL ) {
176174 return null ;
177175 }
@@ -189,26 +187,29 @@ private String translateBinary(String op, String rop, RexCall call) {
189187 }
190188 }
191189
192- /** Combines a field name, operator, and literal to produce a predicate string. */
193- private String translateOp2 (String op , String name , RexLiteral right ) {
190+ /** Combines a field name, operator, and literal to produce a binary
191+ * condition token. */
192+ private ConditionToken translateOp2 (String op , String name ,
193+ RexLiteral right ) {
194194 Object value = literalValue (right );
195195 String valueString = value .toString ();
196196 String valueType = getLiteralType (right .getType ());
197197
198198 if (value instanceof String ) {
199- final RelDataTypeField field = requireNonNull (rowType .getField (name , true , false ), "field" );
199+ final RelDataTypeField field =
200+ requireNonNull (rowType .getField (name , true , false ), "field" );
200201 SqlTypeName typeName = field .getType ().getSqlTypeName ();
201202 if (typeName != SqlTypeName .CHAR ) {
202203 valueString = "'" + valueString + "'" ;
203204 }
204205 }
205- return name + " " + op + " " + valueString + " " + valueType ;
206+ return ConditionToken . binary ( name , op , valueString , valueType ) ;
206207 }
207208
208209 /** Translates a call to a unary operator. */
209- private String translateUnary (String op , RexCall call ) {
210+ private ConditionToken translateUnary (String op , RexCall call ) {
210211 final RexNode opNode = call .operands .get (0 );
211- @ Nullable String expression = translateUnary2 (op , opNode );
212+ @ Nullable ConditionToken expression = translateUnary2 (op , opNode );
212213
213214 if (expression != null ) {
214215 return expression ;
@@ -218,21 +219,16 @@ private String translateUnary(String op, RexCall call) {
218219 }
219220
220221 /** Translates a call to a unary operator. Returns null on failure. */
221- private @ Nullable String translateUnary2 (String op , RexNode opNode ) {
222+ private @ Nullable ConditionToken translateUnary2 (String op , RexNode opNode ) {
222223 if (opNode .getKind () == SqlKind .INPUT_REF ) {
223224 final RexInputRef inputRef = (RexInputRef ) opNode ;
224225 final String name = fieldNames .get (inputRef .getIndex ());
225- return translateUnaryOp ( op , name );
226+ return ConditionToken . unary ( name , op );
226227 }
227228
228229 return null ;
229230 }
230231
231- /** Combines a field name and a unary operator to produce a predicate string. */
232- private static String translateUnaryOp (String op , String name ) {
233- return name + " " + op ;
234- }
235-
236232 private static String getLiteralType (RelDataType type ) {
237233 if (type .getSqlTypeName () == SqlTypeName .DECIMAL ) {
238234 return "decimal" + "(" + type .getPrecision () + "," + type .getScale () + ")" ;
0 commit comments