View Javadoc
1   /*
2    * Copyright 2021 TiKV Project Authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  
18  package org.tikv.common.expression;
19  
20  import static java.util.Objects.requireNonNull;
21  import static org.tikv.common.expression.StringRegExpression.Type.*;
22  
23  import com.google.common.collect.ImmutableList;
24  import java.util.List;
25  import java.util.Objects;
26  import org.tikv.common.key.TypedKey;
27  import org.tikv.common.types.DataType;
28  import org.tikv.common.types.IntegerType;
29  
30  public class StringRegExpression extends Expression {
31    private final Expression left;
32    private final Expression right;
33    private final Expression reg;
34    private final Type regType;
35    private transient TypedKey key;
36  
37    public StringRegExpression(Type type, Expression left, Expression right, Expression reg) {
38      super(IntegerType.BOOLEAN);
39      resolved = true;
40      this.left = requireNonNull(left, "left expression is null");
41      this.right = requireNonNull(right, "right expression is null");
42      this.regType = requireNonNull(type, "type is null");
43      this.reg = requireNonNull(reg, "reg string is null");
44    }
45  
46    public static StringRegExpression startsWith(Expression left, Expression right) {
47      Expression reg = Constant.create(((Constant) right).getValue() + "%", right.getDataType());
48      return new StringRegExpression(STARTS_WITH, left, right, reg);
49    }
50  
51    public static StringRegExpression contains(Expression left, Expression right) {
52      Expression reg =
53          Constant.create("%" + ((Constant) right).getValue() + "%", right.getDataType());
54      return new StringRegExpression(CONTAINS, left, right, reg);
55    }
56  
57    public static StringRegExpression endsWith(Expression left, Expression right) {
58      Expression reg = Constant.create("%" + ((Constant) right).getValue(), right.getDataType());
59      return new StringRegExpression(ENDS_WITH, left, right, reg);
60    }
61  
62    public static StringRegExpression like(Expression left, Expression right) {
63      return new StringRegExpression(LIKE, left, right, right);
64    }
65  
66    public ColumnRef getColumnRef() {
67      return (ColumnRef) getLeft();
68    }
69  
70    public Constant getValue() {
71      return (Constant) getRight();
72    }
73  
74    public TypedKey getTypedLiteral() {
75      return getTypedLiteral(DataType.UNSPECIFIED_LEN);
76    }
77  
78    public TypedKey getTypedLiteral(int prefixLength) {
79      if (key == null) {
80        key = TypedKey.toTypedKey(getValue().getValue(), getColumnRef().getDataType(), prefixLength);
81      }
82      return key;
83    }
84  
85    @Override
86    public List<Expression> getChildren() {
87      // For LIKE statement, an extra ESCAPE parameter is required as the third parameter for
88      // ScalarFunc.
89      // However in Spark ESCAPE is not supported so we simply set this value to zero.
90      return ImmutableList.of(left, reg, Constant.create(0, IntegerType.BIGINT));
91    }
92  
93    @Override
94    public <R, C> R accept(Visitor<R, C> visitor, C context) {
95      return visitor.visit(this, context);
96    }
97  
98    public Expression getLeft() {
99      return left;
100   }
101 
102   public Expression getRight() {
103     return right;
104   }
105 
106   public Type getRegType() {
107     return regType;
108   }
109 
110   public Expression getReg() {
111     return reg;
112   }
113 
114   @Override
115   public String toString() {
116     return String.format("[%s %s %s reg: %s]", getLeft(), getRegType(), getRight(), getReg());
117   }
118 
119   @Override
120   public boolean equals(Object other) {
121     if (this == other) {
122       return true;
123     }
124     if (!(other instanceof StringRegExpression)) {
125       return false;
126     }
127 
128     StringRegExpression that = (StringRegExpression) other;
129     return (regType == that.regType)
130         && Objects.equals(left, that.left)
131         && Objects.equals(right, that.right)
132         && Objects.equals(reg, that.reg);
133   }
134 
135   @Override
136   public int hashCode() {
137     return Objects.hash(regType, left, right, reg);
138   }
139 
140   public enum Type {
141     STARTS_WITH,
142     CONTAINS,
143     ENDS_WITH,
144     LIKE
145   }
146 }