1
0
Эх сурвалжийг харах

SQL: handle wildcard expansion on incorrect fields (#35134)

Andrei Stefan 7 жил өмнө
parent
commit
b6659847c2

+ 1 - 1
x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/cli/ErrorsTestCase.java

@@ -27,7 +27,7 @@ public abstract class ErrorsTestCase extends CliIntegrationTestCase implements o
     @Override
     public void testSelectInvalidSql() throws Exception {
         assertFoundOneProblem(command("SELECT * FRO"));
-        assertEquals("line 1:8: Cannot determine columns for *" + END, readLine());
+        assertEquals("line 1:8: Cannot determine columns for [*]" + END, readLine());
     }
 
     @Override

+ 1 - 1
x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/jdbc/ErrorsTestCase.java

@@ -20,7 +20,7 @@ public class ErrorsTestCase extends JdbcIntegrationTestCase implements org.elast
     public void testSelectInvalidSql() throws Exception {
         try (Connection c = esJdbc()) {
             SQLException e = expectThrows(SQLException.class, () -> c.prepareStatement("SELECT * FRO").executeQuery());
-            assertEquals("Found 1 problem(s)\nline 1:8: Cannot determine columns for *", e.getMessage());
+            assertEquals("Found 1 problem(s)\nline 1:8: Cannot determine columns for [*]", e.getMessage());
         }
     }
 

+ 1 - 1
x-pack/plugin/sql/qa/src/main/java/org/elasticsearch/xpack/sql/qa/rest/RestSqlTestCase.java

@@ -202,7 +202,7 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
     @Override
     public void testSelectInvalidSql() {
         String mode = randomFrom("jdbc", "plain");
-        expectBadRequest(() -> runSql(mode, "SELECT * FRO"), containsString("1:8: Cannot determine columns for *"));
+        expectBadRequest(() -> runSql(mode, "SELECT * FRO"), containsString("1:8: Cannot determine columns for [*]"));
     }
 
     @Override

+ 14 - 1
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java

@@ -380,7 +380,13 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
             List<Attribute> output = child.output();
             for (NamedExpression ne : projections) {
                 if (ne instanceof UnresolvedStar) {
-                    result.addAll(expandStar((UnresolvedStar) ne, output));
+                    List<NamedExpression> expanded = expandStar((UnresolvedStar) ne, output);
+                    // the field exists, but cannot be expanded (no sub-fields)
+                    if (expanded.isEmpty()) {
+                        result.add(ne);
+                    } else {
+                        result.addAll(expanded);
+                    }
                 } else if (ne instanceof UnresolvedAlias) {
                     UnresolvedAlias ua = (UnresolvedAlias) ne;
                     if (ua.child() instanceof UnresolvedStar) {
@@ -403,6 +409,13 @@ public class Analyzer extends RuleExecutor<LogicalPlan> {
                 // 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);
 
+                // 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;
+                }
                 // now use the resolved 'qualifier' to match
                 for (Attribute attr : output) {
                     // filter the attributes that match based on their path

+ 2 - 2
x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/UnresolvedStar.java

@@ -66,12 +66,12 @@ public class UnresolvedStar extends UnresolvedNamedExpression {
     }
 
     private String message() {
-        return (qualifier() != null ? qualifier() + "." : "") + "*";
+        return (qualifier() != null ? qualifier().qualifiedName() + "." : "") + "*";
     }
 
     @Override
     public String unresolvedMessage() {
-        return "Cannot determine columns for " + message();
+        return "Cannot determine columns for [" + message() + "]";
     }
 
     @Override

+ 32 - 0
x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerifierErrorMessagesTests.java

@@ -49,6 +49,38 @@ public class VerifierErrorMessagesTests extends ESTestCase {
     public void testMissingColumn() {
         assertEquals("1:8: Unknown column [xxx]", verify("SELECT xxx FROM test"));
     }
+    
+    public void testMissingColumnWithWildcard() {
+        assertEquals("1:8: Unknown column [xxx]", verify("SELECT xxx.* FROM test"));
+    }
+    
+    public void testMisspelledColumnWithWildcard() {
+        assertEquals("1:8: Unknown column [tex], did you mean [text]?", verify("SELECT tex.* FROM test"));
+    }
+    
+    public void testColumnWithNoSubFields() {
+        assertEquals("1:8: Cannot determine columns for [text.*]", verify("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"));
+    }
+    
+    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"));
+    }
+    
+    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"));
+    }
 
     public void testMisspelledColumn() {
         assertEquals("1:8: Unknown column [txt], did you mean [text]?", verify("SELECT txt FROM test"));