4949import static com .facebook .presto .common .function .OperatorType .flip ;
5050import static com .facebook .presto .common .type .BooleanType .BOOLEAN ;
5151import static com .facebook .presto .plugin .clp .ClpErrorCode .CLP_PUSHDOWN_UNSUPPORTED_EXPRESSION ;
52+ import static com .facebook .presto .plugin .clp .ClpUtils .KqlUtils .escapeKqlSpecialCharsForStringValue ;
5253import static com .facebook .presto .spi .relation .SpecialFormExpression .Form .AND ;
5354import static java .lang .Integer .parseInt ;
5455import static java .lang .String .format ;
@@ -84,15 +85,18 @@ public class ClpFilterToKqlConverter
8485 private final StandardFunctionResolution standardFunctionResolution ;
8586 private final FunctionMetadataManager functionMetadataManager ;
8687 private final Map <VariableReferenceExpression , ColumnHandle > assignments ;
88+ private final Set <String > metadataFilterColumns ;
8789
8890 public ClpFilterToKqlConverter (
8991 StandardFunctionResolution standardFunctionResolution ,
9092 FunctionMetadataManager functionMetadataManager ,
91- Map <VariableReferenceExpression , ColumnHandle > assignments )
93+ Map <VariableReferenceExpression , ColumnHandle > assignments ,
94+ Set <String > metadataFilterColumns )
9295 {
9396 this .standardFunctionResolution = requireNonNull (standardFunctionResolution , "standardFunctionResolution is null" );
9497 this .functionMetadataManager = requireNonNull (functionMetadataManager , "function metadata manager is null" );
9598 this .assignments = requireNonNull (assignments , "assignments is null" );
99+ this .metadataFilterColumns = requireNonNull (metadataFilterColumns , "metadataFilterColumns is null" );
96100 }
97101
98102 @ Override
@@ -114,11 +118,39 @@ public ClpExpression visitCall(CallExpression node, Void context)
114118 if (operatorType .isComparisonOperator () && operatorType != IS_DISTINCT_FROM ) {
115119 return handleLogicalBinary (operatorType , node );
116120 }
121+ else if (OperatorType .BETWEEN == operatorType ) {
122+ return handleBetween (operatorType , node );
123+ }
117124 }
118125
119126 return new ClpExpression (node );
120127 }
121128
129+ private ClpExpression handleBetween (OperatorType operator , CallExpression node )
130+ {
131+ if (node .getArguments ().size () != 3 ) {
132+ throw new PrestoException (CLP_PUSHDOWN_UNSUPPORTED_EXPRESSION ,
133+ "Logical binary operator must have exactly two arguments. Received: " + node );
134+ }
135+ Optional <String > variableReferenceDefinition = node .getArguments ().get (0 ).accept (this , null ).getPushDownExpression ();
136+ Optional <String > lowerBoundConstantDefinition = node .getArguments ().get (1 ).accept (this , null ).getPushDownExpression ();
137+ Optional <String > upperBoundConstantDefinition = node .getArguments ().get (2 ).accept (this , null ).getPushDownExpression ();
138+ if (!variableReferenceDefinition .isPresent () || !lowerBoundConstantDefinition .isPresent () || !upperBoundConstantDefinition .isPresent ()) {
139+ return new ClpExpression (node );
140+ }
141+ String metadataSql = null ;
142+ String kql = String .format (
143+ "\" %s\" >= %s AND \" %s\" <= %s" ,
144+ variableReferenceDefinition .get (),
145+ lowerBoundConstantDefinition .get (),
146+ variableReferenceDefinition .get (),
147+ upperBoundConstantDefinition .get ());
148+ if (metadataFilterColumns .contains (variableReferenceDefinition .get ())) {
149+ metadataSql = kql ;
150+ }
151+ return new ClpExpression (kql , metadataSql );
152+ }
153+
122154 @ Override
123155 public ClpExpression visitConstant (ConstantExpression node , Void context )
124156 {
@@ -203,7 +235,12 @@ private ClpExpression handleNot(CallExpression node)
203235 if (expression .getRemainingExpression ().isPresent () || !expression .getPushDownExpression ().isPresent ()) {
204236 return new ClpExpression (node );
205237 }
206- return new ClpExpression ("NOT " + expression .getPushDownExpression ().get ());
238+ if (expression .getMetadataSql ().isPresent ()) {
239+ return new ClpExpression ("NOT " + expression .getPushDownExpression ().get (), "NOT " + expression .getMetadataSql ());
240+ }
241+ else {
242+ return new ClpExpression ("NOT " + expression .getPushDownExpression ().get ());
243+ }
207244 }
208245
209246 /**
@@ -350,24 +387,40 @@ private ClpExpression buildClpExpression(
350387 Type literalType ,
351388 RowExpression originalNode )
352389 {
390+ String metadataSql = null ;
353391 if (operator .equals (EQUAL )) {
354392 if (literalType instanceof VarcharType ) {
355- return new ClpExpression (format ("%s: \" %s\" " , variableName , literalString ));
393+ if (metadataFilterColumns .contains (variableName )) {
394+ metadataSql = format ("\" %s\" = '%s'" , variableName , literalString );
395+ }
396+ return new ClpExpression (format ("%s: \" %s\" " , variableName , escapeKqlSpecialCharsForStringValue (literalString )), metadataSql );
356397 }
357398 else {
358- return new ClpExpression (format ("%s: %s" , variableName , literalString ));
399+ if (metadataFilterColumns .contains (variableName )) {
400+ metadataSql = format ("\" %s\" = %s" , variableName , literalString );
401+ }
402+ return new ClpExpression (format ("%s: %s" , variableName , literalString ), metadataSql );
359403 }
360404 }
361405 else if (operator .equals (NOT_EQUAL )) {
362406 if (literalType instanceof VarcharType ) {
363- return new ClpExpression (format ("NOT %s: \" %s\" " , variableName , literalString ));
407+ if (metadataFilterColumns .contains (variableName )) {
408+ metadataSql = format ("NOT \" %s\" = '%s'" , variableName , literalString );
409+ }
410+ return new ClpExpression (format ("NOT %s: \" %s\" " , variableName , escapeKqlSpecialCharsForStringValue (literalString )), metadataSql );
364411 }
365412 else {
366- return new ClpExpression (format ("NOT %s: %s" , variableName , literalString ));
413+ if (metadataFilterColumns .contains (variableName )) {
414+ metadataSql = format ("NOT \" %s\" = %s" , variableName , literalString );
415+ }
416+ return new ClpExpression (format ("NOT %s: %s" , variableName , literalString ), metadataSql );
367417 }
368418 }
369419 else if (LOGICAL_BINARY_OPS_FILTER .contains (operator ) && !(literalType instanceof VarcharType )) {
370- return new ClpExpression (format ("%s %s %s" , variableName , operator .getOperator (), literalString ));
420+ if (metadataFilterColumns .contains (variableName )) {
421+ metadataSql = format ("\" %s\" %s %s" , variableName , operator .getOperator (), literalString );
422+ }
423+ return new ClpExpression (format ("%s %s %s" , variableName , operator .getOperator (), literalString ), metadataSql );
371424 }
372425 return new ClpExpression (originalNode );
373426 }
@@ -568,16 +621,24 @@ private Optional<Integer> parseLengthLiteral(RowExpression lengthExpression, Str
568621 */
569622 private ClpExpression handleAnd (SpecialFormExpression node )
570623 {
624+ StringBuilder metadataQueryBuilder = new StringBuilder ();
625+ metadataQueryBuilder .append ("(" );
571626 StringBuilder queryBuilder = new StringBuilder ();
572627 queryBuilder .append ("(" );
573628 List <RowExpression > remainingExpressions = new ArrayList <>();
629+ boolean hasMetadataSql = false ;
574630 boolean hasPushDownExpression = false ;
575631 for (RowExpression argument : node .getArguments ()) {
576632 ClpExpression expression = argument .accept (this , null );
577633 if (expression .getPushDownExpression ().isPresent ()) {
578634 hasPushDownExpression = true ;
579635 queryBuilder .append (expression .getPushDownExpression ().get ());
580636 queryBuilder .append (" AND " );
637+ if (expression .getMetadataSql ().isPresent ()) {
638+ hasMetadataSql = true ;
639+ metadataQueryBuilder .append (expression .getMetadataSql ().get ());
640+ metadataQueryBuilder .append (" AND " );
641+ }
581642 }
582643 if (expression .getRemainingExpression ().isPresent ()) {
583644 remainingExpressions .add (expression .getRemainingExpression ().get ());
@@ -588,16 +649,21 @@ private ClpExpression handleAnd(SpecialFormExpression node)
588649 }
589650 else if (!remainingExpressions .isEmpty ()) {
590651 if (remainingExpressions .size () == 1 ) {
591- return new ClpExpression (queryBuilder .substring (0 , queryBuilder .length () - 5 ) + ")" , remainingExpressions .get (0 ));
652+ return new ClpExpression (
653+ queryBuilder .substring (0 , queryBuilder .length () - 5 ) + ")" ,
654+ hasMetadataSql ? metadataQueryBuilder .substring (0 , metadataQueryBuilder .length () - 5 ) + ")" : null ,
655+ remainingExpressions .get (0 ));
592656 }
593657 else {
594658 return new ClpExpression (
595659 queryBuilder .substring (0 , queryBuilder .length () - 5 ) + ")" ,
660+ hasMetadataSql ? metadataQueryBuilder .substring (0 , metadataQueryBuilder .length () - 5 ) + ")" : null ,
596661 new SpecialFormExpression (node .getSourceLocation (), AND , BOOLEAN , remainingExpressions ));
597662 }
598663 }
599664 // Remove the last " AND " from the query
600- return new ClpExpression (queryBuilder .substring (0 , queryBuilder .length () - 5 ) + ")" );
665+ return new ClpExpression (queryBuilder .substring (0 , queryBuilder .length () - 5 ) + ")" ,
666+ hasMetadataSql ? metadataQueryBuilder .substring (0 , metadataQueryBuilder .length () - 5 ) + ")" : null );
601667 }
602668
603669 /**
@@ -614,18 +680,30 @@ else if (!remainingExpressions.isEmpty()) {
614680 */
615681 private ClpExpression handleOr (SpecialFormExpression node )
616682 {
683+ StringBuilder metadataQueryBuilder = new StringBuilder ();
684+ metadataQueryBuilder .append ("(" );
617685 StringBuilder queryBuilder = new StringBuilder ();
618686 queryBuilder .append ("(" );
687+ boolean hasAllMetadataSql = true ;
619688 for (RowExpression argument : node .getArguments ()) {
620689 ClpExpression expression = argument .accept (this , null );
621690 if (expression .getRemainingExpression ().isPresent () || !expression .getPushDownExpression ().isPresent ()) {
622691 return new ClpExpression (node );
623692 }
624693 queryBuilder .append (expression .getPushDownExpression ().get ());
625694 queryBuilder .append (" OR " );
695+ if (hasAllMetadataSql && expression .getMetadataSql ().isPresent ()) {
696+ metadataQueryBuilder .append (expression .getMetadataSql ().get ());
697+ metadataQueryBuilder .append (" OR " );
698+ }
699+ else {
700+ hasAllMetadataSql = false ;
701+ }
626702 }
627703 // Remove the last " OR " from the query
628- return new ClpExpression (queryBuilder .substring (0 , queryBuilder .length () - 4 ) + ")" );
704+ return new ClpExpression (
705+ queryBuilder .substring (0 , queryBuilder .length () - 4 ) + ")" ,
706+ hasAllMetadataSql ? metadataQueryBuilder .substring (0 , metadataQueryBuilder .length () - 4 ) + ")" : null );
629707 }
630708
631709 /**
0 commit comments