2929import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .ComparisonExpression ;
3030import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .DoubleLiteral ;
3131import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .Expression ;
32+ import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .Extract ;
3233import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .GenericLiteral ;
3334import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .IfExpression ;
3435import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .InListExpression ;
4748import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SymbolReference ;
4849import org .apache .iotdb .db .queryengine .plan .relational .type .InternalTypeManager ;
4950
51+ import com .google .common .collect .ImmutableList ;
5052import org .apache .tsfile .common .conf .TSFileConfig ;
5153import org .apache .tsfile .common .regexp .LikePattern ;
5254import org .apache .tsfile .enums .TSDataType ;
5355import org .apache .tsfile .read .common .type .Type ;
5456import org .apache .tsfile .read .filter .basic .Filter ;
5557import org .apache .tsfile .read .filter .factory .FilterFactory ;
5658import org .apache .tsfile .read .filter .factory .ValueFilterApi ;
59+ import org .apache .tsfile .read .filter .operator .ExtractTimeFilterOperators ;
5760import org .apache .tsfile .utils .Binary ;
5861
5962import javax .annotation .Nullable ;
7275import static org .apache .iotdb .db .queryengine .plan .relational .analyzer .predicate .ConvertPredicateToTimeFilterVisitor .getLongValue ;
7376import static org .apache .iotdb .db .queryengine .plan .relational .analyzer .predicate .PredicatePushIntoScanChecker .isLiteral ;
7477import static org .apache .iotdb .db .queryengine .plan .relational .analyzer .predicate .PredicatePushIntoScanChecker .isSymbolReference ;
78+ import static org .apache .iotdb .db .queryengine .plan .relational .planner .ir .GlobalTimePredicateExtractVisitor .isExtractTimeColumn ;
7579import static org .apache .iotdb .db .queryengine .plan .relational .planner .ir .GlobalTimePredicateExtractVisitor .isTimeColumn ;
80+ import static org .apache .tsfile .read .common .type .TimestampType .TIMESTAMP ;
7681
7782public class ConvertPredicateToFilterVisitor
7883 extends PredicateVisitor <Filter , ConvertPredicateToFilterVisitor .Context > {
7984
8085 @ Nullable private final String timeColumnName ;
8186 private final ConvertPredicateToTimeFilterVisitor timeFilterVisitor ;
87+ private final ZoneId zoneId ;
88+ private final TimeUnit currPrecision ;
8289
8390 public ConvertPredicateToFilterVisitor (
8491 @ Nullable String timeColumnName , ZoneId zoneId , TimeUnit currPrecision ) {
8592 this .timeColumnName = timeColumnName ;
8693 this .timeFilterVisitor = new ConvertPredicateToTimeFilterVisitor (zoneId , currPrecision );
94+ this .zoneId = zoneId ;
95+ this .currPrecision = currPrecision ;
8796 }
8897
8998 @ Override
@@ -168,6 +177,48 @@ public static <T extends Comparable<T>> Filter constructCompareFilter(
168177 }
169178 }
170179
180+ private Filter constructExtractCompareFilter (
181+ ComparisonExpression .Operator operator ,
182+ SymbolReference symbolReference ,
183+ Extract .Field field ,
184+ Literal literal ,
185+ Context context ) {
186+
187+ if (!context .isMeasurementColumn (symbolReference )) {
188+ throw new IllegalStateException (
189+ String .format ("Only support measurement column in filter: %s" , symbolReference ));
190+ }
191+
192+ int measurementIndex = context .getMeasurementIndex (symbolReference .getName ());
193+ long value = getValue (literal , TIMESTAMP );
194+ ExtractTimeFilterOperators .Field field1 =
195+ ExtractTimeFilterOperators .Field .values ()[field .ordinal ()];
196+
197+ switch (operator ) {
198+ case EQUAL :
199+ return ValueFilterApi .extractValueEq (
200+ measurementIndex , value , field1 , zoneId , currPrecision );
201+ case NOT_EQUAL :
202+ return ValueFilterApi .extractValueNotEq (
203+ measurementIndex , value , field1 , zoneId , currPrecision );
204+ case GREATER_THAN :
205+ return ValueFilterApi .extractValueGt (
206+ measurementIndex , value , field1 , zoneId , currPrecision );
207+ case GREATER_THAN_OR_EQUAL :
208+ return ValueFilterApi .extractValueGtEq (
209+ measurementIndex , value , field1 , zoneId , currPrecision );
210+ case LESS_THAN :
211+ return ValueFilterApi .extractValueLt (
212+ measurementIndex , value , field1 , zoneId , currPrecision );
213+ case LESS_THAN_OR_EQUAL :
214+ return ValueFilterApi .extractValueLtEq (
215+ measurementIndex , value , field1 , zoneId , currPrecision );
216+ default :
217+ throw new IllegalArgumentException (
218+ String .format ("Unsupported extract comparison operator %s" , operator ));
219+ }
220+ }
221+
171222 @ SuppressWarnings ("unchecked" )
172223 public static <T extends Comparable <T >> T getValue (Literal value , Type dataType ) {
173224 try {
@@ -273,6 +324,22 @@ && isSymbolReference(right)
273324 && context .isMeasurementColumn ((SymbolReference ) right )) {
274325 return constructCompareFilter (
275326 node .getOperator ().flip (), (SymbolReference ) right , (Literal ) left , context );
327+ } else if (context .isExtractMeasurementColumn (left ) && isLiteral (right )) {
328+ Extract extract = (Extract ) left ;
329+ return constructExtractCompareFilter (
330+ node .getOperator (),
331+ (SymbolReference ) extract .getExpression (),
332+ extract .getField (),
333+ (Literal ) right ,
334+ context );
335+ } else if (isLiteral (left ) && context .isExtractMeasurementColumn (right )) {
336+ Extract extract = (Extract ) right ;
337+ return constructExtractCompareFilter (
338+ node .getOperator ().flip (),
339+ (SymbolReference ) extract .getExpression (),
340+ extract .getField (),
341+ (Literal ) left ,
342+ context );
276343 } else {
277344 throw new IllegalStateException (
278345 String .format ("%s is not supported in value push down" , node ));
@@ -307,7 +374,10 @@ protected Filter visitBetweenPredicate(BetweenPredicate node, Context context) {
307374
308375 if (isTimeColumn (firstExpression , timeColumnName )
309376 || isTimeColumn (secondExpression , timeColumnName )
310- || isTimeColumn (thirdExpression , timeColumnName )) {
377+ || isTimeColumn (thirdExpression , timeColumnName )
378+ || isExtractTimeColumn (firstExpression , timeColumnName )
379+ || isExtractTimeColumn (secondExpression , timeColumnName )
380+ || isExtractTimeColumn (thirdExpression , timeColumnName )) {
311381 return timeFilterVisitor .process (node , null );
312382 }
313383
@@ -331,6 +401,33 @@ protected Filter visitBetweenPredicate(BetweenPredicate node, Context context) {
331401 (SymbolReference ) thirdExpression ,
332402 (Literal ) firstExpression ,
333403 context );
404+ } else if (context .isExtractMeasurementColumn (firstExpression )) {
405+ checkArgument (isLiteral (secondExpression ));
406+ checkArgument (isLiteral (thirdExpression ));
407+ long minValue = getLongValue (secondExpression );
408+ long maxValue = getLongValue (thirdExpression );
409+ Extract extract = (Extract ) firstExpression ;
410+ int measurementIndex =
411+ context .getMeasurementIndex (((SymbolReference ) extract .getExpression ()).getName ());
412+ ExtractTimeFilterOperators .Field field =
413+ ExtractTimeFilterOperators .Field .values ()[extract .getField ().ordinal ()];
414+
415+ if (minValue == maxValue ) {
416+ return ValueFilterApi .extractValueEq (
417+ measurementIndex , minValue , field , zoneId , currPrecision );
418+ }
419+ return FilterFactory .and (
420+ ImmutableList .of (
421+ ValueFilterApi .extractValueGtEq (
422+ measurementIndex , minValue , field , zoneId , currPrecision ),
423+ ValueFilterApi .extractValueLtEq (
424+ measurementIndex , maxValue , field , zoneId , currPrecision )));
425+ } else if (context .isExtractMeasurementColumn (secondExpression )) {
426+ throw new IllegalStateException (
427+ "Should not reach here before PredicateCombineIntoTableScanChecker support Extract push-down in third child" );
428+ } else if (context .isExtractMeasurementColumn (thirdExpression )) {
429+ throw new IllegalStateException (
430+ "Should not reach here before PredicateCombineIntoTableScanChecker support Extract push-down in third child" );
334431 } else {
335432 throw new IllegalStateException (
336433 String .format ("%s is not supported in value push down" , node ));
@@ -429,5 +526,14 @@ public boolean isMeasurementColumn(SymbolReference symbolReference) {
429526 ColumnSchema schema = schemaMap .get (Symbol .from (symbolReference ));
430527 return schema != null && schema .getColumnCategory () == TsTableColumnCategory .FIELD ;
431528 }
529+
530+ public boolean isExtractMeasurementColumn (Expression expression ) {
531+ if (expression instanceof Extract
532+ && ((Extract ) expression ).getExpression () instanceof SymbolReference ) {
533+ ColumnSchema schema = schemaMap .get (Symbol .from (((Extract ) expression ).getExpression ()));
534+ return schema != null && schema .getColumnCategory () == TsTableColumnCategory .FIELD ;
535+ }
536+ return false ;
537+ }
432538 }
433539}
0 commit comments