This is an automated email from the ASF dual-hosted git repository.

stigahuang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git


The following commit(s) were added to refs/heads/master by this push:
     new f22b805c8 IMPALA-13936: REFRESH should wait for ALTER ownership events
f22b805c8 is described below

commit f22b805c889d34568008ee0bbea47d04b4ba09b8
Author: stiga-huang <[email protected]>
AuthorDate: Mon Apr 7 17:55:02 2025 +0800

    IMPALA-13936: REFRESH should wait for ALTER ownership events
    
    Coordinator uses collectTableRefs() to collect table names used by a
    statement. For ResetMetadataStmt used by REFRESH and INVALIDATE METADATA
    commands, it's intended to not return the table name in
    collectTableRefs() to avoid triggering unneccessary table metadata
    loading. However, when this method is used for the HMS event sync
    feature, we do want to know what the table is. Thus, catalogd can return
    the latest metadata of it after waiting for HMS events are synced. This
    bug leads to REFRESH/INVALIDATE not waiting for HMS ALTER ownership
    events to be synced. REFRESH/INVALIDATE statements might unexpectedly
    fail or succeed due to stale ownership info in coordinators.
    
    To avoid changing the existing logic of collectTableRefs(), this patch
    uses getTableName() directly for REFRESH statements since we know it's a
    single-table statement. There are other kinds of such single-table
    statements like DROP TABLE. To be generic, introduces a new interface,
    SingleTableStmt, for all such statements that have a single table name.
    If a statement is a SingleTableStmt, we use getTableName() directly
    instead of collectTableRefs() in collectRequiredObjects().
    
    This improves coordinator in collecting table names for single-table
    statements. E.g. "DROP TABLE mydb.foo" previously has two candidate
    table names - "mydb.foo" and "default.mydb" (assuming the session db is
    "default"). Now it just collects "mydb.foo". Catalogd can return less
    metadata in the response.
    
    Tests:
     - Added FE tests for collectRequiredObjects() where coordinators
       collect db/table names.
     - Added authorization tests on altering the ownership in Hive and
       running queries in Impala.
    
    Change-Id: I813007e9ec42392d0f6d3996331987c138cc4fb8
    Reviewed-on: http://gerrit.cloudera.org:8080/22743
    Reviewed-by: Impala Public Jenkins <[email protected]>
    Tested-by: Impala Public Jenkins <[email protected]>
---
 .../org/apache/impala/analysis/AlterTableStmt.java |   4 +-
 .../apache/impala/analysis/CommentOnDbStmt.java    |   3 +
 .../impala/analysis/CommentOnTableOrViewStmt.java  |   6 +-
 .../apache/impala/analysis/ComputeStatsStmt.java   |   3 +-
 .../impala/analysis/ConvertTableToIcebergStmt.java |   5 +-
 .../impala/analysis/CreateTableAsSelectStmt.java   |   2 +-
 .../apache/impala/analysis/CreateTableStmt.java    |  15 +-
 .../impala/analysis/DescribeHistoryStmt.java       |   5 +-
 .../org/apache/impala/analysis/DropStatsStmt.java  |   5 +-
 .../impala/analysis/DropTableOrViewStmt.java       |   4 +-
 .../org/apache/impala/analysis/LoadDataStmt.java   |   5 +-
 .../apache/impala/analysis/ResetMetadataStmt.java  |   5 +-
 .../impala/analysis/ShowCreateTableStmt.java       |   5 +-
 .../org/apache/impala/analysis/ShowFilesStmt.java  |   5 +-
 .../org/apache/impala/analysis/ShowStatsStmt.java  |   5 +-
 .../{CommentOnDbStmt.java => SingleTableStmt.java} |  35 ++--
 .../org/apache/impala/analysis/TruncateStmt.java   |   5 +-
 .../java/org/apache/impala/service/Frontend.java   |  42 +++--
 .../org/apache/impala/service/FrontendTest.java    | 178 +++++++++++++++++++++
 .../org/apache/impala/service/JdbcTestBase.java    |   3 +-
 tests/authorization/test_ranger.py                 |  83 ++++++++++
 tests/common/impala_test_suite.py                  |  14 +-
 22 files changed, 372 insertions(+), 65 deletions(-)

diff --git a/fe/src/main/java/org/apache/impala/analysis/AlterTableStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/AlterTableStmt.java
index c5aa16a4a..a377e83f8 100644
--- a/fe/src/main/java/org/apache/impala/analysis/AlterTableStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/AlterTableStmt.java
@@ -31,7 +31,7 @@ import com.google.common.base.Preconditions;
 /**
  * Base class for all ALTER TABLE statements.
  */
-public abstract class AlterTableStmt extends StatementBase {
+public abstract class AlterTableStmt extends StatementBase implements 
SingleTableStmt {
   protected TableName tableName_;
 
   // Set during analysis.
@@ -48,6 +48,8 @@ public abstract class AlterTableStmt extends StatementBase {
    */
   public abstract String getOperation();
 
+  @Override
+  public TableName getTableName() { return tableName_; }
   public String getTbl() { return tableName_.getTbl(); }
 
   /**
diff --git a/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java
index a216fd3d8..9ef5928e6 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java
@@ -34,6 +34,9 @@ public class CommentOnDbStmt extends CommentOnStmt {
     dbName_ = dbName;
   }
 
+  @Override
+  public String getParsedDb() { return dbName_; }
+
   @Override
   public void analyze(Analyzer analyzer) throws AnalysisException {
     super.analyze(analyzer);
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/CommentOnTableOrViewStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/CommentOnTableOrViewStmt.java
index 36325a669..06f847232 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CommentOnTableOrViewStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CommentOnTableOrViewStmt.java
@@ -27,7 +27,8 @@ import java.util.List;
 /**
  * A base class for COMMENT ON TABLE/VIEW.
  */
-public abstract class CommentOnTableOrViewStmt extends CommentOnStmt {
+public abstract class CommentOnTableOrViewStmt extends CommentOnStmt
+    implements SingleTableStmt {
   protected TableName tableName_;
 
   public CommentOnTableOrViewStmt(TableName tableName, String comment) {
@@ -36,6 +37,9 @@ public abstract class CommentOnTableOrViewStmt extends 
CommentOnStmt {
     tableName_ = tableName;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_;}
+
   @Override
   public void collectTableRefs(List<TableRef> tblRefs) {
     tblRefs.add(new TableRef(tableName_.toPath(), null));
diff --git a/fe/src/main/java/org/apache/impala/analysis/ComputeStatsStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ComputeStatsStmt.java
index 14889899e..762b5607b 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ComputeStatsStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ComputeStatsStmt.java
@@ -112,7 +112,7 @@ import com.google.common.collect.Sets;
  * TODO: Allow more coarse (db)
  * TODO: Compute stats on complex types.
  */
-public class ComputeStatsStmt extends StatementBase {
+public class ComputeStatsStmt extends StatementBase implements SingleTableStmt 
{
   private static final Logger LOG = Logger.getLogger(ComputeStatsStmt.class);
 
   private static String AVRO_SCHEMA_MSG_PREFIX = "Cannot COMPUTE STATS on Avro 
table " +
@@ -1028,6 +1028,7 @@ public class ComputeStatsStmt extends StatementBase {
     return partitionSet_;
   }
 
+  @Override
   public TableName getTableName() {
     return tableName_;
   }
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/ConvertTableToIcebergStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ConvertTableToIcebergStmt.java
index 557c77dc1..7f91f1248 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ConvertTableToIcebergStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ConvertTableToIcebergStmt.java
@@ -50,7 +50,7 @@ import org.apache.impala.util.MigrateTableUtil;
  * ALTER TABLE <table name> CONVERT TO ICEBERG
  * [TBLPROPERTIES (prop1=val1, prop2=val2 ...)]
  */
-public class ConvertTableToIcebergStmt extends StatementBase {
+public class ConvertTableToIcebergStmt extends StatementBase implements 
SingleTableStmt {
 
   private TableName tableName_;
   private TableName tmpHdfsTableName_;
@@ -73,6 +73,9 @@ public class ConvertTableToIcebergStmt extends StatementBase {
     this(tableName, Maps.newHashMap());
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public void collectTableRefs(List<TableRef> tblRefs) {
     tblRefs.add(new TableRef(tableName_.toPath(), null));
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/CreateTableAsSelectStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/CreateTableAsSelectStmt.java
index 87a62f1cf..78e7e37d6 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CreateTableAsSelectStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CreateTableAsSelectStmt.java
@@ -105,7 +105,7 @@ public class CreateTableAsSelectStmt extends StatementBase {
         pkvs.add(new PartitionKeyValue(key, null));
       }
     }
-    insertStmt_ = InsertStmt.createInsert(null, createStmt_.getTblName(), 
false, pkvs,
+    insertStmt_ = InsertStmt.createInsert(null, createStmt_.getTableName(), 
false, pkvs,
         planHints, null, params.queryStmt, null);
   }
 
diff --git a/fe/src/main/java/org/apache/impala/analysis/CreateTableStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/CreateTableStmt.java
index 8899bbd8f..1e9d0f6ef 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CreateTableStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CreateTableStmt.java
@@ -63,7 +63,7 @@ import com.google.common.primitives.Ints;
 /**
  * Represents a CREATE TABLE statement.
  */
-public class CreateTableStmt extends StatementBase {
+public class CreateTableStmt extends StatementBase implements SingleTableStmt {
 
   @VisibleForTesting
   final static String KUDU_STORAGE_HANDLER_ERROR_MESSAGE = "Kudu tables must 
be"
@@ -106,8 +106,9 @@ public class CreateTableStmt extends StatementBase {
   @Override
   public CreateTableStmt clone() { return new CreateTableStmt(this); }
 
-  public String getTbl() { return getTblName().getTbl(); }
-  public TableName getTblName() { return tableDef_.getTblName(); }
+  public String getTbl() { return getTableName().getTbl(); }
+  @Override
+  public TableName getTableName() { return tableDef_.getTblName(); }
   public boolean getIfNotExists() { return tableDef_.getIfNotExists(); }
   public List<ColumnDef> getColumnDefs() { return tableDef_.getColumnDefs(); }
   private void setColumnDefs(List<ColumnDef> colDefs) {
@@ -191,7 +192,7 @@ public class CreateTableStmt extends StatementBase {
    */
   public String getDb() {
     Preconditions.checkState(isAnalyzed());
-    return getTblName().getDb();
+    return getTableName().getDb();
   }
 
   @Override
@@ -580,17 +581,17 @@ public class CreateTableStmt extends StatementBase {
         // No Avro schema was explicitly set in the serde or table properties, 
so infer
         // the Avro schema from the column definitions.
         Schema inferredSchema = AvroSchemaConverter.convertColumnDefs(
-            getColumnDefs(), getTblName().toString());
+            getColumnDefs(), getTableName().toString());
         avroSchema = inferredSchema.toString();
       }
       if (Strings.isNullOrEmpty(avroSchema)) {
         throw new AnalysisException("Avro schema is null or empty: " +
-            getTblName().toString());
+            getTableName().toString());
       }
       avroCols = AvroSchemaParser.parse(avroSchema);
     } catch (SchemaParseException e) {
       throw new AnalysisException(String.format(
-          "Error parsing Avro schema for table '%s': %s", 
getTblName().toString(),
+          "Error parsing Avro schema for table '%s': %s", 
getTableName().toString(),
           e.getMessage()));
     }
     Preconditions.checkNotNull(avroCols);
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/DescribeHistoryStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/DescribeHistoryStmt.java
index 1ada79887..2b906e0a8 100644
--- a/fe/src/main/java/org/apache/impala/analysis/DescribeHistoryStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/DescribeHistoryStmt.java
@@ -40,7 +40,7 @@ import com.google.common.base.Preconditions;
  *         DESCRIBE HISTORY <table> FROM <ts>;
  *         DESCRIBE HISTORY <table> FROM now() - interval 1 days;
  */
-public class DescribeHistoryStmt extends StatementBase {
+public class DescribeHistoryStmt extends StatementBase implements 
SingleTableStmt {
   private final static Logger LOG = 
LoggerFactory.getLogger(TimeTravelSpec.class);
 
   // Represents the predicate with which this statement was called.
@@ -94,6 +94,9 @@ public class DescribeHistoryStmt extends StatementBase {
     kind_ = Kind.BETWEEN;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public void collectTableRefs(List<TableRef> tblRefs) {
     tblRefs.add(new TableRef(tableName_.toPath(), null));
diff --git a/fe/src/main/java/org/apache/impala/analysis/DropStatsStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/DropStatsStmt.java
index de91981c6..5eafa631a 100644
--- a/fe/src/main/java/org/apache/impala/analysis/DropStatsStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/DropStatsStmt.java
@@ -30,7 +30,7 @@ import com.google.common.base.Preconditions;
  * Represents both a DROP STATS statement, and the DROP INCREMENTAL STATS 
<tbl> PARTITION
  * <part_spec> variant.
  */
-public class DropStatsStmt extends StatementBase {
+public class DropStatsStmt extends StatementBase implements SingleTableStmt {
   protected final TableName tableName_;
 
   // Set during analysis
@@ -52,6 +52,9 @@ public class DropStatsStmt extends StatementBase {
     this.partitionSet_ = partitionSet;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public String toSql(ToSqlOptions options) {
     StringBuilder sb = new StringBuilder("DROP ");
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/DropTableOrViewStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/DropTableOrViewStmt.java
index 594b7e376..8aa12421c 100644
--- a/fe/src/main/java/org/apache/impala/analysis/DropTableOrViewStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/DropTableOrViewStmt.java
@@ -37,7 +37,7 @@ import com.google.common.base.Preconditions;
 /**
  * Represents a DROP TABLE/VIEW [IF EXISTS] statement
  */
-public class DropTableOrViewStmt extends StatementBase {
+public class DropTableOrViewStmt extends StatementBase implements 
SingleTableStmt {
   private static final Logger LOG = 
LoggerFactory.getLogger(DropTableOrViewStmt.class);
 
   protected final TableName tableName_;
@@ -164,6 +164,8 @@ public class DropTableOrViewStmt extends StatementBase {
     return dbName_;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
   public String getTbl() { return tableName_.getTbl(); }
   public boolean isDropTable() { return dropTable_; }
 }
diff --git a/fe/src/main/java/org/apache/impala/analysis/LoadDataStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/LoadDataStmt.java
index a6dcc6946..c64a6f7fa 100644
--- a/fe/src/main/java/org/apache/impala/analysis/LoadDataStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/LoadDataStmt.java
@@ -62,7 +62,7 @@ import org.apache.parquet.hadoop.ParquetFileWriter;
  *  2. INSERT INTO from the temporary table to the target table
  *  3. DROP temporary table
  */
-public class LoadDataStmt extends StatementBase {
+public class LoadDataStmt extends StatementBase implements SingleTableStmt {
   private final TableName tableName_;
   private final HdfsUri sourceDataPath_;
   private final PartitionSpec partitionSpec_;
@@ -85,6 +85,9 @@ public class LoadDataStmt extends StatementBase {
     this.partitionSpec_ = partitionSpec;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   public String getTbl() {
     return tableName_.getTbl();
   }
diff --git a/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
index 07723289b..d980ccba7 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ResetMetadataStmt.java
@@ -45,7 +45,7 @@ import com.google.common.base.Preconditions;
  * REFRESH FUNCTIONS <database>
  * REFRESH AUTHORIZATION
  */
-public class ResetMetadataStmt extends StatementBase {
+public class ResetMetadataStmt extends StatementBase implements 
SingleTableStmt {
 
   public enum Action {
     INVALIDATE_METADATA_ALL(false),
@@ -127,6 +127,9 @@ public class ResetMetadataStmt extends StatementBase {
         /*table*/ null, /*partition*/ null);
   }
 
+  @Override
+  public String getParsedDb() { return database_; }
+  @Override
   public TableName getTableName() { return tableName_; }
 
   public PartitionSpec getPartitionSpec() { return partitionSpec_; }
diff --git 
a/fe/src/main/java/org/apache/impala/analysis/ShowCreateTableStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ShowCreateTableStmt.java
index 32ebceffa..8cc102140 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ShowCreateTableStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ShowCreateTableStmt.java
@@ -35,7 +35,7 @@ import com.google.common.base.Preconditions;
  *
  * Syntax: SHOW CREATE (TABLE|VIEW) <table or view>
  */
-public class ShowCreateTableStmt extends StatementBase {
+public class ShowCreateTableStmt extends StatementBase implements 
SingleTableStmt {
   private TableName tableName_;
 
   // The object type keyword used, e.g. TABLE or VIEW, needed to output 
matching SQL.
@@ -47,6 +47,9 @@ public class ShowCreateTableStmt extends StatementBase {
     this.objectType_ = objectType;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public String toSql(ToSqlOptions options) {
     return "SHOW CREATE " + objectType_.name() + " " + tableName_;
diff --git a/fe/src/main/java/org/apache/impala/analysis/ShowFilesStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ShowFilesStmt.java
index 0db0357f7..ab90a5387 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ShowFilesStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ShowFilesStmt.java
@@ -35,7 +35,7 @@ import com.google.common.base.Preconditions;
  * SHOW FILES IN [dbName.]tableName [PARTITION(key=value,...)]
  *
  */
-public class ShowFilesStmt extends StatementBase {
+public class ShowFilesStmt extends StatementBase implements SingleTableStmt {
   private final TableName tableName_;
 
   // Show files for all the partitions if this is null.
@@ -57,6 +57,9 @@ public class ShowFilesStmt extends StatementBase {
     return strBuilder.toString();
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public void collectTableRefs(List<TableRef> tblRefs) {
     tblRefs.add(new TableRef(tableName_.toPath(), null));
diff --git a/fe/src/main/java/org/apache/impala/analysis/ShowStatsStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/ShowStatsStmt.java
index 7946f43f9..3a0427959 100644
--- a/fe/src/main/java/org/apache/impala/analysis/ShowStatsStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/ShowStatsStmt.java
@@ -35,7 +35,7 @@ import com.google.common.base.Preconditions;
  * Representation of a SHOW TABLE/COLUMN STATS statement for
  * displaying column and table/partition statistics for a given table.
  */
-public class ShowStatsStmt extends StatementBase {
+public class ShowStatsStmt extends StatementBase implements SingleTableStmt {
   protected final TShowStatsOp op_;
   protected final TableName tableName_;
   protected boolean show_column_minmax_stats_ = false;
@@ -48,6 +48,9 @@ public class ShowStatsStmt extends StatementBase {
     tableName_ = Preconditions.checkNotNull(tableName);
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public String toSql(ToSqlOptions options) {
     return getSqlPrefix() + " " + tableName_.toString();
diff --git a/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/SingleTableStmt.java
similarity index 51%
copy from fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java
copy to fe/src/main/java/org/apache/impala/analysis/SingleTableStmt.java
index a216fd3d8..cc94b1737 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CommentOnDbStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/SingleTableStmt.java
@@ -17,33 +17,16 @@
 
 package org.apache.impala.analysis;
 
-import com.google.common.base.Preconditions;
-import org.apache.impala.authorization.Privilege;
-import org.apache.impala.common.AnalysisException;
-import org.apache.impala.thrift.TCommentOnParams;
+import javax.annotation.Nullable;
 
 /**
- * Represents a COMMENT ON DATABASE db IS 'comment' statement.
+ * Statements that targets on a single table. E.g. DROP TABLE <table>.
  */
-public class CommentOnDbStmt extends CommentOnStmt {
-  private final String dbName_;
-
-  public CommentOnDbStmt(String dbName, String comment) {
-    super(comment);
-    Preconditions.checkNotNull(dbName);
-    dbName_ = dbName;
-  }
-
-  @Override
-  public void analyze(Analyzer analyzer) throws AnalysisException {
-    super.analyze(analyzer);
-    analyzer.getDb(dbName_, Privilege.ALTER);
-  }
-
-  @Override
-  public TCommentOnParams toThrift() {
-    TCommentOnParams params = super.toThrift();
-    params.setDb(dbName_);
-    return params;
-  }
+public interface SingleTableStmt {
+  /**
+   * Returns the TableName of the statement. It might be null, e.g. when 
ResetMetadataStmt
+   * is a global INVALIDATE METADATA. It's extracted before analyzing the 
statement so
+   * might not be fully-qualified.
+   */
+  @Nullable TableName getTableName();
 }
diff --git a/fe/src/main/java/org/apache/impala/analysis/TruncateStmt.java 
b/fe/src/main/java/org/apache/impala/analysis/TruncateStmt.java
index 52e7bb9b4..30aa77489 100644
--- a/fe/src/main/java/org/apache/impala/analysis/TruncateStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/TruncateStmt.java
@@ -34,7 +34,7 @@ import com.google.common.base.Preconditions;
  * TRUNCATE [TABLE] [IF EXISTS] [database.]table
  *
  */
-public class TruncateStmt extends StatementBase {
+public class TruncateStmt extends StatementBase implements SingleTableStmt {
   private TableName tableName_;
   private final boolean ifExists_;
 
@@ -48,6 +48,9 @@ public class TruncateStmt extends StatementBase {
     ifExists_ = ifExists;
   }
 
+  @Override
+  public TableName getTableName() { return tableName_; }
+
   @Override
   public void collectTableRefs(List<TableRef> tblRefs) {
     tblRefs.add(new TableRef(tableName_.toPath(), null));
diff --git a/fe/src/main/java/org/apache/impala/service/Frontend.java 
b/fe/src/main/java/org/apache/impala/service/Frontend.java
index ce8ee8162..c61cc272c 100644
--- a/fe/src/main/java/org/apache/impala/service/Frontend.java
+++ b/fe/src/main/java/org/apache/impala/service/Frontend.java
@@ -99,6 +99,7 @@ import org.apache.impala.analysis.ShowFunctionsStmt;
 import org.apache.impala.analysis.ShowGrantPrincipalStmt;
 import org.apache.impala.analysis.ShowRolesStmt;
 import org.apache.impala.analysis.ShowTablesOrViewsStmt;
+import org.apache.impala.analysis.SingleTableStmt;
 import org.apache.impala.analysis.StatementBase;
 import org.apache.impala.analysis.StmtMetadataLoader;
 import org.apache.impala.analysis.StmtMetadataLoader.StmtTableCache;
@@ -2228,8 +2229,8 @@ public class Frontend {
    * Collect required catalog objects for query planning of the statement and 
update
    * the request.
    */
-  private void collectRequiredObjects(TWaitForHmsEventRequest req, 
StatementBase stmt,
-      String sessionDb) {
+  public static void collectRequiredObjects(TWaitForHmsEventRequest req,
+      StatementBase stmt, String sessionDb) {
     if (stmt instanceof ShowDbsStmt) {
       req.want_db_list = true;
       return;
@@ -2254,29 +2255,42 @@ public class Frontend {
       } else {
         LOG.info("Waiting for HMS events on database " + dbName);
       }
-      // 'dbName' is not null only for CREATE/DROP/ALTER database or SHOW 
TABLES/VIEWS
-      // statements. No more tables are needed.
+      // 'dbName' is not null only for CREATE/DROP/ALTER database or SHOW 
TABLES / VIEWS /
+      // FUNCTIONS statements. No more tables are needed.
       return;
     }
-    List<TableRef> tblRefs = new ArrayList<>();
-    stmt.collectTableRefs(tblRefs);
-    Set<TableName> tableNames = new HashSet<>();
-    for (TableRef ref : tblRefs) {
-      tableNames.addAll(org.apache.impala.analysis.Path.getCandidateTables(
-          ref.getPath(), sessionDb));
+    Collection<TableName> tableNames;
+    // Handle SingleTableStmt such as CREATE/DROP/ALTER TABLE separately to 
collect a
+    // single table name. Note that collectTableRefs() might return several 
candidate
+    // names or nothing (for REFRESH/INVALIDATE METADATA <table>). So we only 
use it for
+    // multi-table statements.
+    if (stmt instanceof SingleTableStmt) {
+      TableName tblName = ((SingleTableStmt) stmt).getTableName();
+      // Statements like global INVALIDATE METADATA don't have the table name.
+      if (tblName == null) return;
+      if (!tblName.isFullyQualified()) {
+        tblName = new TableName(sessionDb, tblName.getTbl());
+      }
+      tableNames = Collections.singletonList(tblName);
+    } else {
+      List<TableRef> tblRefs = new ArrayList<>();
+      stmt.collectTableRefs(tblRefs);
+      tableNames = new HashSet<>();
+      for (TableRef ref : tblRefs) {
+        tableNames.addAll(org.apache.impala.analysis.Path.getCandidateTables(
+            ref.getPath(), sessionDb));
+      }
     }
     Set<String> dbNames = new HashSet<>();
     for (TableName tblName : tableNames) {
       dbNames.add(tblName.getDb());
-      TCatalogObject tblDesc = new TCatalogObject();
-      tblDesc.setType(TCatalogObjectType.TABLE);
+      TCatalogObject tblDesc = new TCatalogObject(TCatalogObjectType.TABLE, 0);
       tblDesc.setTable(new TTable(tblName.getDb(), tblName.getTbl()));
       req.addToObject_descs(tblDesc);
     }
     // Add dbs needed by the tables.
     for (String name : dbNames) {
-      TCatalogObject dbDesc = new TCatalogObject();
-      dbDesc.setType(TCatalogObjectType.DATABASE);
+      TCatalogObject dbDesc = new TCatalogObject(TCatalogObjectType.DATABASE, 
0);
       dbDesc.setDb(new TDatabase(name));
       req.addToObject_descs(dbDesc);
     }
diff --git a/fe/src/test/java/org/apache/impala/service/FrontendTest.java 
b/fe/src/test/java/org/apache/impala/service/FrontendTest.java
index 9bfcce0b2..ee53947eb 100644
--- a/fe/src/test/java/org/apache/impala/service/FrontendTest.java
+++ b/fe/src/test/java/org/apache/impala/service/FrontendTest.java
@@ -19,10 +19,12 @@ package org.apache.impala.service;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -32,17 +34,23 @@ import org.apache.hive.service.rpc.thrift.TGetFunctionsReq;
 import org.apache.hive.service.rpc.thrift.TGetInfoReq;
 import org.apache.hive.service.rpc.thrift.TGetSchemasReq;
 import org.apache.hive.service.rpc.thrift.TGetTablesReq;
+import org.apache.impala.analysis.Parser;
+import org.apache.impala.analysis.StatementBase;
 import org.apache.impala.catalog.Db;
 import org.apache.impala.catalog.ScalarType;
 import org.apache.impala.catalog.Table;
 import org.apache.impala.catalog.Type;
+import org.apache.impala.common.AnalysisException;
 import org.apache.impala.common.FrontendTestBase;
 import org.apache.impala.common.ImpalaException;
 import org.apache.impala.testutil.TestUtils;
+import org.apache.impala.thrift.TCatalogObject;
+import org.apache.impala.thrift.TCatalogObjectType;
 import org.apache.impala.thrift.TMetadataOpRequest;
 import org.apache.impala.thrift.TMetadataOpcode;
 import org.apache.impala.thrift.TResultRow;
 import org.apache.impala.thrift.TResultSet;
+import org.apache.impala.thrift.TWaitForHmsEventRequest;
 import org.junit.Assume;
 import org.junit.Test;
 
@@ -388,4 +396,174 @@ public class FrontendTest extends FrontendTestBase {
       throws ImpalaException {
     return frontend_.execHiveServer2MetadataOp(req);
   }
+
+  @Test
+  public void TestCollectRequiredObjectsForHmsEventSync() throws 
AnalysisException {
+    String db = "session_db";
+
+    TestCollectRequiredObjectsHelper("SELECT * FROM db1.tbl1, tbl2, db3.tbl3, 
tbl4",
+        db, Arrays.asList("db1", "db3", db), Arrays.asList("db1.tbl1", db + 
".db1",
+            db + ".tbl2", "db3.tbl3", db + ".db3", db + ".tbl4"));
+    TestCollectRequiredObjectsHelper(
+        "SELECT * FROM tbl1 t where exists (SELECT 1 FROM db1.tbl2 t2 where 
t2.id=t.id)",
+        db, Arrays.asList("db1", db),
+        Arrays.asList(db + ".tbl1", "db1.tbl2", db + ".db1"));
+
+    TestCollectRequiredObjectsHelper("INVALIDATE METADATA",
+        db, Collections.emptyList(), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("REFRESH AUTHORIZATION",
+        db, Collections.emptyList(), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("REFRESH FUNCTIONS mydb",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("INVALIDATE METADATA mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("INVALIDATE METADATA foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("REFRESH mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("REFRESH foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("REFRESH mydb.foo PARTITION (p=1)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("REFRESH foo PARTITION (p=1)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+
+    TestCollectRequiredObjectsHelper("CREATE TABLE mydb.foo(i int)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("CREATE TABLE foo(i int)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("CREATE TABLE foo LIKE bar",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo", db + ".bar"));
+    TestCollectRequiredObjectsHelper("CREATE TABLE foo AS SELECT * FROM 
db1.tbl1",
+        db, Arrays.asList(db, "db1"),
+        Arrays.asList(db + ".foo", db + ".db1", "db1.tbl1"));
+
+    TestCollectRequiredObjectsHelper("ALTER TABLE foo DROP PARTITION(p=1)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("ALTER TABLE mydb.foo ADD PARTITION(p=1)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("ALTER TABLE foo CONVERT TO ICEBERG",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("ALTER TABLE mydb.foo CONVERT TO ICEBERG",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("DROP TABLE mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("DROP TABLE foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+
+    TestCollectRequiredObjectsHelper("SHOW PARTITIONS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("SHOW FILES IN mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("SHOW TABLE STATS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("SHOW COLUMN STATS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("INSERT INTO foo SELECT * FROM bar, baz",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo", db + ".bar", db + 
".baz"));
+
+    TestCollectRequiredObjectsHelper("LOAD DATA INPATH 'path' INTO TABLE foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("LOAD DATA INPATH 'path' INTO TABLE 
mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper(
+        "LOAD DATA INPATH 'path' INTO TABLE foo PARTITION(p=1)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper(
+        "LOAD DATA INPATH 'path' INTO TABLE mydb.foo PARTITION(p=1)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("COMPUTE STATS foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("COMPUTE STATS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("COMPUTE INCREMENTAL STATS foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("COMPUTE INCREMENTAL STATS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("COMPUTE INCREMENTAL STATS foo 
PARTITION(p=1)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("COMPUTE INCREMENTAL STATS mydb.foo 
PARTITION(p=1)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("DROP STATS foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("DROP STATS mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("DROP INCREMENTAL STATS foo 
PARTITION(p=1)",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("DROP INCREMENTAL STATS mydb.foo 
PARTITION(p=1)",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("DESCRIBE foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("DESCRIBE mydb.tbl",
+        db, Arrays.asList(db, "mydb"), Arrays.asList("mydb.tbl", db + 
".mydb"));
+    TestCollectRequiredObjectsHelper("DESCRIBE mydb.tbl.complex_col",
+        db, Arrays.asList(db, "mydb"), Arrays.asList("mydb.tbl", db + 
".mydb"));
+    TestCollectRequiredObjectsHelper("DESCRIBE 
mydb.tbl.complex_col.nested_col",
+        db, Arrays.asList(db, "mydb"), Arrays.asList("mydb.tbl", db + 
".mydb"));
+    TestCollectRequiredObjectsHelper("DESCRIBE HISTORY foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("DESCRIBE HISTORY mydb.tbl",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.tbl"));
+
+    TestCollectRequiredObjectsHelper("TRUNCATE TABLE foo",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("TRUNCATE TABLE mydb.foo",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+
+    TestCollectRequiredObjectsHelper("COMMENT ON TABLE foo IS 'comment'",
+        db, Arrays.asList(db), Arrays.asList(db + ".foo"));
+    TestCollectRequiredObjectsHelper("COMMENT ON TABLE mydb.foo IS 'comment'",
+        db, Arrays.asList("mydb"), Arrays.asList("mydb.foo"));
+    TestCollectRequiredObjectsHelper("COMMENT ON DATABASE mydb IS 'comment'",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+
+    TestCollectRequiredObjectsHelper("CREATE DATABASE mydb",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("ALTER DATABASE mydb SET OWNER USER 
user1",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("DROP DATABASE mydb",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+
+    TestCollectRequiredObjectsHelper("SHOW FUNCTIONS",
+        db, Arrays.asList(db), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("SHOW FUNCTIONS IN mydb",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("SHOW TABLES",
+        db, Arrays.asList(db), Collections.emptyList());
+    TestCollectRequiredObjectsHelper("SHOW TABLES IN mydb",
+        db, Arrays.asList("mydb"), Collections.emptyList());
+  }
+
+  public void TestCollectRequiredObjectsHelper(String query,
+      String sessionDb, List<String> expectedDbNames, List<String> 
expectedTableNames)
+      throws AnalysisException {
+    StatementBase stmt = Parser.parse(query);
+    TWaitForHmsEventRequest req = new TWaitForHmsEventRequest();
+    Frontend.collectRequiredObjects(req, stmt, sessionDb);
+    if (expectedDbNames.isEmpty() && expectedTableNames.isEmpty()) {
+      assertNull(req.object_descs);
+      return;
+    }
+    List<String> dbNames = new ArrayList<>();
+    List<String> tableNames = new ArrayList<>();
+    for (TCatalogObject obj : req.getObject_descs()) {
+      if (obj.getType() == TCatalogObjectType.DATABASE) {
+        dbNames.add(obj.getDb().getDb_name());
+      } else {
+        assertEquals(TCatalogObjectType.TABLE, obj.getType());
+        tableNames.add(obj.getTable().getDb_name() + "." + 
obj.getTable().getTbl_name());
+      }
+    }
+    Collections.sort(dbNames);
+    Collections.sort(tableNames);
+    Collections.sort(expectedDbNames);
+    Collections.sort(expectedTableNames);
+    assertEquals(expectedDbNames, dbNames);
+    assertEquals(expectedTableNames, tableNames);
+  }
 }
diff --git a/fe/src/test/java/org/apache/impala/service/JdbcTestBase.java 
b/fe/src/test/java/org/apache/impala/service/JdbcTestBase.java
index f6619cb7e..47442bf8d 100644
--- a/fe/src/test/java/org/apache/impala/service/JdbcTestBase.java
+++ b/fe/src/test/java/org/apache/impala/service/JdbcTestBase.java
@@ -32,7 +32,6 @@ import org.apache.impala.analysis.StatementBase;
 import org.apache.impala.testutil.ImpalaJdbcClient;
 import org.junit.After;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 import org.junit.runner.RunWith;
 
 import com.google.common.collect.Lists;
@@ -118,7 +117,7 @@ public abstract class JdbcTestBase {
     // Once the stmt was executed successfully, add the fully-qualified table 
name
     // for cleanup in @After.
     CreateTableStmt parsedStmt = (CreateTableStmt) result;
-    testTableNames_.add(parsedStmt.getTblName().toString());
+    testTableNames_.add(parsedStmt.getTableName().toString());
   }
 
   protected void dropTestTable(String tableName) throws SQLException {
diff --git a/tests/authorization/test_ranger.py 
b/tests/authorization/test_ranger.py
index 393e11461..f79e40e18 100644
--- a/tests/authorization/test_ranger.py
+++ b/tests/authorization/test_ranger.py
@@ -1973,6 +1973,89 @@ class TestRanger(CustomClusterTestSuite):
     finally:
       self._run_query_as_user("drop database {0} cascade".format(test_db), 
ADMIN, True)
 
+  @pytest.mark.execute_serially
+  @CustomClusterTestSuite.with_args(
+    impalad_args=IMPALAD_ARGS,
+    catalogd_args=CATALOGD_ARGS + " --hms_event_polling_interval_s=5")
+  def test_alter_owner_hms_event_sync(self, unique_name):
+    """Test Impala queries that depends on database ownership changes in Hive.
+       Use a longer polling interval to mimic lag in event processing."""
+    test_user = getuser()
+    test_db = unique_name + "_db"
+    # A client that only used by 'test_user'. Just need to set the username at 
the
+    # first statement. It will keep using the same username.
+    user_client = self.create_impala_client()
+    user_client.set_configuration({"sync_hms_events_wait_time_s": 10,
+                                   "sync_hms_events_strict_mode": True})
+
+    # Methods to change ownership in Hive which will generate ALTER_DATABASE 
events.
+    def change_db_owner_to_user():
+      self.run_stmt_in_hive(
+        "alter database {0} set owner user {1}".format(test_db, test_user), 
ADMIN)
+
+    def reset_db_owner_to_admin():
+      self.run_stmt_in_hive(
+        "alter database {0} set owner user {1}".format(test_db, ADMIN), ADMIN)
+
+    # Create a test database as "admin" user. Owner is set accordingly.
+    # By default, only the "admin" user and owner of the db can read/write 
this db.
+    self._run_query_as_user(
+        "drop database if exists {0} cascade".format(test_db), ADMIN, 
expect_success=True)
+    self._run_query_as_user(
+        "create database {0}".format(test_db), ADMIN, expect_success=True)
+    try:
+      # Test table statement waits for db alter owner events
+      # Try to create a table under test_db as current user. It should fail 
since
+      # test_user is not the db owner.
+      create_tbl_stmt = "create table {0}.foo(a int)".format(test_db)
+      self.execute_query_expect_failure(user_client, create_tbl_stmt, 
user=test_user)
+      change_db_owner_to_user()
+      # Creating the table again should succeed once the ALTER_DATABASE event 
is synced.
+      self.execute_query_expect_success(user_client, create_tbl_stmt)
+      reset_db_owner_to_admin()
+
+      # Test table statement waits for table alter owner events
+      stmts = [
+        "describe {}.foo".format(test_db),
+        "insert into {}.foo values (0)".format(test_db),
+        "select * from {}.foo".format(test_db),
+        "compute stats {}.foo".format(test_db),
+        "refresh {}.foo".format(test_db),
+        "drop table {}.foo".format(test_db),
+      ]
+      for stmt in stmts:
+        # Change table owner to admin
+        self.run_stmt_in_hive(
+            "alter table {0}.foo set owner user {1}".format(test_db, ADMIN), 
ADMIN)
+        self.execute_query_expect_failure(user_client, stmt)
+        # Change table owner to user
+        self.run_stmt_in_hive(
+            "alter table {0}.foo set owner user {1}".format(test_db, 
test_user), ADMIN)
+        self.execute_query_expect_success(user_client, stmt)
+      # Create the table again since the last statement is DROP TABLE.
+      change_db_owner_to_user()
+      self.execute_query_expect_success(user_client, create_tbl_stmt)
+      reset_db_owner_to_admin()
+
+      # Test SHOW DATABASES waits for db change owner events. The db is 
invisible if user
+      # is not the owner.
+      assert test_db not in self.all_db_names(user_client)
+      change_db_owner_to_user()
+      assert test_db in self.all_db_names(user_client)
+      reset_db_owner_to_admin()
+
+      # Test SHOW TABLES
+      # Run a query on the table to make its ownership info loaded. Otherwise, 
it will
+      # be missing in SHOW TABLES due to IMPALA-8937.
+      self.execute_query_expect_success(user_client, "describe 
{}.foo".format(test_db))
+      # SHOW TABLES should fail since user is not the owner of this db
+      self.execute_query_expect_failure(user_client, "show tables in " + 
test_db)
+      change_db_owner_to_user()
+      assert ["foo"] == self.all_table_names(user_client, test_db)
+      reset_db_owner_to_admin()
+    finally:
+      self._run_query_as_user("drop database {0} cascade".format(test_db), 
ADMIN, True)
+
   @pytest.mark.execute_serially
   @CustomClusterTestSuite.with_args(
     impalad_args=IMPALAD_ARGS, catalogd_args=CATALOGD_ARGS)
diff --git a/tests/common/impala_test_suite.py 
b/tests/common/impala_test_suite.py
index db62e2242..70c162b6f 100644
--- a/tests/common/impala_test_suite.py
+++ b/tests/common/impala_test_suite.py
@@ -518,11 +518,21 @@ class ImpalaTestSuite(BaseTestSuite):
     return DelegatingHdfsClient(webhdfs_client, HadoopFsCommandLineClient())
 
   @classmethod
-  def all_db_names(cls):
-    results = cls.client.execute("show databases").data
+  def all_db_names(cls, client=None):
+    if client is None:
+      client = cls.client
+    results = client.execute("show databases").data
     # Extract first column - database name
     return [row.split("\t")[0] for row in results]
 
+  @classmethod
+  def all_table_names(cls, client=None, db="default"):
+    if client is None:
+      client = cls.client
+    results = client.execute("show tables in " + db).data
+    # Extract first column - table name
+    return [row.split("\t")[0] for row in results]
+
   @classmethod
   def cleanup_db(cls, db_name, sync_ddl=1):
     # Create a new client to avoid polluting query options of existing clients.


Reply via email to