|
100 | 100 | import org.opensearch.sql.ast.tree.RareTopN; |
101 | 101 | import org.opensearch.sql.ast.tree.Relation; |
102 | 102 | import org.opensearch.sql.ast.tree.Rename; |
| 103 | +import org.opensearch.sql.ast.tree.Rex; |
103 | 104 | import org.opensearch.sql.ast.tree.Sort; |
104 | 105 | import org.opensearch.sql.ast.tree.Sort.SortOption; |
105 | 106 | import org.opensearch.sql.ast.tree.SubqueryAlias; |
|
117 | 118 | import org.opensearch.sql.common.utils.StringUtils; |
118 | 119 | import org.opensearch.sql.exception.CalciteUnsupportedException; |
119 | 120 | import org.opensearch.sql.exception.SemanticCheckException; |
| 121 | +import org.opensearch.sql.expression.parse.RegexCommonUtils; |
120 | 122 | import org.opensearch.sql.expression.function.BuiltinFunctionName; |
121 | 123 | import org.opensearch.sql.expression.function.PPLFuncImpTable; |
122 | 124 | import org.opensearch.sql.utils.ParseUtils; |
@@ -171,6 +173,41 @@ public RelNode visitFilter(Filter node, CalcitePlanContext context) { |
171 | 173 | return context.relBuilder.peek(); |
172 | 174 | } |
173 | 175 |
|
| 176 | + @Override |
| 177 | + public RelNode visitRex(Rex node, CalcitePlanContext context) { |
| 178 | + visitChildren(node, context); |
| 179 | + |
| 180 | + RexNode fieldRex = rexVisitor.analyze(node.getField(), context); |
| 181 | + String patternStr = (String) node.getPattern().getValue(); |
| 182 | + List<String> namedGroups = RegexCommonUtils.getNamedGroupCandidates(patternStr); |
| 183 | + |
| 184 | + if (namedGroups.isEmpty()) { |
| 185 | + throw new IllegalArgumentException("Rex pattern must contain at least one named capture group"); |
| 186 | + } |
| 187 | + |
| 188 | + // Filter matching rows on data nodes using script pushdown |
| 189 | + RexNode regexMatchCondition = context.rexBuilder.makeCall( |
| 190 | + org.apache.calcite.sql.fun.SqlLibraryOperators.REGEXP_CONTAINS, |
| 191 | + fieldRex, |
| 192 | + context.rexBuilder.makeLiteral(patternStr) |
| 193 | + ); |
| 194 | + context.relBuilder.filter(regexMatchCondition); |
| 195 | + |
| 196 | + // Extract fields from filtered data |
| 197 | + List<RexNode> newFields = new ArrayList<>(); |
| 198 | + for (int i = 0; i < namedGroups.size(); i++) { |
| 199 | + RexNode extractCall = PPLFuncImpTable.INSTANCE.resolve( |
| 200 | + context.rexBuilder, |
| 201 | + BuiltinFunctionName.REX_EXTRACT, |
| 202 | + fieldRex, |
| 203 | + context.rexBuilder.makeLiteral(patternStr), |
| 204 | + context.relBuilder.literal(i + 1)); |
| 205 | + newFields.add(extractCall); |
| 206 | + } |
| 207 | + |
| 208 | + projectPlusOverriding(newFields, namedGroups, context); |
| 209 | + return context.relBuilder.peek(); |
| 210 | + } |
174 | 211 | private boolean containsSubqueryExpression(Node expr) { |
175 | 212 | if (expr == null) { |
176 | 213 | return false; |
|
0 commit comments