diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java index b376e38e40b..ec5f62e5987 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java @@ -153,8 +153,11 @@ public class Analyzer extends RuleExecutor { // // Shared methods around the analyzer rules // - private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection attrList) { + return resolveAgainstList(u, attrList, false); + } + + private static Attribute resolveAgainstList(UnresolvedAttribute u, Collection attrList, boolean allowCompound) { List matches = new ArrayList<>(); // first take into account the qualified version @@ -181,7 +184,7 @@ public class Analyzer extends RuleExecutor { } 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 { ); } + 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 exprs) { for (Expression expression : exprs) { if (expression instanceof UnresolvedStar) { @@ -348,21 +370,6 @@ public class Analyzer extends RuleExecutor { 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 { 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 diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java index 3b03079ca72..347f085e142 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java @@ -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 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 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)")); } -} +} \ No newline at end of file