Skip to content

Commit c0d50fa

Browse files
committed
Merge remote-tracking branch 'origin/main' into issues/4136
Signed-off-by: Yuanchun Shen <yuanchu@amazon.com>
2 parents 599b6db + 0e5802b commit c0d50fa

145 files changed

Lines changed: 6748 additions & 381 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

common/src/main/java/org/opensearch/sql/common/setting/Settings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public enum Key {
3030
PATTERN_MAX_SAMPLE_COUNT("plugins.ppl.pattern.max.sample.count"),
3131
PATTERN_BUFFER_LIMIT("plugins.ppl.pattern.buffer.limit"),
3232
PPL_REX_MAX_MATCH_LIMIT("plugins.ppl.rex.max_match.limit"),
33+
PPL_VALUES_MAX_LIMIT("plugins.ppl.values.max.limit"),
3334
PPL_SYNTAX_LEGACY_PREFERRED("plugins.ppl.syntax.legacy.preferred"),
3435

3536
/** Enable Calcite as execution engine */

core/src/main/java/org/opensearch/sql/analysis/Analyzer.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import org.opensearch.sql.ast.tree.Rename;
8787
import org.opensearch.sql.ast.tree.Reverse;
8888
import org.opensearch.sql.ast.tree.Rex;
89+
import org.opensearch.sql.ast.tree.Search;
8990
import org.opensearch.sql.ast.tree.Sort;
9091
import org.opensearch.sql.ast.tree.Sort.SortOption;
9192
import org.opensearch.sql.ast.tree.SubqueryAlias;
@@ -278,6 +279,18 @@ public LogicalPlan visitLimit(Limit node, AnalysisContext context) {
278279
return new LogicalLimit(child, node.getLimit(), node.getOffset());
279280
}
280281

282+
@Override
283+
public LogicalPlan visitSearch(Search node, AnalysisContext context) {
284+
LogicalPlan child = node.getChild().get(0).accept(this, context);
285+
Function queryStringFunc =
286+
AstDSL.function(
287+
"query_string",
288+
AstDSL.unresolvedArg("query", AstDSL.stringLiteral(node.getQueryString())));
289+
290+
Expression analyzed = expressionAnalyzer.analyze(queryStringFunc, context);
291+
return new LogicalFilter(child, analyzed);
292+
}
293+
281294
@Override
282295
public LogicalPlan visitFilter(Filter node, AnalysisContext context) {
283296
LogicalPlan child = node.getChild().get(0).accept(this, context);

core/src/main/java/org/opensearch/sql/analysis/ExpressionAnalyzer.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.Collections;
1818
import java.util.List;
1919
import java.util.Optional;
20+
import java.util.Set;
2021
import java.util.stream.Collectors;
2122
import lombok.Getter;
2223
import org.opensearch.sql.analysis.symbol.Namespace;
@@ -53,6 +54,7 @@
5354
import org.opensearch.sql.ast.expression.subquery.ExistsSubquery;
5455
import org.opensearch.sql.ast.expression.subquery.InSubquery;
5556
import org.opensearch.sql.ast.expression.subquery.ScalarSubquery;
57+
import org.opensearch.sql.calcite.utils.CalciteUtils;
5658
import org.opensearch.sql.data.model.ExprValueUtils;
5759
import org.opensearch.sql.data.type.ExprCoreType;
5860
import org.opensearch.sql.data.type.ExprType;
@@ -191,6 +193,7 @@ public Expression visitRelevanceFieldList(RelevanceFieldList node, AnalysisConte
191193
@Override
192194
public Expression visitFunction(Function node, AnalysisContext context) {
193195
FunctionName functionName = FunctionName.of(node.getFuncName());
196+
validateCalciteOnlyFunction(functionName);
194197
List<Expression> arguments =
195198
node.getFuncArgs().stream()
196199
.map(
@@ -208,6 +211,34 @@ public Expression visitFunction(Function node, AnalysisContext context) {
208211
repository.compile(context.getFunctionProperties(), functionName, arguments);
209212
}
210213

214+
/**
215+
* Validates that functions requiring Calcite engine are not used without it.
216+
*
217+
* @param functionName The function name to validate
218+
*/
219+
private void validateCalciteOnlyFunction(FunctionName functionName) {
220+
if (isCalciteOnlyFunction(functionName)) {
221+
throw CalciteUtils.getOnlyForCalciteException(functionName.getFunctionName().toUpperCase());
222+
}
223+
}
224+
225+
/**
226+
* Checks if a function requires Calcite engine to be enabled.
227+
*
228+
* @param functionName The function name to check
229+
* @return true if the function requires Calcite, false otherwise
230+
*/
231+
private boolean isCalciteOnlyFunction(FunctionName functionName) {
232+
// Set of functions that are only supported with Calcite engine
233+
Set<String> calciteOnlyFunctions =
234+
ImmutableSet.of(
235+
BuiltinFunctionName.REGEX_MATCH.getName().getFunctionName(),
236+
BuiltinFunctionName.STRFTIME.getName().getFunctionName());
237+
238+
return calciteOnlyFunctions.stream()
239+
.anyMatch(f -> f.equalsIgnoreCase(functionName.getFunctionName()));
240+
}
241+
211242
@SuppressWarnings("unchecked")
212243
@Override
213244
public Expression visitWindowFunction(WindowFunction node, AnalysisContext context) {

core/src/main/java/org/opensearch/sql/ast/AbstractNodeVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import org.opensearch.sql.ast.tree.Reverse;
7676
import org.opensearch.sql.ast.tree.Rex;
7777
import org.opensearch.sql.ast.tree.SPath;
78+
import org.opensearch.sql.ast.tree.Search;
7879
import org.opensearch.sql.ast.tree.Sort;
7980
import org.opensearch.sql.ast.tree.SubqueryAlias;
8081
import org.opensearch.sql.ast.tree.TableFunction;
@@ -131,6 +132,10 @@ public T visitTableFunction(TableFunction node, C context) {
131132
return visitChildren(node, context);
132133
}
133134

135+
public T visitSearch(Search node, C context) {
136+
return visitChildren(node, context);
137+
}
138+
134139
public T visitFilter(Filter node, C context) {
135140
return visitChildren(node, context);
136141
}

core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.opensearch.sql.ast.tree.RelationSubquery;
7272
import org.opensearch.sql.ast.tree.Rename;
7373
import org.opensearch.sql.ast.tree.SPath;
74+
import org.opensearch.sql.ast.tree.Search;
7475
import org.opensearch.sql.ast.tree.Sort;
7576
import org.opensearch.sql.ast.tree.Sort.SortOption;
7677
import org.opensearch.sql.ast.tree.SpanBin;
@@ -109,6 +110,10 @@ public UnresolvedPlan describe(String tableName) {
109110
return new DescribeRelation(qualifiedName(tableName));
110111
}
111112

113+
public static UnresolvedPlan search(UnresolvedPlan input, String queryString) {
114+
return new Search(input, queryString);
115+
}
116+
112117
public UnresolvedPlan subqueryAlias(UnresolvedPlan child, String alias) {
113118
return new SubqueryAlias(child, alias);
114119
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.expression;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import lombok.EqualsAndHashCode;
11+
import lombok.Getter;
12+
import lombok.RequiredArgsConstructor;
13+
import lombok.ToString;
14+
15+
/** Search expression for AND operator. */
16+
@Getter
17+
@RequiredArgsConstructor
18+
@EqualsAndHashCode(callSuper = false)
19+
@ToString
20+
public class SearchAnd extends SearchExpression {
21+
22+
private final SearchExpression left;
23+
private final SearchExpression right;
24+
25+
@Override
26+
public String toQueryString() {
27+
return left.toQueryString() + " AND " + right.toQueryString();
28+
}
29+
30+
@Override
31+
public List<? extends UnresolvedExpression> getChild() {
32+
return Arrays.asList(left, right);
33+
}
34+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.expression;
7+
8+
import java.util.Arrays;
9+
import java.util.List;
10+
import lombok.EqualsAndHashCode;
11+
import lombok.Getter;
12+
import lombok.RequiredArgsConstructor;
13+
import lombok.ToString;
14+
import org.opensearch.sql.utils.QueryStringUtils;
15+
16+
/** Search expression for field comparisons. */
17+
@Getter
18+
@RequiredArgsConstructor
19+
@EqualsAndHashCode(callSuper = false)
20+
@ToString
21+
public class SearchComparison extends SearchExpression {
22+
23+
public enum Operator {
24+
EQUALS("="),
25+
NOT_EQUALS("!="),
26+
LESS_THAN("<"),
27+
LESS_OR_EQUAL("<="),
28+
GREATER_THAN(">"),
29+
GREATER_OR_EQUAL(">=");
30+
31+
private final String symbol;
32+
33+
Operator(String symbol) {
34+
this.symbol = symbol;
35+
}
36+
37+
public String getSymbol() {
38+
return symbol;
39+
}
40+
}
41+
42+
private final Field field;
43+
private final Operator operator;
44+
private final SearchLiteral value;
45+
46+
@Override
47+
public String toQueryString() {
48+
String fieldName = QueryStringUtils.escapeFieldName(field.getField().toString());
49+
String valueStr = value.toQueryString();
50+
switch (operator) {
51+
case NOT_EQUALS:
52+
return "( _exists_:" + fieldName + " AND NOT " + fieldName + ":" + valueStr + " )";
53+
case GREATER_THAN:
54+
return fieldName + ":>" + valueStr;
55+
case GREATER_OR_EQUAL:
56+
return fieldName + ":>=" + valueStr;
57+
case LESS_THAN:
58+
return fieldName + ":<" + valueStr;
59+
case LESS_OR_EQUAL:
60+
return fieldName + ":<=" + valueStr;
61+
default:
62+
return fieldName + ":" + valueStr;
63+
}
64+
}
65+
66+
@Override
67+
public List<? extends UnresolvedExpression> getChild() {
68+
return Arrays.asList(field, value);
69+
}
70+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.expression;
7+
8+
import org.opensearch.sql.ast.AbstractNodeVisitor;
9+
10+
/** Base class for search expressions that get converted to query_string syntax. */
11+
public abstract class SearchExpression extends UnresolvedExpression {
12+
13+
/**
14+
* Convert this search expression to query_string syntax.
15+
*
16+
* @return the query string representation
17+
*/
18+
public abstract String toQueryString();
19+
20+
@Override
21+
public <R, C> R accept(AbstractNodeVisitor<R, C> nodeVisitor, C context) {
22+
return nodeVisitor.visitChildren(this, context);
23+
}
24+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.expression;
7+
8+
import java.util.Collections;
9+
import java.util.List;
10+
import lombok.EqualsAndHashCode;
11+
import lombok.Getter;
12+
import lombok.RequiredArgsConstructor;
13+
import lombok.ToString;
14+
15+
/** Search expression for grouped expressions (parentheses). */
16+
@Getter
17+
@RequiredArgsConstructor
18+
@EqualsAndHashCode(callSuper = false)
19+
@ToString
20+
public class SearchGroup extends SearchExpression {
21+
22+
private final SearchExpression expression;
23+
24+
@Override
25+
public String toQueryString() {
26+
return "(" + expression.toQueryString() + ")";
27+
}
28+
29+
@Override
30+
public List<? extends UnresolvedExpression> getChild() {
31+
return Collections.singletonList(expression);
32+
}
33+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.ast.expression;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.stream.Collectors;
11+
import lombok.EqualsAndHashCode;
12+
import lombok.Getter;
13+
import lombok.RequiredArgsConstructor;
14+
import lombok.ToString;
15+
import org.opensearch.sql.utils.QueryStringUtils;
16+
17+
/** Search expression for IN operator. */
18+
@Getter
19+
@RequiredArgsConstructor
20+
@EqualsAndHashCode(callSuper = false)
21+
@ToString
22+
public class SearchIn extends SearchExpression {
23+
24+
private final Field field;
25+
private final List<SearchLiteral> values;
26+
27+
@Override
28+
public String toQueryString() {
29+
String fieldName = QueryStringUtils.escapeFieldName(field.getField().toString());
30+
String valueList =
31+
values.stream().map(SearchLiteral::toQueryString).collect(Collectors.joining(" OR "));
32+
33+
return fieldName + ":( " + valueList + " )";
34+
}
35+
36+
@Override
37+
public List<? extends UnresolvedExpression> getChild() {
38+
List<UnresolvedExpression> children = new ArrayList<>();
39+
children.add(field);
40+
// SearchLiteral extends SearchExpression which extends UnresolvedExpression
41+
children.addAll(values);
42+
return children;
43+
}
44+
}

0 commit comments

Comments
 (0)