SQL: Improve validation of unsupported fields (#35675)
Fix bug in Analyzer that caused it to report unsupported fields only when declared in projections. The rule has been extended to all field declarations. Fix #35673
This commit is contained in:
parent
f8e333b117
commit
4119409b6d
|
@ -153,8 +153,11 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||
//
|
||||
// Shared methods around the analyzer rules
|
||||
//
|
||||
|
||||
private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection<Attribute> attrList) {
|
||||
return resolveAgainstList(u, attrList, false);
|
||||
}
|
||||
|
||||
private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection<Attribute> attrList, boolean allowCompound) {
|
||||
List<Attribute> matches = new ArrayList<>();
|
||||
|
||||
// first take into account the qualified version
|
||||
|
@ -181,7 +184,7 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||
}
|
||||
|
||||
if (matches.size() == 1) {
|
||||
return matches.get(0);
|
||||
return handleSpecialFields(u, matches.get(0), allowCompound);
|
||||
}
|
||||
|
||||
return u.withUnresolvedMessage("Reference [" + u.qualifiedName()
|
||||
|
@ -193,6 +196,25 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||
);
|
||||
}
|
||||
|
||||
private static Attribute handleSpecialFields(UnresolvedAttribute u, Attribute named, boolean allowCompound) {
|
||||
// if it's a object/compound type, keep it unresolved with a nice error message
|
||||
if (named instanceof FieldAttribute) {
|
||||
FieldAttribute fa = (FieldAttribute) named;
|
||||
// unsupported types
|
||||
if (DataTypes.isUnsupported(fa.dataType())) {
|
||||
UnsupportedEsField unsupportedField = (UnsupportedEsField) fa.field();
|
||||
named = u.withUnresolvedMessage(
|
||||
"Cannot use field [" + fa.name() + "] type [" + unsupportedField.getOriginalType() + "] as is unsupported");
|
||||
}
|
||||
// compound fields
|
||||
else if (allowCompound == false && fa.dataType().isPrimitive() == false) {
|
||||
named = u.withUnresolvedMessage(
|
||||
"Cannot use field [" + fa.name() + "] type [" + fa.dataType().esType + "] only its subfields");
|
||||
}
|
||||
}
|
||||
return named;
|
||||
}
|
||||
|
||||
private static boolean hasStar(List<? extends Expression> exprs) {
|
||||
for (Expression expression : exprs) {
|
||||
if (expression instanceof UnresolvedStar) {
|
||||
|
@ -348,21 +370,6 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||
NamedExpression named = resolveAgainstList(u, childrenOutput);
|
||||
// if resolved, return it; otherwise keep it in place to be resolved later
|
||||
if (named != null) {
|
||||
// if it's a object/compound type, keep it unresolved with a nice error message
|
||||
if (named instanceof FieldAttribute) {
|
||||
FieldAttribute fa = (FieldAttribute) named;
|
||||
if (DataTypes.isUnsupported(fa.dataType())) {
|
||||
UnsupportedEsField unsupportedField = (UnsupportedEsField) fa.field();
|
||||
named = u.withUnresolvedMessage(
|
||||
"Cannot use field [" + fa.name() + "] type [" + unsupportedField.getOriginalType() +
|
||||
"] as is unsupported");
|
||||
}
|
||||
else if (!fa.dataType().isPrimitive()) {
|
||||
named = u.withUnresolvedMessage(
|
||||
"Cannot use field [" + fa.name() + "] type [" + fa.dataType().esType + "] only its subfields");
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Resolved {} to {}", u, named);
|
||||
}
|
||||
|
@ -407,15 +414,19 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
|
|||
if (us.qualifier() != null) {
|
||||
// resolve the so-called qualifier first
|
||||
// since this is an unresolved start we don't know whether it's a path or an actual qualifier
|
||||
Attribute q = resolveAgainstList(us.qualifier(), output);
|
||||
Attribute q = resolveAgainstList(us.qualifier(), output, true);
|
||||
|
||||
// the wildcard couldn't be expanded because the field doesn't exist at all
|
||||
// so, add to the list of expanded attributes its qualifier (the field without the wildcard)
|
||||
// the qualifier will be unresolved and later used in the error message presented to the user
|
||||
if (q == null) {
|
||||
expanded.add(us.qualifier());
|
||||
return expanded;
|
||||
return singletonList(us.qualifier());
|
||||
}
|
||||
// qualifier is unknown (e.g. unsupported type), bail out early
|
||||
else if (q.resolved() == false) {
|
||||
return singletonList(q);
|
||||
}
|
||||
|
||||
// now use the resolved 'qualifier' to match
|
||||
for (Attribute attr : output) {
|
||||
// filter the attributes that match based on their path
|
||||
|
|
|
@ -21,13 +21,13 @@ import java.util.TimeZone;
|
|||
public class VerifierErrorMessagesTests extends ESTestCase {
|
||||
private SqlParser parser = new SqlParser();
|
||||
|
||||
private String verify(String sql) {
|
||||
private String error(String sql) {
|
||||
Map<String, EsField> mapping = TypesTests.loadMapping("mapping-multi-field-with-nested.json");
|
||||
EsIndex test = new EsIndex("test", mapping);
|
||||
return verify(IndexResolution.valid(test), sql);
|
||||
return error(IndexResolution.valid(test), sql);
|
||||
}
|
||||
|
||||
private String verify(IndexResolution getIndexResult, String sql) {
|
||||
private String error(IndexResolution getIndexResult, String sql) {
|
||||
Analyzer analyzer = new Analyzer(new FunctionRegistry(), getIndexResult, TimeZone.getTimeZone("UTC"));
|
||||
AnalysisException e = expectThrows(AnalysisException.class, () -> analyzer.analyze(parser.createStatement(sql), true));
|
||||
assertTrue(e.getMessage().startsWith("Found "));
|
||||
|
@ -35,299 +35,335 @@ public class VerifierErrorMessagesTests extends ESTestCase {
|
|||
return e.getMessage().substring(header.length());
|
||||
}
|
||||
|
||||
private LogicalPlan accepted(String sql) {
|
||||
private LogicalPlan accept(String sql) {
|
||||
Map<String, EsField> mapping = TypesTests.loadMapping("mapping-multi-field-with-nested.json");
|
||||
EsIndex test = new EsIndex("test", mapping);
|
||||
Analyzer analyzer = new Analyzer(new FunctionRegistry(), IndexResolution.valid(test), TimeZone.getTimeZone("UTC"));
|
||||
return accept(IndexResolution.valid(test), sql);
|
||||
}
|
||||
|
||||
private LogicalPlan accept(IndexResolution resolution, String sql) {
|
||||
Analyzer analyzer = new Analyzer(new FunctionRegistry(), resolution, TimeZone.getTimeZone("UTC"));
|
||||
return analyzer.analyze(parser.createStatement(sql), true);
|
||||
}
|
||||
|
||||
public void testMissingIndex() {
|
||||
assertEquals("1:17: Unknown index [missing]", verify(IndexResolution.notFound("missing"), "SELECT foo FROM missing"));
|
||||
assertEquals("1:17: Unknown index [missing]", error(IndexResolution.notFound("missing"), "SELECT foo FROM missing"));
|
||||
}
|
||||
|
||||
public void testMissingColumn() {
|
||||
assertEquals("1:8: Unknown column [xxx]", verify("SELECT xxx FROM test"));
|
||||
assertEquals("1:8: Unknown column [xxx]", error("SELECT xxx FROM test"));
|
||||
}
|
||||
|
||||
|
||||
public void testMissingColumnFilter() {
|
||||
assertEquals("1:26: Unknown column [xxx]", error("SELECT * FROM test WHERE xxx > 1"));
|
||||
}
|
||||
|
||||
public void testMissingColumnWithWildcard() {
|
||||
assertEquals("1:8: Unknown column [xxx]", verify("SELECT xxx.* FROM test"));
|
||||
assertEquals("1:8: Unknown column [xxx]", error("SELECT xxx.* FROM test"));
|
||||
}
|
||||
|
||||
public void testMisspelledColumnWithWildcard() {
|
||||
assertEquals("1:8: Unknown column [tex], did you mean [text]?", verify("SELECT tex.* FROM test"));
|
||||
assertEquals("1:8: Unknown column [tex], did you mean [text]?", error("SELECT tex.* FROM test"));
|
||||
}
|
||||
|
||||
public void testColumnWithNoSubFields() {
|
||||
assertEquals("1:8: Cannot determine columns for [text.*]", verify("SELECT text.* FROM test"));
|
||||
assertEquals("1:8: Cannot determine columns for [text.*]", error("SELECT text.* FROM test"));
|
||||
}
|
||||
|
||||
public void testMultipleColumnsWithWildcard1() {
|
||||
assertEquals("1:14: Unknown column [a]\n" +
|
||||
"line 1:17: Unknown column [b]\n" +
|
||||
"line 1:22: Unknown column [c]\n" +
|
||||
"line 1:25: Unknown column [tex], did you mean [text]?", verify("SELECT bool, a, b.*, c, tex.* FROM test"));
|
||||
assertEquals("1:14: Unknown column [a]\n" +
|
||||
"line 1:17: Unknown column [b]\n" +
|
||||
"line 1:22: Unknown column [c]\n" +
|
||||
"line 1:25: Unknown column [tex], did you mean [text]?", error("SELECT bool, a, b.*, c, tex.* FROM test"));
|
||||
}
|
||||
|
||||
public void testMultipleColumnsWithWildcard2() {
|
||||
assertEquals("1:8: Unknown column [tex], did you mean [text]?\n" +
|
||||
"line 1:21: Unknown column [a]\n" +
|
||||
"line 1:24: Unknown column [dat], did you mean [date]?\n" +
|
||||
"line 1:31: Unknown column [c]", verify("SELECT tex.*, bool, a, dat.*, c FROM test"));
|
||||
assertEquals("1:8: Unknown column [tex], did you mean [text]?\n" +
|
||||
"line 1:21: Unknown column [a]\n" +
|
||||
"line 1:24: Unknown column [dat], did you mean [date]?\n" +
|
||||
"line 1:31: Unknown column [c]", error("SELECT tex.*, bool, a, dat.*, c FROM test"));
|
||||
}
|
||||
|
||||
public void testMultipleColumnsWithWildcard3() {
|
||||
assertEquals("1:8: Unknown column [ate], did you mean [date]?\n" +
|
||||
"line 1:21: Unknown column [keyw], did you mean [keyword]?\n" +
|
||||
"line 1:29: Unknown column [da], did you mean [date]?" , verify("SELECT ate.*, bool, keyw.*, da FROM test"));
|
||||
assertEquals("1:8: Unknown column [ate], did you mean [date]?\n" +
|
||||
"line 1:21: Unknown column [keyw], did you mean [keyword]?\n" +
|
||||
"line 1:29: Unknown column [da], did you mean [date]?" , error("SELECT ate.*, bool, keyw.*, da FROM test"));
|
||||
}
|
||||
|
||||
public void testMisspelledColumn() {
|
||||
assertEquals("1:8: Unknown column [txt], did you mean [text]?", verify("SELECT txt FROM test"));
|
||||
assertEquals("1:8: Unknown column [txt], did you mean [text]?", error("SELECT txt FROM test"));
|
||||
}
|
||||
|
||||
public void testFunctionOverMissingField() {
|
||||
assertEquals("1:12: Unknown column [xxx]", verify("SELECT ABS(xxx) FROM test"));
|
||||
assertEquals("1:12: Unknown column [xxx]", error("SELECT ABS(xxx) FROM test"));
|
||||
}
|
||||
|
||||
public void testFunctionOverMissingFieldInFilter() {
|
||||
assertEquals("1:30: Unknown column [xxx]", error("SELECT * FROM test WHERE ABS(xxx) > 1"));
|
||||
}
|
||||
|
||||
public void testMissingFunction() {
|
||||
assertEquals("1:8: Unknown function [ZAZ]", verify("SELECT ZAZ(bool) FROM test"));
|
||||
assertEquals("1:8: Unknown function [ZAZ]", error("SELECT ZAZ(bool) FROM test"));
|
||||
}
|
||||
|
||||
public void testMisspelledFunction() {
|
||||
assertEquals("1:8: Unknown function [COONT], did you mean any of [COUNT, COT, CONCAT]?", verify("SELECT COONT(bool) FROM test"));
|
||||
assertEquals("1:8: Unknown function [COONT], did you mean any of [COUNT, COT, CONCAT]?", error("SELECT COONT(bool) FROM test"));
|
||||
}
|
||||
|
||||
public void testMissingColumnInGroupBy() {
|
||||
assertEquals("1:41: Unknown column [xxx]", verify("SELECT * FROM test GROUP BY DAY_OF_YEAR(xxx)"));
|
||||
assertEquals("1:41: Unknown column [xxx]", error("SELECT * FROM test GROUP BY DAY_OF_YEAR(xxx)"));
|
||||
}
|
||||
|
||||
public void testFilterOnUnknownColumn() {
|
||||
assertEquals("1:26: Unknown column [xxx]", verify("SELECT * FROM test WHERE xxx = 1"));
|
||||
assertEquals("1:26: Unknown column [xxx]", error("SELECT * FROM test WHERE xxx = 1"));
|
||||
}
|
||||
|
||||
public void testMissingColumnInOrderBy() {
|
||||
// xxx offset is that of the order by field
|
||||
assertEquals("1:29: Unknown column [xxx]", verify("SELECT * FROM test ORDER BY xxx"));
|
||||
assertEquals("1:29: Unknown column [xxx]", error("SELECT * FROM test ORDER BY xxx"));
|
||||
}
|
||||
|
||||
public void testMissingColumnFunctionInOrderBy() {
|
||||
// xxx offset is that of the order by field
|
||||
assertEquals("1:41: Unknown column [xxx]", verify("SELECT * FROM test ORDER BY DAY_oF_YEAR(xxx)"));
|
||||
assertEquals("1:41: Unknown column [xxx]", error("SELECT * FROM test ORDER BY DAY_oF_YEAR(xxx)"));
|
||||
}
|
||||
|
||||
public void testMissingExtract() {
|
||||
assertEquals("1:8: Unknown datetime field [ZAZ]", verify("SELECT EXTRACT(ZAZ FROM date) FROM test"));
|
||||
assertEquals("1:8: Unknown datetime field [ZAZ]", error("SELECT EXTRACT(ZAZ FROM date) FROM test"));
|
||||
}
|
||||
|
||||
public void testMissingExtractSimilar() {
|
||||
assertEquals("1:8: Unknown datetime field [DAP], did you mean [DAY]?", verify("SELECT EXTRACT(DAP FROM date) FROM test"));
|
||||
assertEquals("1:8: Unknown datetime field [DAP], did you mean [DAY]?", error("SELECT EXTRACT(DAP FROM date) FROM test"));
|
||||
}
|
||||
|
||||
public void testMissingExtractSimilarMany() {
|
||||
assertEquals("1:8: Unknown datetime field [DOP], did you mean any of [DOM, DOW, DOY]?",
|
||||
verify("SELECT EXTRACT(DOP FROM date) FROM test"));
|
||||
error("SELECT EXTRACT(DOP FROM date) FROM test"));
|
||||
}
|
||||
|
||||
public void testExtractNonDateTime() {
|
||||
assertEquals("1:8: Invalid datetime field [ABS]. Use any datetime function.", verify("SELECT EXTRACT(ABS FROM date) FROM test"));
|
||||
assertEquals("1:8: Invalid datetime field [ABS]. Use any datetime function.", error("SELECT EXTRACT(ABS FROM date) FROM test"));
|
||||
}
|
||||
|
||||
public void testMultipleColumns() {
|
||||
// xxx offset is that of the order by field
|
||||
assertEquals("1:43: Unknown column [xxx]\nline 1:8: Unknown column [xxx]",
|
||||
verify("SELECT xxx FROM test GROUP BY DAY_oF_YEAR(xxx)"));
|
||||
error("SELECT xxx FROM test GROUP BY DAY_oF_YEAR(xxx)"));
|
||||
}
|
||||
|
||||
// GROUP BY
|
||||
public void testGroupBySelectNonGrouped() {
|
||||
assertEquals("1:8: Cannot use non-grouped column [text], expected [int]",
|
||||
verify("SELECT text, int FROM test GROUP BY int"));
|
||||
error("SELECT text, int FROM test GROUP BY int"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByNonGrouped() {
|
||||
assertEquals("1:50: Cannot order by non-grouped column [bool], expected [text]",
|
||||
verify("SELECT MAX(int) FROM test GROUP BY text ORDER BY bool"));
|
||||
error("SELECT MAX(int) FROM test GROUP BY text ORDER BY bool"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByNonGrouped_WithHaving() {
|
||||
assertEquals("1:71: Cannot order by non-grouped column [bool], expected [text]",
|
||||
verify("SELECT MAX(int) FROM test GROUP BY text HAVING MAX(int) > 10 ORDER BY bool"));
|
||||
error("SELECT MAX(int) FROM test GROUP BY text HAVING MAX(int) > 10 ORDER BY bool"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByAliasedInSelectAllowed() {
|
||||
LogicalPlan lp = accepted("SELECT text t FROM test GROUP BY text ORDER BY t");
|
||||
LogicalPlan lp = accept("SELECT text t FROM test GROUP BY text ORDER BY t");
|
||||
assertNotNull(lp);
|
||||
}
|
||||
|
||||
public void testGroupByOrderByScalarOverNonGrouped() {
|
||||
assertEquals("1:50: Cannot order by non-grouped column [YEAR(date [UTC])], expected [text]",
|
||||
verify("SELECT MAX(int) FROM test GROUP BY text ORDER BY YEAR(date)"));
|
||||
error("SELECT MAX(int) FROM test GROUP BY text ORDER BY YEAR(date)"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByScalarOverNonGrouped_WithHaving() {
|
||||
assertEquals("1:71: Cannot order by non-grouped column [YEAR(date [UTC])], expected [text]",
|
||||
verify("SELECT MAX(int) FROM test GROUP BY text HAVING MAX(int) > 10 ORDER BY YEAR(date)"));
|
||||
error("SELECT MAX(int) FROM test GROUP BY text HAVING MAX(int) > 10 ORDER BY YEAR(date)"));
|
||||
}
|
||||
|
||||
public void testGroupByHavingNonGrouped() {
|
||||
assertEquals("1:48: Cannot filter by non-grouped column [int], expected [text]",
|
||||
verify("SELECT AVG(int) FROM test GROUP BY text HAVING int > 10"));
|
||||
error("SELECT AVG(int) FROM test GROUP BY text HAVING int > 10"));
|
||||
}
|
||||
|
||||
public void testGroupByAggregate() {
|
||||
assertEquals("1:36: Cannot use an aggregate [AVG] for grouping",
|
||||
verify("SELECT AVG(int) FROM test GROUP BY AVG(int)"));
|
||||
error("SELECT AVG(int) FROM test GROUP BY AVG(int)"));
|
||||
}
|
||||
|
||||
public void testStarOnNested() {
|
||||
assertNotNull(accept("SELECT dep.* FROM test"));
|
||||
}
|
||||
|
||||
public void testGroupByOnNested() {
|
||||
assertEquals("1:38: Grouping isn't (yet) compatible with nested fields [dep.dep_id]",
|
||||
verify("SELECT dep.dep_id FROM test GROUP BY dep.dep_id"));
|
||||
error("SELECT dep.dep_id FROM test GROUP BY dep.dep_id"));
|
||||
}
|
||||
|
||||
public void testHavingOnNested() {
|
||||
assertEquals("1:51: HAVING isn't (yet) compatible with nested fields [dep.start_date]",
|
||||
verify("SELECT int FROM test GROUP BY int HAVING AVG(YEAR(dep.start_date)) > 1980"));
|
||||
error("SELECT int FROM test GROUP BY int HAVING AVG(YEAR(dep.start_date)) > 1980"));
|
||||
}
|
||||
|
||||
public void testGroupByScalarFunctionWithAggOnTarget() {
|
||||
assertEquals("1:31: Cannot use an aggregate [AVG] for grouping",
|
||||
verify("SELECT int FROM test GROUP BY AVG(int) + 2"));
|
||||
error("SELECT int FROM test GROUP BY AVG(int) + 2"));
|
||||
}
|
||||
|
||||
public void testUnsupportedType() {
|
||||
assertEquals("1:8: Cannot use field [unsupported] type [ip_range] as is unsupported",
|
||||
verify("SELECT unsupported FROM test"));
|
||||
error("SELECT unsupported FROM test"));
|
||||
}
|
||||
|
||||
public void testUnsupportedStarExpansion() {
|
||||
assertEquals("1:8: Cannot use field [unsupported] type [ip_range] as is unsupported",
|
||||
error("SELECT unsupported.* FROM test"));
|
||||
}
|
||||
|
||||
public void testUnsupportedTypeInFilter() {
|
||||
assertEquals("1:26: Cannot use field [unsupported] type [ip_range] as is unsupported",
|
||||
error("SELECT * FROM test WHERE unsupported > 1"));
|
||||
}
|
||||
|
||||
public void testUnsupportedTypeInFunction() {
|
||||
assertEquals("1:12: Cannot use field [unsupported] type [ip_range] as is unsupported",
|
||||
error("SELECT ABS(unsupported) FROM test"));
|
||||
}
|
||||
|
||||
public void testUnsupportedTypeInOrder() {
|
||||
assertEquals("1:29: Cannot use field [unsupported] type [ip_range] as is unsupported",
|
||||
error("SELECT * FROM test ORDER BY unsupported"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByNonKey() {
|
||||
assertEquals("1:52: Cannot order by non-grouped column [a], expected [bool]",
|
||||
verify("SELECT AVG(int) a FROM test GROUP BY bool ORDER BY a"));
|
||||
error("SELECT AVG(int) a FROM test GROUP BY bool ORDER BY a"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByFunctionOverKey() {
|
||||
assertEquals("1:44: Cannot order by non-grouped column [MAX(int)], expected [int]",
|
||||
verify("SELECT int FROM test GROUP BY int ORDER BY MAX(int)"));
|
||||
error("SELECT int FROM test GROUP BY int ORDER BY MAX(int)"));
|
||||
}
|
||||
|
||||
public void testGroupByOrderByScore() {
|
||||
assertEquals("1:44: Cannot order by non-grouped column [SCORE()], expected [int]",
|
||||
verify("SELECT int FROM test GROUP BY int ORDER BY SCORE()"));
|
||||
error("SELECT int FROM test GROUP BY int ORDER BY SCORE()"));
|
||||
}
|
||||
|
||||
public void testHavingOnColumn() {
|
||||
assertEquals("1:42: Cannot filter HAVING on non-aggregate [int]; consider using WHERE instead",
|
||||
verify("SELECT int FROM test GROUP BY int HAVING int > 2"));
|
||||
error("SELECT int FROM test GROUP BY int HAVING int > 2"));
|
||||
}
|
||||
|
||||
public void testHavingOnScalar() {
|
||||
assertEquals("1:42: Cannot filter HAVING on non-aggregate [int]; consider using WHERE instead",
|
||||
verify("SELECT int FROM test GROUP BY int HAVING 2 < ABS(int)"));
|
||||
error("SELECT int FROM test GROUP BY int HAVING 2 < ABS(int)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypes_SelectClause() {
|
||||
assertEquals("1:17: expected data type [INTEGER], value provided is of type [KEYWORD]",
|
||||
verify("SELECT 1 IN (2, '3', 4)"));
|
||||
error("SELECT 1 IN (2, '3', 4)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypes_SelectClause() {
|
||||
assertEquals("1:27: expected data type [INTEGER], value provided is of type [KEYWORD]",
|
||||
verify("SELECT 1 = 1 OR 1 IN (2, '3', 4)"));
|
||||
error("SELECT 1 = 1 OR 1 IN (2, '3', 4)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypesFromLeftValue_SelectClause() {
|
||||
assertEquals("1:14: expected data type [INTEGER], value provided is of type [KEYWORD]",
|
||||
verify("SELECT 1 IN ('foo', 'bar')"));
|
||||
error("SELECT 1 IN ('foo', 'bar')"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypesFromLeftValue_SelectClause() {
|
||||
assertEquals("1:29: expected data type [KEYWORD], value provided is of type [INTEGER]",
|
||||
verify("SELECT 1 = 1 OR 'foo' IN (2, 3)"));
|
||||
error("SELECT 1 = 1 OR 'foo' IN (2, 3)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypes_WhereClause() {
|
||||
assertEquals("1:49: expected data type [TEXT], value provided is of type [INTEGER]",
|
||||
verify("SELECT * FROM test WHERE text IN ('foo', 'bar', 4)"));
|
||||
error("SELECT * FROM test WHERE text IN ('foo', 'bar', 4)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypes_WhereClause() {
|
||||
assertEquals("1:60: expected data type [TEXT], value provided is of type [INTEGER]",
|
||||
verify("SELECT * FROM test WHERE int = 1 OR text IN ('foo', 'bar', 2)"));
|
||||
error("SELECT * FROM test WHERE int = 1 OR text IN ('foo', 'bar', 2)"));
|
||||
}
|
||||
|
||||
public void testInWithDifferentDataTypesFromLeftValue_WhereClause() {
|
||||
assertEquals("1:35: expected data type [TEXT], value provided is of type [INTEGER]",
|
||||
verify("SELECT * FROM test WHERE text IN (1, 2)"));
|
||||
error("SELECT * FROM test WHERE text IN (1, 2)"));
|
||||
}
|
||||
|
||||
public void testInNestedWithDifferentDataTypesFromLeftValue_WhereClause() {
|
||||
assertEquals("1:46: expected data type [TEXT], value provided is of type [INTEGER]",
|
||||
verify("SELECT * FROM test WHERE int = 1 OR text IN (1, 2)"));
|
||||
error("SELECT * FROM test WHERE int = 1 OR text IN (1, 2)"));
|
||||
}
|
||||
|
||||
public void testNotSupportedAggregateOnDate() {
|
||||
assertEquals("1:8: [AVG] argument must be [numeric], found value [date] type [date]",
|
||||
verify("SELECT AVG(date) FROM test"));
|
||||
error("SELECT AVG(date) FROM test"));
|
||||
}
|
||||
|
||||
public void testNotSupportedAggregateOnString() {
|
||||
assertEquals("1:8: [MAX] argument must be [numeric or date], found value [keyword] type [keyword]",
|
||||
verify("SELECT MAX(keyword) FROM test"));
|
||||
error("SELECT MAX(keyword) FROM test"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForStringFunction_WithOneArg() {
|
||||
assertEquals("1:8: [LENGTH] argument must be [string], found value [1] type [integer]",
|
||||
verify("SELECT LENGTH(1)"));
|
||||
error("SELECT LENGTH(1)"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForNumericFunction_WithOneArg() {
|
||||
assertEquals("1:8: [COS] argument must be [numeric], found value [foo] type [keyword]",
|
||||
verify("SELECT COS('foo')"));
|
||||
error("SELECT COS('foo')"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForBooleanFunction_WithOneArg() {
|
||||
assertEquals("1:8: [NOT] argument must be [boolean], found value [foo] type [keyword]",
|
||||
verify("SELECT NOT 'foo'"));
|
||||
error("SELECT NOT 'foo'"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForStringFunction_WithTwoArgs() {
|
||||
assertEquals("1:8: [CONCAT] first argument must be [string], found value [1] type [integer]",
|
||||
verify("SELECT CONCAT(1, 'bar')"));
|
||||
error("SELECT CONCAT(1, 'bar')"));
|
||||
assertEquals("1:8: [CONCAT] second argument must be [string], found value [2] type [integer]",
|
||||
verify("SELECT CONCAT('foo', 2)"));
|
||||
error("SELECT CONCAT('foo', 2)"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForNumericFunction_WithTwoArgs() {
|
||||
assertEquals("1:8: [TRUNCATE] first argument must be [numeric], found value [foo] type [keyword]",
|
||||
verify("SELECT TRUNCATE('foo', 2)"));
|
||||
error("SELECT TRUNCATE('foo', 2)"));
|
||||
assertEquals("1:8: [TRUNCATE] second argument must be [numeric], found value [bar] type [keyword]",
|
||||
verify("SELECT TRUNCATE(1.2, 'bar')"));
|
||||
error("SELECT TRUNCATE(1.2, 'bar')"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForBooleanFuntion_WithTwoArgs() {
|
||||
assertEquals("1:8: [OR] first argument must be [boolean], found value [1] type [integer]",
|
||||
verify("SELECT 1 OR true"));
|
||||
error("SELECT 1 OR true"));
|
||||
assertEquals("1:8: [OR] second argument must be [boolean], found value [2] type [integer]",
|
||||
verify("SELECT true OR 2"));
|
||||
error("SELECT true OR 2"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForFunction_WithThreeArgs() {
|
||||
assertEquals("1:8: [REPLACE] first argument must be [string], found value [1] type [integer]",
|
||||
verify("SELECT REPLACE(1, 'foo', 'bar')"));
|
||||
error("SELECT REPLACE(1, 'foo', 'bar')"));
|
||||
assertEquals("1:8: [REPLACE] second argument must be [string], found value [2] type [integer]",
|
||||
verify("SELECT REPLACE('text', 2, 'bar')"));
|
||||
error("SELECT REPLACE('text', 2, 'bar')"));
|
||||
assertEquals("1:8: [REPLACE] third argument must be [string], found value [3] type [integer]",
|
||||
verify("SELECT REPLACE('text', 'foo', 3)"));
|
||||
error("SELECT REPLACE('text', 'foo', 3)"));
|
||||
}
|
||||
|
||||
public void testInvalidTypeForFunction_WithFourArgs() {
|
||||
assertEquals("1:8: [INSERT] first argument must be [string], found value [1] type [integer]",
|
||||
verify("SELECT INSERT(1, 1, 2, 'new')"));
|
||||
error("SELECT INSERT(1, 1, 2, 'new')"));
|
||||
assertEquals("1:8: [INSERT] second argument must be [numeric], found value [foo] type [keyword]",
|
||||
verify("SELECT INSERT('text', 'foo', 2, 'new')"));
|
||||
error("SELECT INSERT('text', 'foo', 2, 'new')"));
|
||||
assertEquals("1:8: [INSERT] third argument must be [numeric], found value [bar] type [keyword]",
|
||||
verify("SELECT INSERT('text', 1, 'bar', 'new')"));
|
||||
error("SELECT INSERT('text', 1, 'bar', 'new')"));
|
||||
assertEquals("1:8: [INSERT] fourth argument must be [string], found value [3] type [integer]",
|
||||
verify("SELECT INSERT('text', 1, 2, 3)"));
|
||||
error("SELECT INSERT('text', 1, 2, 3)"));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue