SQL: add catalog filter to SYS COLUMNS command (elastic/x-pack-elasticsearch#3978)
Add basic support for catalog parameters in SYS COLUMN Pass an empty string instead of a null inside the prepared statement Don't use pattern for catalog in getColumns Original commit: elastic/x-pack-elasticsearch@17e9e851a0
This commit is contained in:
parent
b2631f9ac8
commit
b8c9c5325c
|
@ -759,9 +759,11 @@ class JdbcDatabaseMetaData implements DatabaseMetaData, JdbcWrapper {
|
|||
@Override
|
||||
public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
|
||||
throws SQLException {
|
||||
PreparedStatement ps = con.prepareStatement("SYS COLUMNS TABLE LIKE ? LIKE ?");
|
||||
ps.setString(1, tableNamePattern != null ? tableNamePattern.trim() : "%");
|
||||
ps.setString(2, columnNamePattern != null ? columnNamePattern.trim() : "%");
|
||||
PreparedStatement ps = con.prepareStatement("SYS COLUMNS CATALOG ? TABLE LIKE ? LIKE ?");
|
||||
// TODO: until passing null works, pass an empty string
|
||||
ps.setString(1, catalog != null ? catalog.trim() : "");
|
||||
ps.setString(2, tableNamePattern != null ? tableNamePattern.trim() : "%");
|
||||
ps.setString(3, columnNamePattern != null ? columnNamePattern.trim() : "%");
|
||||
return ps.executeQuery();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ statement
|
|||
| SYS TABLES (CATALOG LIKE? clusterPattern=pattern)?
|
||||
(LIKE? tablePattern=pattern)?
|
||||
(TYPE STRING (',' STRING)* )? #sysTables
|
||||
| SYS COLUMNS (TABLE LIKE? indexPattern=pattern)?
|
||||
| SYS COLUMNS (CATALOG cluster=STRING)?
|
||||
(TABLE LIKE? indexPattern=pattern)?
|
||||
(LIKE? columnPattern=pattern)? #sysColumns
|
||||
| SYS TYPES #sysTypes
|
||||
| SYS TABLE TYPES #sysTableTypes
|
||||
|
@ -286,7 +287,9 @@ ASC: 'ASC';
|
|||
BETWEEN: 'BETWEEN';
|
||||
BY: 'BY';
|
||||
CAST: 'CAST';
|
||||
CATALOG: 'CATALOG';CATALOGS: 'CATALOGS';COLUMNS: 'COLUMNS';
|
||||
CATALOG: 'CATALOG';
|
||||
CATALOGS: 'CATALOGS';
|
||||
COLUMNS: 'COLUMNS';
|
||||
DEBUG: 'DEBUG';
|
||||
DESC: 'DESC';
|
||||
DESCRIBE: 'DESCRIBE';
|
||||
|
|
|
@ -160,7 +160,7 @@ abstract class CommandBuilder extends LogicalPlanBuilder {
|
|||
|
||||
@Override
|
||||
public Object visitSysColumns(SysColumnsContext ctx) {
|
||||
return new SysColumns(source(ctx), visitPattern(ctx.indexPattern), visitPattern(ctx.columnPattern));
|
||||
return new SysColumns(source(ctx), string(ctx.cluster), visitPattern(ctx.indexPattern), visitPattern(ctx.columnPattern));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -6,6 +6,7 @@
|
|||
package org.elasticsearch.xpack.sql.plan.logical.command.sys;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.xpack.sql.analysis.index.EsIndex;
|
||||
import org.elasticsearch.xpack.sql.expression.Attribute;
|
||||
import org.elasticsearch.xpack.sql.expression.regex.LikePattern;
|
||||
|
@ -37,26 +38,20 @@ import static org.elasticsearch.xpack.sql.type.DataType.SHORT;
|
|||
*/
|
||||
public class SysColumns extends Command {
|
||||
|
||||
private final String catalog;
|
||||
private final LikePattern indexPattern;
|
||||
private final LikePattern columnPattern;
|
||||
|
||||
public SysColumns(Location location, LikePattern indexPattern, LikePattern columnPattern) {
|
||||
public SysColumns(Location location, String catalog, LikePattern indexPattern, LikePattern columnPattern) {
|
||||
super(location);
|
||||
this.catalog = catalog;
|
||||
this.indexPattern = indexPattern;
|
||||
this.columnPattern = columnPattern;
|
||||
}
|
||||
|
||||
public LikePattern indexPattern() {
|
||||
return indexPattern;
|
||||
}
|
||||
|
||||
public LikePattern columnPattern() {
|
||||
return columnPattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<SysColumns> info() {
|
||||
return NodeInfo.create(this, SysColumns::new, indexPattern, columnPattern);
|
||||
return NodeInfo.create(this, SysColumns::new, catalog, indexPattern, columnPattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,12 +86,18 @@ public class SysColumns extends Command {
|
|||
|
||||
@Override
|
||||
public void execute(SqlSession session, ActionListener<SchemaRowSet> listener) {
|
||||
String cluster = session.indexResolver().clusterName();
|
||||
|
||||
// bail-out early if the catalog is present but differs
|
||||
if (Strings.hasText(catalog) && !cluster.equals(catalog)) {
|
||||
listener.onResponse(Rows.empty(output()));
|
||||
return;
|
||||
}
|
||||
|
||||
String index = indexPattern != null ? indexPattern.asIndexNameWildcard() : "*";
|
||||
String regex = indexPattern != null ? indexPattern.asJavaRegex() : null;
|
||||
|
||||
Pattern columnMatcher = columnPattern != null ? Pattern.compile(columnPattern.asJavaRegex()) : null;
|
||||
|
||||
String cluster = session.indexResolver().clusterName();
|
||||
|
||||
session.indexResolver().resolveAsSeparateMappings(index, regex, ActionListener.wrap(esIndices -> {
|
||||
List<List<?>> rows = new ArrayList<>();
|
||||
|
@ -168,7 +169,7 @@ public class SysColumns extends Command {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(indexPattern, columnPattern);
|
||||
return Objects.hash(catalog, indexPattern, columnPattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -182,7 +183,8 @@ public class SysColumns extends Command {
|
|||
}
|
||||
|
||||
SysColumns other = (SysColumns) obj;
|
||||
return Objects.equals(indexPattern, other.indexPattern)
|
||||
return Objects.equals(catalog, other.catalog)
|
||||
&& Objects.equals(indexPattern, other.indexPattern)
|
||||
&& Objects.equals(columnPattern, other.columnPattern);
|
||||
}
|
||||
}
|
|
@ -75,6 +75,24 @@ public class SysParserTests extends ESTestCase {
|
|||
runSysColumns("SYS COLUMNS");
|
||||
}
|
||||
|
||||
public void testSysColumnEmptyCatalog() throws Exception {
|
||||
Tuple<Command, SqlSession> sql = sql("SYS COLUMNS CATALOG '' TABLE LIKE '%' LIKE '%'");
|
||||
|
||||
sql.v1().execute(sql.v2(), ActionListener.wrap(r -> {
|
||||
assertEquals(24, r.columnCount());
|
||||
assertEquals(22, r.size());
|
||||
}, ex -> fail(ex.getMessage())));
|
||||
}
|
||||
|
||||
public void testSysColsTableOnlyCatalog() throws Exception {
|
||||
Tuple<Command, SqlSession> sql = sql("SYS COLUMNS CATALOG 'catalog'");
|
||||
|
||||
sql.v1().execute(sql.v2(), ActionListener.wrap(r -> {
|
||||
assertEquals(24, r.columnCount());
|
||||
assertEquals(0, r.size());
|
||||
}, ex -> fail(ex.getMessage())));
|
||||
}
|
||||
|
||||
public void testSysColsTableOnlyPattern() throws Exception {
|
||||
runSysColumns("SYS COLUMNS TABLE LIKE 'test'");
|
||||
}
|
||||
|
|
|
@ -286,9 +286,9 @@ public class JdbcSecurityIT extends SqlSecurityTestCase {
|
|||
createUser("full_access", "cli_or_jdbc_minimal");
|
||||
|
||||
expectActionMatchesAdmin(
|
||||
con -> con.getMetaData().getColumns("%", "%", "%t", "%"),
|
||||
con -> con.getMetaData().getColumns(null, "%", "%t", "%"),
|
||||
"full_access",
|
||||
con -> con.getMetaData().getColumns("%", "%", "%", "%"));
|
||||
con -> con.getMetaData().getColumns(null, "%", "%", "%"));
|
||||
}
|
||||
|
||||
public void testMetaDataGetColumnsWithNoAccess() throws Exception {
|
||||
|
@ -301,18 +301,18 @@ public class JdbcSecurityIT extends SqlSecurityTestCase {
|
|||
createUser("wrong_access", "read_something_else");
|
||||
|
||||
expectActionMatchesAdmin(
|
||||
con -> con.getMetaData().getColumns("%", "%", "not_created", "%"),
|
||||
con -> con.getMetaData().getColumns(null, "%", "not_created", "%"),
|
||||
"wrong_access",
|
||||
con -> con.getMetaData().getColumns("%", "%", "test", "%"));
|
||||
con -> con.getMetaData().getColumns(null, "%", "test", "%"));
|
||||
}
|
||||
|
||||
public void testMetaDataGetColumnsSingleFieldGranted() throws Exception {
|
||||
createUser("only_a", "read_test_a");
|
||||
|
||||
expectActionMatchesAdmin(
|
||||
con -> con.getMetaData().getColumns("%", "%", "test", "a"),
|
||||
con -> con.getMetaData().getColumns(null, "%", "test", "a"),
|
||||
"only_a",
|
||||
con -> con.getMetaData().getColumns("%", "%", "test", "%"));
|
||||
con -> con.getMetaData().getColumns(null, "%", "test", "%"));
|
||||
}
|
||||
|
||||
public void testMetaDataGetColumnsSingleFieldExcepted() throws Exception {
|
||||
|
@ -322,7 +322,7 @@ public class JdbcSecurityIT extends SqlSecurityTestCase {
|
|||
* both 'a' and 'b' we'll have to roll our own assertion here, but we
|
||||
* are intentionally much less restrictive then the tests elsewhere. */
|
||||
try (Connection con = es(userProperties("not_c"))) {
|
||||
ResultSet result = con.getMetaData().getColumns("%", "%", "test", "%");
|
||||
ResultSet result = con.getMetaData().getColumns(null, "%", "test", "%");
|
||||
assertTrue(result.next());
|
||||
String columnName = result.getString(4);
|
||||
assertEquals("a", columnName);
|
||||
|
@ -337,8 +337,8 @@ public class JdbcSecurityIT extends SqlSecurityTestCase {
|
|||
createUser("no_3s", "read_test_without_c_3");
|
||||
|
||||
expectActionMatchesAdmin(
|
||||
con -> con.getMetaData().getColumns("%", "%", "test", "%"),
|
||||
con -> con.getMetaData().getColumns(null, "%", "test", "%"),
|
||||
"no_3s",
|
||||
con -> con.getMetaData().getColumns("%", "%", "test", "%"));
|
||||
con -> con.getMetaData().getColumns(null, "%", "test", "%"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class DatabaseMetaDataTestCase extends JdbcIntegrationTestCase {
|
|||
h2.createStatement().executeUpdate("RUNSCRIPT FROM 'classpath:/setup_mock_metadata_get_columns.sql'");
|
||||
|
||||
ResultSet expected = h2.createStatement().executeQuery("SELECT '" + clusterName() + "' AS TABLE_CAT, * FROM mock");
|
||||
assertResultSets(expected, es.getMetaData().getColumns("%", "%", "%", null));
|
||||
assertResultSets(expected, es.getMetaData().getColumns(null, "%", "%", null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue