Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import org.opensearch.sql.ast.expression.subquery.InSubquery;
import org.opensearch.sql.ast.expression.subquery.ScalarSubquery;
import org.opensearch.sql.calcite.utils.CalciteUtils;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.data.type.ExprCoreType;
import org.opensearch.sql.data.type.ExprType;
Expand Down Expand Up @@ -269,10 +271,16 @@ public Expression visitHighlightFunction(HighlightFunction node, AnalysisContext
public Expression visitScoreFunction(ScoreFunction node, AnalysisContext context) {
Literal boostArg = node.getRelevanceFieldWeight();
if (!boostArg.getType().equals(DataType.DOUBLE)) {
throw new SemanticCheckException(
String.format(
"Expected boost type '%s' but got '%s'",
DataType.DOUBLE.name(), boostArg.getType().name()));
throw ErrorReport.wrap(
new SemanticCheckException(
String.format(
"Expected boost type '%s' but got '%s'",
DataType.DOUBLE.name(), boostArg.getType().name())))
.code(ErrorCode.TYPE_ERROR)
.context("parameter", "boost")
.context("expected_type", DataType.DOUBLE.name())
.context("actual_type", boostArg.getType().name())
.build();
}
Double thisBoostValue = ((Double) boostArg.getValue());

Expand Down Expand Up @@ -402,8 +410,13 @@ public Expression visitCase(Case node, AnalysisContext context) {
// Make CaseClause return list so it can be used in error message in determined order
List<ExprType> resultTypes = caseClause.allResultTypes();
if (ImmutableSet.copyOf(resultTypes).size() > 1) {
throw new SemanticCheckException(
"All result types of CASE clause must be the same, but found " + resultTypes);
throw ErrorReport.wrap(
new SemanticCheckException(
"All result types of CASE clause must be the same, but found " + resultTypes))
.code(ErrorCode.TYPE_ERROR)
.context("construct", "CASE")
.context("result_types", resultTypes.stream().map(Object::toString).toList())
.build();
}
return caseClause;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.type.SqlTypeName;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;

/**
* Utility class for unifying schemas across multiple RelNodes. Supports two strategies:
Expand Down Expand Up @@ -86,10 +88,17 @@ private static List<SchemaField> buildUnifiedSchema(List<RelNode> nodes) {
seenFields.put(fieldName, fieldType);
} else if (!areTypesCompatible(existingType, fieldType)) {
// Same field name but different type - throw exception
throw new IllegalArgumentException(
String.format(
"Unable to process column '%s' due to incompatible types: '%s' and '%s'",
fieldName, existingType.getSqlTypeName(), fieldType.getSqlTypeName()));
String existingTypeName = String.valueOf(existingType.getSqlTypeName());
String newTypeName = String.valueOf(fieldType.getSqlTypeName());
throw ErrorReport.wrap(
new IllegalArgumentException(
String.format(
"Unable to process column '%s' due to incompatible types: '%s' and '%s'",
fieldName, existingTypeName, newTypeName)))
.code(ErrorCode.TYPE_ERROR)
.context("column", fieldName)
.context("types", List.of(existingTypeName, newTypeName))
.build();
}
// If we've seen this exact (name, type) combination, skip it
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import java.util.List;
import java.util.Locale;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprNullValue;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.model.ExprValueUtils;
Expand Down Expand Up @@ -82,8 +84,16 @@ public void add(ExprValue value) {
sumResult = doubleValue(getDoubleValue(sumResult) + getDoubleValue(value));
break;
default:
throw new ExpressionEvaluationException(
String.format("unexpected type [%s] in sum aggregation", type));
throw ErrorReport.wrap(
new ExpressionEvaluationException(
String.format(
"sum aggregation does not support type %s; expected a numeric type"
+ " (INTEGER, LONG, FLOAT, or DOUBLE)",
type)))
.code(ErrorCode.TYPE_ERROR)
.context("aggregation", "sum")
.context("actual_type", type.toString())
.build();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import lombok.RequiredArgsConstructor;
import lombok.Singular;
import org.apache.commons.lang3.tuple.Pair;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.exception.ExpressionEvaluationException;

/**
Expand Down Expand Up @@ -52,19 +54,30 @@ public Pair<FunctionSignature, FunctionBuilder> resolve(FunctionSignature unreso
if (FunctionSignature.isVarArgFunction(bestMatchEntry.getValue().getParamTypeList())
&& (unresolvedSignature.getParamTypeList().isEmpty()
|| unresolvedSignature.getParamTypeList().size() > 9)) {
throw new ExpressionEvaluationException(
String.format(
"%s function expected 1-9 arguments, but got %d",
functionName, unresolvedSignature.getParamTypeList().size()));
throw ErrorReport.wrap(
new ExpressionEvaluationException(
String.format(
"%s function expected 1-9 arguments, but got %d",
functionName, unresolvedSignature.getParamTypeList().size())))
.code(ErrorCode.TYPE_ERROR)
.context("function", functionName.toString())
.context("actual_arg_count", unresolvedSignature.getParamTypeList().size())
.build();
}
if (FunctionSignature.NOT_MATCH.equals(bestMatchEntry.getKey())
&& !FunctionSignature.isVarArgFunction(bestMatchEntry.getValue().getParamTypeList())) {
throw new ExpressionEvaluationException(
String.format(
"%s function expected %s, but got %s",
functionName,
formatFunctions(functionBundle.keySet()),
unresolvedSignature.formatTypes()));
throw ErrorReport.wrap(
new ExpressionEvaluationException(
String.format(
"%s function expected %s, but got %s",
functionName,
formatFunctions(functionBundle.keySet()),
unresolvedSignature.formatTypes())))
.code(ErrorCode.TYPE_ERROR)
.context("function", functionName.toString())
.context("expected_signatures", formatFunctions(functionBundle.keySet()))
.context("actual_types", unresolvedSignature.formatTypes())
.build();
} else {
FunctionSignature resolvedSignature = bestMatchEntry.getValue();
return Pair.of(resolvedSignature, functionBundle.get(resolvedSignature));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@
import org.opensearch.sql.ast.tree.RareTopN.CommandType;
import org.opensearch.sql.ast.tree.UnresolvedPlan;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.type.ExprCoreType;
import org.opensearch.sql.exception.ExpressionEvaluationException;
import org.opensearch.sql.exception.SemanticCheckException;
Expand Down Expand Up @@ -159,9 +161,9 @@ public void filter_relation_with_invalid_qualifiedName_ExpressionEvaluationExcep
AstDSL.relation("schema"),
AstDSL.equalTo(AstDSL.qualifiedName("_test"), AstDSL.intLiteral(1)));

ExpressionEvaluationException exception =
assertThrows(ExpressionEvaluationException.class, () -> analyze(typeMismatchPlan));
ErrorReport exception = assertThrows(ErrorReport.class, () -> analyze(typeMismatchPlan));
assertEquals(getIncompatibleTypeErrMsg(STRING, INTEGER), exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down Expand Up @@ -369,9 +371,9 @@ public void analyze_filter_visit_score_function_with_unsupported_boost_SemanticC
AstDSL.unresolvedArg("query", stringLiteral("search query")),
AstDSL.unresolvedArg("boost", stringLiteral("3"))),
AstDSL.stringLiteral("3.0")));
SemanticCheckException exception =
assertThrows(SemanticCheckException.class, () -> analyze(unresolvedPlan));
ErrorReport exception = assertThrows(ErrorReport.class, () -> analyze(unresolvedPlan));
assertEquals("Expected boost type 'DOUBLE' but got 'STRING'", exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import org.opensearch.sql.ast.expression.UnresolvedExpression;
import org.opensearch.sql.ast.tree.UnresolvedPlan;
import org.opensearch.sql.common.antlr.SyntaxCheckException;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprTupleValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.exception.SemanticCheckException;
Expand Down Expand Up @@ -165,11 +167,11 @@ public void case_with_default_result_type_different() {
AstDSL.when(AstDSL.intLiteral(30), AstDSL.stringLiteral("Thirty")),
AstDSL.when(AstDSL.intLiteral(50), AstDSL.stringLiteral("Fifty")));

SemanticCheckException exception =
assertThrows(SemanticCheckException.class, () -> analyze(caseWhen));
ErrorReport exception = assertThrows(ErrorReport.class, () -> analyze(caseWhen));
assertEquals(
"All result types of CASE clause must be the same, but found [STRING, STRING, INTEGER]",
exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.exception.ExpressionEvaluationException;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.LiteralExpression;
Expand Down Expand Up @@ -185,7 +185,7 @@ public void test_percentile_with_invalid_size() {
assertEquals("out of bounds percent value, must be in [0, 100]", exception.getMessage());
var exception2 =
assertThrows(
ExpressionEvaluationException.class,
ErrorReport.class,
() ->
aggregation(
DSL.percentile(DSL.ref("double_value", DOUBLE), DSL.literal("string")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.Test;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.model.ExprValueUtils;
import org.opensearch.sql.data.type.ExprCoreType;
Expand Down Expand Up @@ -67,14 +69,18 @@ public void sum_string_field_expression() {
SumAggregator sumAggregator =
new SumAggregator(ImmutableList.of(DSL.ref("string_value", STRING)), ExprCoreType.STRING);
SumState sumState = sumAggregator.create();
ExpressionEvaluationException exception =
ErrorReport exception =
assertThrows(
ExpressionEvaluationException.class,
ErrorReport.class,
() ->
sumAggregator.iterate(
ExprValueUtils.tupleValue(ImmutableMap.of("string_value", "m")).bindingTuples(),
sumState));
assertEquals("unexpected type [STRING] in sum aggregation", exception.getMessage());
assertEquals(
"sum aggregation does not support type STRING; expected a numeric type (INTEGER, LONG,"
+ " FLOAT, or DOUBLE)",
exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import java.time.Period;
import java.time.ZoneOffset;
import org.junit.jupiter.api.Test;
import org.opensearch.sql.exception.ExpressionEvaluationException;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;

public class DateAddAndAddDateTest extends DateTimeTestBase {

Expand Down Expand Up @@ -152,12 +153,12 @@ public void adddate_has_second_signature_but_not_date_add() {

var exception =
assertThrows(
ExpressionEvaluationException.class,
() -> date_add(LocalDateTime.of(1961, 4, 12, 9, 7), 100500));
ErrorReport.class, () -> date_add(LocalDateTime.of(1961, 4, 12, 9, 7), 100500));
assertEquals(
"date_add function expected {[DATE,INTERVAL],[TIMESTAMP,INTERVAL],"
+ "[TIME,INTERVAL]}, but got [TIMESTAMP,INTEGER]",
exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import java.time.Period;
import java.time.ZoneOffset;
import org.junit.jupiter.api.Test;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.exception.ExpressionEvaluationException;

public class DateSubAndSubDateTest extends DateTimeTestBase {

Expand Down Expand Up @@ -136,12 +137,12 @@ public void subdate_has_second_signature_but_not_date_sub() {

var exception =
assertThrows(
ExpressionEvaluationException.class,
() -> date_sub(LocalDateTime.of(1961, 4, 12, 9, 7), 100500));
ErrorReport.class, () -> date_sub(LocalDateTime.of(1961, 4, 12, 9, 7), 100500));
assertEquals(
"date_sub function expected {[DATE,INTERVAL],[TIMESTAMP,INTERVAL],[TIME,INTERVAL]}, but got"
+ " [TIMESTAMP,INTEGER]",
exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.sql.common.error.ErrorCode;
import org.opensearch.sql.common.error.ErrorReport;
import org.opensearch.sql.data.type.WideningTypeRule;
import org.opensearch.sql.exception.ExpressionEvaluationException;

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -68,12 +69,12 @@ void resolve_function_not_match() {
DefaultFunctionResolver resolver =
new DefaultFunctionResolver(functionName, ImmutableMap.of(notMatchFS, notMatchBuilder));

ExpressionEvaluationException exception =
assertThrows(
ExpressionEvaluationException.class, () -> resolver.resolve(functionSignature));
ErrorReport exception =
assertThrows(ErrorReport.class, () -> resolver.resolve(functionSignature));
assertEquals(
"add function expected {[INTEGER,INTEGER]}, but got [BOOLEAN,BOOLEAN]",
exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand All @@ -100,10 +101,10 @@ void resolve_varargs_no_args_function_signature_not_match() {
DefaultFunctionResolver resolver =
new DefaultFunctionResolver(functionName, ImmutableMap.of(bestMatchFS, bestMatchBuilder));

ExpressionEvaluationException exception =
assertThrows(
ExpressionEvaluationException.class, () -> resolver.resolve(functionSignature));
ErrorReport exception =
assertThrows(ErrorReport.class, () -> resolver.resolve(functionSignature));
assertEquals("concat function expected 1-9 arguments, but got 0", exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}

@Test
Expand All @@ -120,9 +121,9 @@ void resolve_varargs_too_many_args_function_signature_not_match() {
DefaultFunctionResolver resolver =
new DefaultFunctionResolver(functionName, ImmutableMap.of(bestMatchFS, bestMatchBuilder));

ExpressionEvaluationException exception =
assertThrows(
ExpressionEvaluationException.class, () -> resolver.resolve(functionSignature));
ErrorReport exception =
assertThrows(ErrorReport.class, () -> resolver.resolve(functionSignature));
assertEquals("concat function expected 1-9 arguments, but got 10", exception.getMessage());
assertEquals(ErrorCode.TYPE_ERROR, exception.getCode());
}
}
Loading
Loading