diff --git a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java index 56974537304..e69d5b02013 100644 --- a/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java +++ b/x-pack/plugin/sql/jdbc/src/main/java/org/elasticsearch/xpack/sql/jdbc/JdbcDatabaseMetaData.java @@ -257,8 +257,7 @@ class JdbcDatabaseMetaData implements DatabaseMetaData, JdbcWrapper { @Override public boolean supportsConvert() throws SQLException { - //TODO: add Convert - return false; + return true; } @Override @@ -774,14 +773,14 @@ class JdbcDatabaseMetaData implements DatabaseMetaData, JdbcWrapper { @Override public ResultSet getCatalogs() throws SQLException { // TABLE_CAT is the first column - Object[][] data = queryColumn(con, "SYS TABLES CATALOG LIKE '%'", 1); + Object[][] data = queryColumn(con, "SYS TABLES CATALOG LIKE '%' LIKE ''", 1); return memorySet(con.cfg, columnInfo("", "TABLE_CAT"), data); } @Override public ResultSet getTableTypes() throws SQLException { // TABLE_TYPE (4) - Object[][] data = queryColumn(con, "SYS TABLES TYPE '%'", 4); + Object[][] data = queryColumn(con, "SYS TABLES CATALOG LIKE '' LIKE '' TYPE '%'", 4); return memorySet(con.cfg, columnInfo("", "TABLE_TYPE"), data); } diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java index 87709ac104e..04935023747 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/parser/CommandBuilder.java @@ -149,9 +149,8 @@ abstract class CommandBuilder extends LogicalPlanBuilder { if (value != null) { // check special ODBC wildcard case if (value.equals(StringUtils.SQL_WILDCARD) && ctx.string().size() == 1) { - // convert % to enumeration - // https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/value-list-arguments?view=ssdt-18vs2017 - types.addAll(IndexType.VALID); + // treat % as null + // https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/value-list-arguments } // special case for legacy apps (like msquery) that always asks for 'TABLE' // which we manually map to all concrete tables supported diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTables.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTables.java index 5ce1e6dcc8a..53f1e1019b7 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTables.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTables.java @@ -14,9 +14,8 @@ import org.elasticsearch.xpack.sql.plan.logical.command.Command; import org.elasticsearch.xpack.sql.session.Rows; import org.elasticsearch.xpack.sql.session.SchemaRowSet; import org.elasticsearch.xpack.sql.session.SqlSession; -import org.elasticsearch.xpack.sql.tree.Source; import org.elasticsearch.xpack.sql.tree.NodeInfo; -import org.elasticsearch.xpack.sql.util.CollectionUtils; +import org.elasticsearch.xpack.sql.tree.Source; import java.util.ArrayList; import java.util.Comparator; @@ -77,8 +76,11 @@ public class SysTables extends Command { // namely one param specified with '%', everything else empty string // https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqltables-function?view=ssdt-18vs2017#comments - if (clusterPattern != null && clusterPattern.pattern().equals(SQL_WILDCARD)) { - if ((pattern == null || pattern.pattern().isEmpty()) && CollectionUtils.isEmpty(types)) { + // catalog enumeration + if (clusterPattern == null || clusterPattern.pattern().equals(SQL_WILDCARD)) { + // enumerate only if pattern is "" and no types are specified (types is null) + if (pattern != null && pattern.pattern().isEmpty() && index == null + && types == null) { Object[] enumeration = new Object[10]; // send only the cluster, everything else null enumeration[0] = cluster; @@ -87,12 +89,15 @@ public class SysTables extends Command { } } - // if no types were specified (the parser takes care of the % case) - if (IndexType.VALID.equals(types)) { - if ((clusterPattern == null || clusterPattern.pattern().isEmpty()) - && (pattern == null || pattern.pattern().isEmpty())) { + // enumerate types + // if no types are specified (the parser takes care of the % case) + if (types == null) { + // empty string for catalog + if (clusterPattern != null && clusterPattern.pattern().isEmpty() + // empty string for table like and no index specified + && pattern != null && pattern.pattern().isEmpty() && index == null) { List> values = new ArrayList<>(); - // send only the types, everything else null + // send only the types, everything else is made of empty strings for (IndexType type : IndexType.VALID) { Object[] enumeration = new Object[10]; enumeration[3] = type.toSql(); @@ -105,7 +110,7 @@ public class SysTables extends Command { } } - + // no enumeration pattern found, list actual tables String cRegex = clusterPattern != null ? clusterPattern.asJavaRegex() : null; // if the catalog doesn't match, don't return any results diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTablesTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTablesTests.java index 74ecdc80c12..e2baeb2d8af 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTablesTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/plan/logical/command/sys/SysTablesTests.java @@ -51,20 +51,60 @@ public class SysTablesTests extends ESTestCase { private final IndexInfo index = new IndexInfo("test", IndexType.INDEX); private final IndexInfo alias = new IndexInfo("alias", IndexType.ALIAS); - public void testSysTablesEnumerateCatalog() throws Exception { - executeCommand("SYS TABLES CATALOG LIKE '%'", r -> { + // + // catalog enumeration + // + public void testSysTablesCatalogEnumeration() throws Exception { + executeCommand("SYS TABLES CATALOG LIKE '%' LIKE ''", r -> { assertEquals(1, r.size()); assertEquals(CLUSTER_NAME, r.column(0)); - }); + // everything else should be null + for (int i = 1; i < 10; i++) { + assertNull(r.column(i)); + } + }, index); } - public void testSysTablesEnumerateTypes() throws Exception { - executeCommand("SYS TABLES TYPE '%'", r -> { + // + // table types enumeration + // + public void testSysTablesTypesEnumerationWoString() throws Exception { + executeCommand("SYS TABLES CATALOG LIKE '' LIKE '' ", r -> { assertEquals(2, r.size()); assertEquals("BASE TABLE", r.column(3)); assertTrue(r.advanceRow()); assertEquals("VIEW", r.column(3)); - }); + }, new IndexInfo[0]); + } + + public void testSysTablesEnumerateTypes() throws Exception { + executeCommand("SYS TABLES CATALOG LIKE '' LIKE '' TYPE '%'", r -> { + assertEquals(2, r.size()); + assertEquals("BASE TABLE", r.column(3)); + assertTrue(r.advanceRow()); + assertEquals("VIEW", r.column(3)); + }, alias, index); + } + + public void testSysTablesTypesEnumeration() throws Exception { + executeCommand("SYS TABLES CATALOG LIKE '' LIKE '' TYPE '%'", r -> { + assertEquals(2, r.size()); + + Iterator it = IndexType.VALID.stream().sorted(Comparator.comparing(IndexType::toSql)).iterator(); + + for (int t = 0; t < r.size(); t++) { + assertEquals(it.next().toSql(), r.column(3)); + + // everything else should be null + for (int i = 0; i < 10; i++) { + if (i != 3) { + assertNull(r.column(i)); + } + } + + r.advanceRow(); + } + }, new IndexInfo[0]); } public void testSysTablesDifferentCatalog() throws Exception { @@ -77,17 +117,42 @@ public class SysTablesTests extends ESTestCase { public void testSysTablesNoTypes() throws Exception { executeCommand("SYS TABLES", r -> { assertEquals(2, r.size()); + assertEquals("test", r.column(2)); assertEquals("BASE TABLE", r.column(3)); assertTrue(r.advanceRow()); + assertEquals("alias", r.column(2)); + assertEquals("VIEW", r.column(3)); + }, index, alias); + } + + public void testSysTablesWithLegacyTypes() throws Exception { + executeCommand("SYS TABLES TYPE 'TABLE', 'ALIAS'", r -> { + assertEquals(2, r.size()); + assertEquals("test", r.column(2)); + assertEquals("TABLE", r.column(3)); + assertTrue(r.advanceRow()); + assertEquals("alias", r.column(2)); + assertEquals("VIEW", r.column(3)); + }, index, alias); + } + + public void testSysTablesWithProperTypes() throws Exception { + executeCommand("SYS TABLES TYPE 'BASE TABLE', 'ALIAS'", r -> { + assertEquals(2, r.size()); + assertEquals("test", r.column(2)); + assertEquals("BASE TABLE", r.column(3)); + assertTrue(r.advanceRow()); + assertEquals("alias", r.column(2)); assertEquals("VIEW", r.column(3)); }, index, alias); } public void testSysTablesPattern() throws Exception { executeCommand("SYS TABLES LIKE '%'", r -> { - assertEquals("test", r.column(2)); - assertTrue(r.advanceRow()); assertEquals(2, r.size()); + assertEquals("test", r.column(2)); + assertEquals("BASE TABLE", r.column(3)); + assertTrue(r.advanceRow()); assertEquals("alias", r.column(2)); }, index, alias); } @@ -130,7 +195,18 @@ public class SysTablesTests extends ESTestCase { assertEquals("test", r.column(2)); assertEquals("TABLE", r.column(3)); }, index); + } + public void testSysTablesNoPatternWithTypesSpecifiedInLegacyMode() throws Exception { + executeCommand("SYS TABLES TYPE 'TABLE','VIEW'", r -> { + assertEquals(2, r.size()); + assertEquals("test", r.column(2)); + assertEquals("TABLE", r.column(3)); + assertTrue(r.advanceRow()); + assertEquals("alias", r.column(2)); + assertEquals("VIEW", r.column(3)); + + }, index, alias); } public void testSysTablesOnlyIndicesLegacyModeParameterized() throws Exception { @@ -192,43 +268,6 @@ public class SysTablesTests extends ESTestCase { }, new IndexInfo[0]); } - public void testSysTablesCatalogEnumeration() throws Exception { - executeCommand("SYS TABLES CATALOG LIKE '%' LIKE ''", r -> { - assertEquals(1, r.size()); - assertEquals(CLUSTER_NAME, r.column(0)); - // everything else should be null - for (int i = 1; i < 10; i++) { - assertNull(r.column(i)); - } - }, new IndexInfo[0]); - } - - public void testSysTablesTypesEnumeration() throws Exception { - executeCommand("SYS TABLES CATALOG LIKE '' LIKE '' TYPE '%'", r -> { - assertEquals(2, r.size()); - - Iterator it = IndexType.VALID.stream().sorted(Comparator.comparing(IndexType::toSql)).iterator(); - - for (int t = 0; t < r.size(); t++) { - assertEquals(it.next().toSql(), r.column(3)); - - // everything else should be null - for (int i = 0; i < 10; i++) { - if (i != 3) { - assertNull(r.column(i)); - } - } - - r.advanceRow(); - } - }, new IndexInfo[0]); - } - - public void testSysTablesTypesEnumerationWoString() throws Exception { - executeCommand("SYS TABLES CATALOG LIKE '' LIKE '' ", r -> { - assertEquals(0, r.size()); - }, new IndexInfo[0]); - } private SqlTypedParamValue param(Object value) { return new SqlTypedParamValue(DataTypes.fromJava(value).typeName, value);