This is an automated email from the ASF dual-hosted git repository. arina pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/drill.git
commit 6fef0820d427aca92df42ca5c578e932d7a0b36b Author: Volodymyr Vysotskyi <vvo...@gmail.com> AuthorDate: Tue Jan 21 20:16:36 2020 +0200 DRILL-7527: DROP METADATA doesn't work with table name starting with '/' inside workspace closes #1958 --- .../apache/drill/common/util/DrillStringUtils.java | 37 +++++++++++----------- .../sql/conversion/DrillCalciteCatalogReader.java | 4 +-- .../planner/sql/handlers/CreateTableHandler.java | 6 ++-- .../planner/sql/handlers/DropTableHandler.java | 4 +-- .../exec/planner/sql/handlers/ViewHandler.java | 6 ++-- .../drill/exec/planner/sql/parser/SqlSchema.java | 4 +-- .../apache/drill/exec/store/dfs/FileSelection.java | 12 ++----- .../exec/store/dfs/WorkspaceSchemaFactory.java | 3 +- .../drill/exec/sql/TestMetastoreCommands.java | 30 ++++++++++++++++++ .../drill/exec/store/dfs/TestFileSelection.java | 5 +-- .../apache/drill/metastore/metadata/TableInfo.java | 4 ++- 11 files changed, 70 insertions(+), 45 deletions(-) diff --git a/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java b/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java index 0fb6f80..de65ff8 100644 --- a/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java +++ b/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java @@ -17,13 +17,13 @@ */ package org.apache.drill.common.util; -import org.apache.drill.shaded.guava.com.google.common.base.Joiner; import io.netty.buffer.ByteBuf; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.Collectors; public class DrillStringUtils { @@ -51,7 +51,7 @@ public class DrillStringUtils { * @param input the {@code String} to unescape, may be null * @return a new unescaped {@code String}, {@code null} if null string input */ - public static final String unescapeJava(String input) { + public static String unescapeJava(String input) { return StringEscapeUtils.unescapeJava(input); } @@ -72,11 +72,11 @@ public class DrillStringUtils { * @param input String to escape values in, may be null * @return String with escaped values, {@code null} if null string input */ - public static final String escapeJava(String input) { + public static String escapeJava(String input) { return StringEscapeUtils.escapeJava(input); } - public static final String escapeNewLines(String input) { + public static String escapeNewLines(String input) { if (input == null) { return null; } @@ -209,21 +209,20 @@ public class DrillStringUtils { * @return The sanitized CSV string */ public static String sanitizeCSV(String csv) { - // tokenize String[] tokens = csv.split(","); - ArrayList<String> sanitizedTokens = new ArrayList<String>(tokens.length); - // check for empties - for (String s : tokens) { - String trimmedToken = s.trim(); - if (trimmedToken.length() != 0) { - sanitizedTokens.add(trimmedToken); - } - } - String result = ""; - if (sanitizedTokens.size() != 0) { - result = Joiner.on(",").join(sanitizedTokens); - } - return result; + return Arrays.stream(tokens) + .map(String::trim) + .filter(StringUtils::isNotEmpty) + .collect(Collectors.joining(",")); } + /** + * Removes all leading slash characters from specified string. + * + * @param path string to remove all leading slash characters + * @return string with removed leading slash characters + */ + public static String removeLeadingSlash(String path) { + return StringUtils.stripStart(path, "/"); + } } diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/conversion/DrillCalciteCatalogReader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/conversion/DrillCalciteCatalogReader.java index 4c8b254..b6fdcc5 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/conversion/DrillCalciteCatalogReader.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/conversion/DrillCalciteCatalogReader.java @@ -35,11 +35,11 @@ import org.apache.calcite.sql.validate.SqlValidatorUtil; import org.apache.calcite.util.Util; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.metastore.MetadataProviderManager; import org.apache.drill.exec.planner.logical.DrillTable; import org.apache.drill.exec.planner.sql.SchemaUtilites; import org.apache.drill.exec.rpc.user.UserSession; -import org.apache.drill.exec.store.dfs.FileSelection; import org.apache.drill.shaded.guava.com.google.common.cache.CacheBuilder; import org.apache.drill.shaded.guava.com.google.common.cache.CacheLoader; import org.apache.drill.shaded.guava.com.google.common.cache.LoadingCache; @@ -101,7 +101,7 @@ class DrillCalciteCatalogReader extends CalciteCatalogReader { List<String> getTemporaryNames(List<String> names) { if (needsTemporaryTableCheck(names, session.getDefaultSchemaPath(), drillConfig)) { - String tableName = FileSelection.removeLeadingSlash(names.get(names.size() - 1)); + String tableName = DrillStringUtils.removeLeadingSlash(names.get(names.size() - 1)); String temporaryTableName = session.resolveTemporaryTableName(tableName); if (temporaryTableName != null) { List<String> temporaryNames = new ArrayList<>(SchemaUtilites.getSchemaPathAsList(temporarySchema)); diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/CreateTableHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/CreateTableHandler.java index 82a111a..082fe27 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/CreateTableHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/CreateTableHandler.java @@ -37,6 +37,7 @@ import org.apache.calcite.tools.RelConversionException; import org.apache.calcite.tools.ValidationException; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.physical.PhysicalPlan; import org.apache.drill.exec.physical.base.PhysicalOperator; @@ -55,7 +56,6 @@ import org.apache.drill.exec.planner.sql.DrillSqlOperator; import org.apache.drill.exec.planner.sql.SchemaUtilites; import org.apache.drill.exec.planner.sql.parser.SqlCreateTable; import org.apache.drill.exec.store.AbstractSchema; -import org.apache.drill.exec.store.dfs.FileSelection; import org.apache.drill.exec.util.Pointer; import org.apache.drill.exec.work.foreman.ForemanSetupException; import org.apache.drill.exec.work.foreman.SqlUnsupportedException; @@ -73,7 +73,7 @@ public class CreateTableHandler extends DefaultSqlHandler { @Override public PhysicalPlan getPlan(SqlNode sqlNode) throws ValidationException, RelConversionException, IOException, ForemanSetupException { final SqlCreateTable sqlCreateTable = unwrap(sqlNode, SqlCreateTable.class); - final String originalTableName = FileSelection.removeLeadingSlash(sqlCreateTable.getName()); + final String originalTableName = DrillStringUtils.removeLeadingSlash(sqlCreateTable.getName()); final ConvertedRelNode convertedRelNode = validateAndConvert(sqlCreateTable.getQuery()); final RelDataType validatedRowType = convertedRelNode.getValidatedRowType(); @@ -329,4 +329,4 @@ public class CreateTableHandler extends DefaultSqlHandler { } return true; } -} \ No newline at end of file +} diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DropTableHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DropTableHandler.java index 665bddd..ab0427a 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DropTableHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DropTableHandler.java @@ -25,13 +25,13 @@ import org.apache.calcite.schema.Table; import org.apache.calcite.sql.SqlNode; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.physical.PhysicalPlan; import org.apache.drill.exec.planner.sql.DirectPlan; import org.apache.drill.exec.planner.sql.SchemaUtilites; import org.apache.drill.exec.planner.sql.parser.SqlDropTable; import org.apache.drill.exec.rpc.user.UserSession; import org.apache.drill.exec.store.AbstractSchema; -import org.apache.drill.exec.store.dfs.FileSelection; // SqlHandler for dropping a table. public class DropTableHandler extends DefaultSqlHandler { @@ -54,7 +54,7 @@ public class DropTableHandler extends DefaultSqlHandler { @Override public PhysicalPlan getPlan(SqlNode sqlNode) { SqlDropTable dropTableNode = ((SqlDropTable) sqlNode); - String originalTableName = FileSelection.removeLeadingSlash(dropTableNode.getName()); + String originalTableName = DrillStringUtils.removeLeadingSlash(dropTableNode.getName()); SchemaPlus defaultSchema = config.getConverter().getDefaultSchema(); List<String> tableSchema = dropTableNode.getSchema(); DrillConfig drillConfig = context.getConfig(); diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/ViewHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/ViewHandler.java index d524d2d..7812d84 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/ViewHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/ViewHandler.java @@ -27,6 +27,7 @@ import org.apache.calcite.tools.RelConversionException; import org.apache.calcite.tools.ValidationException; import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.dotdrill.View; import org.apache.drill.exec.ops.QueryContext; import org.apache.drill.exec.physical.PhysicalPlan; @@ -35,7 +36,6 @@ import org.apache.drill.exec.planner.sql.SchemaUtilites; import org.apache.drill.exec.planner.sql.parser.SqlCreateView; import org.apache.drill.exec.planner.sql.parser.SqlDropView; import org.apache.drill.exec.store.AbstractSchema; -import org.apache.drill.exec.store.dfs.FileSelection; import org.apache.drill.exec.work.foreman.ForemanSetupException; import org.apache.calcite.rel.RelNode; import org.apache.calcite.sql.SqlNode; @@ -61,7 +61,7 @@ public abstract class ViewHandler extends DefaultSqlHandler { public PhysicalPlan getPlan(SqlNode sqlNode) throws ValidationException, RelConversionException, IOException, ForemanSetupException { SqlCreateView createView = unwrap(sqlNode, SqlCreateView.class); - final String newViewName = FileSelection.removeLeadingSlash(createView.getName()); + final String newViewName = DrillStringUtils.removeLeadingSlash(createView.getName()); // Disallow temporary tables usage in view definition config.getConverter().disallowTemporaryTables(); @@ -157,7 +157,7 @@ public abstract class ViewHandler extends DefaultSqlHandler { @Override public PhysicalPlan getPlan(SqlNode sqlNode) throws IOException, ForemanSetupException { SqlDropView dropView = unwrap(sqlNode, SqlDropView.class); - final String viewName = FileSelection.removeLeadingSlash(dropView.getName()); + final String viewName = DrillStringUtils.removeLeadingSlash(dropView.getName()); final AbstractSchema drillSchema = SchemaUtilites.resolveToMutableDrillSchema(context.getNewDefaultSchema(), dropView.getSchemaPath()); diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/SqlSchema.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/SqlSchema.java index 44a3adb..97f52a3 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/SqlSchema.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/parser/SqlSchema.java @@ -29,11 +29,11 @@ import org.apache.calcite.sql.SqlSpecialOperator; import org.apache.calcite.sql.SqlWriter; import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.util.SqlBasicVisitor; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.planner.sql.handlers.AbstractSqlHandler; import org.apache.drill.exec.planner.sql.handlers.SqlHandlerConfig; import org.apache.drill.exec.planner.sql.handlers.SchemaHandler; import org.apache.drill.exec.planner.sql.handlers.SqlHandlerUtil; -import org.apache.drill.exec.store.dfs.FileSelection; import java.util.Arrays; import java.util.Collections; @@ -88,7 +88,7 @@ public abstract class SqlSchema extends DrillSqlCall { public String getTableName() { if (hasTable()) { String tableName = table.isSimple() ? table.getSimple() : table.names.get(table.names.size() - 1); - return FileSelection.removeLeadingSlash(tableName); + return DrillStringUtils.removeLeadingSlash(tableName); } return null; } diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/FileSelection.java b/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/FileSelection.java index a1fccb7..6700114 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/FileSelection.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/FileSelection.java @@ -18,6 +18,7 @@ package org.apache.drill.exec.store.dfs; import org.apache.drill.common.exceptions.DrillRuntimeException; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.util.DrillFileSystemUtil; import org.apache.drill.shaded.guava.com.google.common.base.Preconditions; import org.apache.drill.shaded.guava.com.google.common.base.Stopwatch; @@ -269,7 +270,7 @@ public class FileSelection { Stopwatch timer = logger.isDebugEnabled() ? Stopwatch.createStarted() : null; boolean hasWildcard = path.contains(WILD_CARD); - Path combined = new Path(parent, removeLeadingSlash(path)); + Path combined = new Path(parent, DrillStringUtils.removeLeadingSlash(path)); if (!allowAccessOutsideWorkspace) { checkBackPaths(new Path(parent).toUri().getPath(), combined.toUri().getPath(), path); } @@ -365,15 +366,6 @@ public class FileSelection { } } - public static String removeLeadingSlash(String path) { - if (!path.isEmpty() && path.charAt(0) == '/') { - String newPath = path.substring(1); - return removeLeadingSlash(newPath); - } else { - return path; - } - } - /** * Check if the path is a valid sub path under the parent after removing backpaths. Throw an exception if * it is not. We pass subpath in as a parameter only for the error message diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/WorkspaceSchemaFactory.java b/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/WorkspaceSchemaFactory.java index 87b5592..7d9d9dd 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/WorkspaceSchemaFactory.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/store/dfs/WorkspaceSchemaFactory.java @@ -46,6 +46,7 @@ import org.apache.drill.common.exceptions.ExecutionSetupException; import org.apache.drill.common.exceptions.UserException; import org.apache.drill.common.logical.FormatPluginConfig; import org.apache.drill.common.scanner.persistence.ScanResult; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.ExecConstants; import org.apache.drill.exec.dotdrill.DotDrillFile; import org.apache.drill.exec.dotdrill.DotDrillType; @@ -410,7 +411,7 @@ public class WorkspaceSchemaFactory { try { try { files = DotDrillUtil.getDotDrills(getFS(), new Path(config.getLocation()), - FileSelection.removeLeadingSlash(tableName), DotDrillType.VIEW); + DrillStringUtils.removeLeadingSlash(tableName), DotDrillType.VIEW); } catch (AccessControlException e) { if (!schemaConfig.getIgnoreAuthErrors()) { logger.debug(e.getMessage()); diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestMetastoreCommands.java b/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestMetastoreCommands.java index ccee4ed..b31002e 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestMetastoreCommands.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/sql/TestMetastoreCommands.java @@ -3131,6 +3131,36 @@ public class TestMetastoreCommands extends ClusterTest { } } + @Test + public void testAnalyzeWithLeadingSlash() throws Exception { + String tableName = "tableWithLeadingSlash"; + TableInfo tableInfo = getTableInfo("/" + tableName, "tmp"); + try { + run("create table dfs.tmp.`%s` as\n" + + "select * from cp.`tpch/region.parquet`", tableName); + + testBuilder() + .sqlQuery("analyze table dfs.tmp.`%s` REFRESH METADATA", tableName) + .unOrdered() + .baselineColumns("ok", "summary") + .baselineValues(true, String.format("Collected / refreshed metadata for table [dfs.tmp.%s]", tableName)) + .go(); + + MetastoreTableInfo metastoreTableInfo = cluster.drillbit().getContext() + .getMetastoreRegistry() + .get() + .tables() + .basicRequests() + .metastoreTableInfo(tableInfo); + + assertTrue("table metadata wasn't found", metastoreTableInfo.isExists()); + } finally { + run("analyze table dfs.tmp.`%s` drop metadata", tableName); + run("drop table if exists dfs.tmp.`%s`", tableName); + client.resetSession(ExecConstants.METASTORE_ENABLED); + } + } + private static <T> ColumnStatistics<T> getColumnStatistics(T minValue, T maxValue, long rowCount, TypeProtos.MinorType minorType) { return new ColumnStatistics<>( diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/store/dfs/TestFileSelection.java b/exec/java-exec/src/test/java/org/apache/drill/exec/store/dfs/TestFileSelection.java index b853b9b..9ab4aea 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/store/dfs/TestFileSelection.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/store/dfs/TestFileSelection.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNull; import java.util.List; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.exec.util.DrillFileSystemUtil; import org.apache.drill.shaded.guava.com.google.common.collect.ImmutableList; import org.apache.drill.test.BaseTestQuery; @@ -62,7 +63,7 @@ public class TestFileSelection extends BaseTestQuery { boolean isPathGood = true; try { String parent = badPaths[i][0]; - String subPath = FileSelection.removeLeadingSlash(badPaths[i][1]); + String subPath = DrillStringUtils.removeLeadingSlash(badPaths[i][1]); String path = new Path(parent, subPath).toString(); FileSelection.checkBackPaths(parent, path, subPath); } catch (IllegalArgumentException e) { @@ -88,7 +89,7 @@ public class TestFileSelection extends BaseTestQuery { for (int i = 0; i < goodPaths.length; i++) { try { String parent = goodPaths[i][0]; - String subPath = FileSelection.removeLeadingSlash(goodPaths[i][1]); + String subPath = DrillStringUtils.removeLeadingSlash(goodPaths[i][1]); String path = new Path(parent, subPath).toString(); FileSelection.checkBackPaths(parent, path, subPath); } catch (IllegalArgumentException e) { diff --git a/metastore/metastore-api/src/main/java/org/apache/drill/metastore/metadata/TableInfo.java b/metastore/metastore-api/src/main/java/org/apache/drill/metastore/metadata/TableInfo.java index 538c4a2..f9fb3f4 100644 --- a/metastore/metastore-api/src/main/java/org/apache/drill/metastore/metadata/TableInfo.java +++ b/metastore/metastore-api/src/main/java/org/apache/drill/metastore/metadata/TableInfo.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import org.apache.drill.common.util.DrillStringUtils; import org.apache.drill.metastore.components.tables.TableMetadataUnit; import org.apache.drill.metastore.expressions.FilterExpression; @@ -156,7 +157,8 @@ public class TableInfo { } public TableInfoBuilder name(String name) { - this.name = name; + // removes leading slash characters since such table names are equivalent + this.name = DrillStringUtils.removeLeadingSlash(name); return this; }