From c9f4fdc6bc7145bb3fcfe88f15bbdf77656cdab5 Mon Sep 17 00:00:00 2001 From: Fredy Wijaya Date: Tue, 3 Apr 2018 10:58:23 -0500 Subject: [PATCH] IMPALA-6650: Add fine-grained DROP privilege Add support for executing DROP statements by granting DROP privilege. These are the new GRANT/REVOKE statements introduced at server, database, and table scopes. GRANT DROP on SERVER svr TO ROLE testrole; GRANT DROP on DATABASE db TO ROLE testrole; GRANT DROP on TABLE tbl TO ROLE testrole; REVOKE DROP on SERVER svr FROM ROLE testrole; REVOKE DROP on DATABASE db FROM ROLE testrole; REVOKE DROP on TABLE tbl FROM ROLE testrole; Testing: - Added new front-end tests - Ran front-end tests Cherry-picks: not for 2.x Change-Id: Iea1dfb0b117cb1725e9656b9a79a9aebee82b5e4 Reviewed-on: http://gerrit.cloudera.org:8080/9911 Reviewed-by: Alex Behm Tested-by: Impala Public Jenkins --- common/thrift/CatalogObjects.thrift | 3 +- fe/.gitignore | 3 + fe/src/main/cup/sql-parser.cup | 2 + .../impala/analysis/DropFunctionStmt.java | 7 +- .../apache/impala/analysis/PrivilegeSpec.java | 7 +- .../authorization/AuthorizationChecker.java | 6 +- .../impala/authorization/Privilege.java | 3 +- .../impala/analysis/AnalyzeAuthStmtsTest.java | 18 ++- .../impala/analysis/AuthorizationTest.java | 128 ++++++++++++++++-- .../apache/impala/analysis/ParserTest.java | 6 + .../test/resources/authz-policy.ini.template | 8 +- 11 files changed, 159 insertions(+), 32 deletions(-) diff --git a/common/thrift/CatalogObjects.thrift b/common/thrift/CatalogObjects.thrift index 703e701e3..ecd27dcbf 100644 --- a/common/thrift/CatalogObjects.thrift +++ b/common/thrift/CatalogObjects.thrift @@ -470,7 +470,8 @@ enum TPrivilegeLevel { SELECT, REFRESH, CREATE, - ALTER + ALTER, + DROP } // Represents a privilege in an authorization policy. Privileges contain the level diff --git a/fe/.gitignore b/fe/.gitignore index 6a1675dab..11a5e9dbb 100644 --- a/fe/.gitignore +++ b/fe/.gitignore @@ -33,6 +33,9 @@ src/test/resources/authz-policy.ini # Generated minicluster config src/test/resources/minicluster-conf.xml +# Generated hive-log4j2.properties file +src/test/resources/hive-log4j2.properties + # Generated thrift files generated-sources diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup index 4d6abfd7b..999ed1608 100644 --- a/fe/src/main/cup/sql-parser.cup +++ b/fe/src/main/cup/sql-parser.cup @@ -966,6 +966,8 @@ privilege ::= {: RESULT = TPrivilegeLevel.CREATE; :} | KW_ALTER {: RESULT = TPrivilegeLevel.ALTER; :} + | KW_DROP + {: RESULT = TPrivilegeLevel.DROP; :} | KW_ALL {: RESULT = TPrivilegeLevel.ALL; :} ; diff --git a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java index b82b9d2d9..86e90c07a 100644 --- a/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java +++ b/fe/src/main/java/org/apache/impala/analysis/DropFunctionStmt.java @@ -85,13 +85,10 @@ public class DropFunctionStmt extends StatementBase { false); } - // For now, if authorization is enabled, the user needs ALL on the server - // to drop functions. - // TODO: this is not the right granularity but acceptable for now. analyzer.registerPrivReq(new PrivilegeRequest( - new AuthorizeableFn(desc_.dbName(), desc_.signatureString()), Privilege.ALL)); + new AuthorizeableFn(desc_.dbName(), desc_.signatureString()), Privilege.DROP)); - Db db = analyzer.getDb(desc_.dbName(), Privilege.DROP, false); + Db db = analyzer.getDb(desc_.dbName(), false); if (db == null && !ifExists_) { throw new AnalysisException(Analyzer.DB_DOES_NOT_EXIST_ERROR_MSG + desc_.dbName()); } diff --git a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java index b2652ccba..ec292a2c6 100644 --- a/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java +++ b/fe/src/main/java/org/apache/impala/analysis/PrivilegeSpec.java @@ -191,9 +191,10 @@ public class PrivilegeSpec implements ParseNode { if (privilegeLevel_ != TPrivilegeLevel.ALL && privilegeLevel_ != TPrivilegeLevel.REFRESH && privilegeLevel_ != TPrivilegeLevel.CREATE && - privilegeLevel_ != TPrivilegeLevel.ALTER) { - throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' " + - "privilege may be applied at SERVER scope in privilege spec."); + privilegeLevel_ != TPrivilegeLevel.ALTER && + privilegeLevel_ != TPrivilegeLevel.DROP) { + throw new AnalysisException("Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or " + + "'DROP' privilege may be applied at SERVER scope in privilege spec."); } break; case DATABASE: diff --git a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java index 07bc4ad16..9fcf02059 100644 --- a/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java +++ b/fe/src/main/java/org/apache/impala/authorization/AuthorizationChecker.java @@ -105,13 +105,13 @@ public class AuthorizationChecker { Preconditions.checkNotNull(privilegeRequest); if (!hasAccess(user, privilegeRequest)) { + Privilege privilege = privilegeRequest.getPrivilege(); if (privilegeRequest.getAuthorizeable() instanceof AuthorizeableFn) { throw new AuthorizationException(String.format( - "User '%s' does not have privileges to CREATE/DROP functions in: %s", - user.getName(), privilegeRequest.getName())); + "User '%s' does not have privileges to %s functions in: %s", + user.getName(), privilege, privilegeRequest.getName())); } - Privilege privilege = privilegeRequest.getPrivilege(); if (EnumSet.of(Privilege.ANY, Privilege.ALL, Privilege.VIEW_METADATA) .contains(privilege)) { throw new AuthorizationException(String.format( diff --git a/fe/src/main/java/org/apache/impala/authorization/Privilege.java b/fe/src/main/java/org/apache/impala/authorization/Privilege.java index 558e4bd21..59cc8d33e 100644 --- a/fe/src/main/java/org/apache/impala/authorization/Privilege.java +++ b/fe/src/main/java/org/apache/impala/authorization/Privilege.java @@ -27,7 +27,7 @@ import org.apache.sentry.core.common.Action; public enum Privilege { ALL(SentryAction.ALL, false), ALTER(SentryAction.ALTER, false), - DROP(SentryAction.ALL, false), + DROP(SentryAction.DROP, false), CREATE(SentryAction.CREATE, false), INSERT(SentryAction.INSERT, false), SELECT(SentryAction.SELECT, false), @@ -56,6 +56,7 @@ public enum Privilege { REFRESH("refresh"), CREATE("create"), ALTER("alter"), + DROP("drop"), ALL("*"); private final String value; diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java index d1eae400f..c56102f5a 100644 --- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java +++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeAuthStmtsTest.java @@ -165,8 +165,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest { AnalyzesOk(String.format("%s INSERT ON DATABASE functional %s myrole", formatArgs)); AnalysisError(String.format("%s INSERT ON SERVER %s myrole", formatArgs), - "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " + - "SERVER scope in privilege spec."); + "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " + + "applied at SERVER scope in privilege spec."); AnalysisError(String.format("%s INSERT ON URI 'hdfs:////abc//123' %s myrole", formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " + "spec."); @@ -181,8 +181,8 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest { AnalyzesOk(String.format("%s SELECT ON DATABASE functional %s myrole", formatArgs)); AnalysisError(String.format("%s SELECT ON SERVER %s myrole", formatArgs), - "Only 'ALL', 'REFRESH', 'CREATE', or 'ALTER' privilege may be applied at " + - "SERVER scope in privilege spec."); + "Only 'ALL', 'REFRESH', 'CREATE', 'ALTER', or 'DROP' privilege may be " + + "applied at SERVER scope in privilege spec."); AnalysisError(String.format("%s SELECT ON URI 'hdfs:////abc//123' %s myrole", formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege " + "spec."); @@ -255,6 +255,16 @@ public class AnalyzeAuthStmtsTest extends AnalyzerTest { AnalysisError(String.format( "%s ALTER ON URI 'hdfs:////abc/123' %s myrole", formatArgs), "Only 'ALL' privilege may be applied at URI scope in privilege spec."); + + // DROP privilege + AnalyzesOk(String.format("%s DROP ON SERVER %s myrole", formatArgs)); + AnalyzesOk(String.format("%s DROP ON SERVER server1 %s myrole", formatArgs)); + AnalyzesOk(String.format("%s DROP ON DATABASE functional %s myrole", formatArgs)); + AnalyzesOk(String.format( + "%s DROP ON TABLE functional.alltypes %s myrole", formatArgs)); + AnalysisError(String.format( + "%s DROP ON URI 'hdfs:////abc/123' %s myrole", formatArgs), + "Only 'ALL' privilege may be applied at URI scope in privilege spec."); } AnalysisContext authDisabledCtx = createAuthDisabledAnalysisCtx(); diff --git a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java index 9085b78e1..a5173fb5b 100644 --- a/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java +++ b/fe/src/test/java/org/apache/impala/analysis/AuthorizationTest.java @@ -40,6 +40,7 @@ import org.apache.impala.catalog.AuthorizationException; import org.apache.impala.catalog.Db; import org.apache.impala.catalog.ImpaladCatalog; import org.apache.impala.catalog.ScalarFunction; +import org.apache.impala.catalog.ScalarType; import org.apache.impala.catalog.Type; import org.apache.impala.common.AnalysisException; import org.apache.impala.common.FrontendTestBase; @@ -87,11 +88,11 @@ public class AuthorizationTest extends FrontendTestBase { // ALL permission on 'tpch' database and 'newdb' database // ALL permission on 'functional_seq_snap' database // SELECT permissions on all tables in 'tpcds' database - // SELECT, REFRESH permissions on 'functional.alltypesagg' (no INSERT permissions) + // SELECT, REFRESH, DROP permissions on 'functional.alltypesagg' // ALTER permissions on 'functional.alltypeserror' - // SELECT permissions on 'functional.complex_view' (no INSERT permissions) - // SELECT, REFRESH permissions on 'functional.view_view' (no INSERT permissions) - // ALTER permission on 'functional.alltypes_view' + // SELECT permissions on 'functional.complex_view' + // SELECT, REFRESH permissions on 'functional.view_view' + // ALTER, DROP permissions on 'functional.alltypes_view' // SELECT permissions on columns ('id', 'int_col', and 'year') on // 'functional.alltypessmall' (no SELECT permissions on 'functional.alltypessmall') // SELECT permissions on columns ('id', 'int_struct_col', 'struct_array_col', @@ -105,7 +106,7 @@ public class AuthorizationTest extends FrontendTestBase { // No permissions on database 'functional_rc' // Only column level permissions in 'functional_avro': // SELECT permissions on columns ('id') on 'functional_avro.alltypessmall' - // REFRESH, INSERT, CREATE, ALTER permissions on 'functional_text_lzo' database + // REFRESH, INSERT, CREATE, ALTER, DROP permissions on 'functional_text_lzo' database public final static String AUTHZ_POLICY_FILE = "/test-warehouse/authz-policy.ini"; public final static User USER = new User(System.getProperty("user.name")); @@ -267,6 +268,18 @@ public class AuthorizationTest extends FrontendTestBase { privilege.setTable_name("alltypesagg"); sentryService.grantRolePrivilege(USER, roleName, privilege); + // drop_functional_alltypesagg + roleName = "drop_functional_alltypesagg"; + sentryService.createRole(USER, roleName, true); + sentryService.grantRoleToGroup(USER, roleName, USER.getName()); + + privilege = new TPrivilege("", TPrivilegeLevel.DROP, + TPrivilegeScope.TABLE, false); + privilege.setServer_name("server1"); + privilege.setDb_name("functional"); + privilege.setTable_name("alltypesagg"); + sentryService.grantRolePrivilege(USER, roleName, privilege); + // refresh_functional_view_view roleName = "refresh_functional_view_view"; sentryService.createRole(USER, roleName, true); @@ -279,6 +292,18 @@ public class AuthorizationTest extends FrontendTestBase { privilege.setTable_name("view_view"); sentryService.grantRolePrivilege(USER, roleName, privilege); + // drop_functional_alltypes_view + roleName = "drop_functional_alltypes_view"; + sentryService.createRole(USER, roleName, true); + sentryService.grantRoleToGroup(USER, roleName, USER.getName()); + + privilege = new TPrivilege("", TPrivilegeLevel.DROP, + TPrivilegeScope.TABLE, false); + privilege.setServer_name("server1"); + privilege.setDb_name("functional"); + privilege.setTable_name("alltypes_view"); + sentryService.grantRolePrivilege(USER, roleName, privilege); + // insert_functional_text_lzo roleName = "insert_functional_text_lzo"; sentryService.createRole(USER, roleName, true); @@ -315,6 +340,18 @@ public class AuthorizationTest extends FrontendTestBase { privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME); sentryService.grantRolePrivilege(USER, roleName, privilege); + // drop_functional_text_lzo + roleName = "drop_functional_text_lzo"; + sentryService.createRole(USER, roleName, true); + sentryService.grantRoleToGroup(USER, roleName, USER.getName()); + + privilege = new TPrivilege("", TPrivilegeLevel.DROP, TPrivilegeScope.DATABASE, + false); + privilege.setServer_name("server1"); + privilege.setDb_name("functional_text_lzo"); + privilege.setTable_name(AuthorizeableTable.ANY_TABLE_NAME); + sentryService.grantRolePrivilege(USER, roleName, privilege); + // alter_functional_alltypeserror roleName = "alter_functional_alltypeserror"; sentryService.createRole(USER, roleName, true); @@ -1244,6 +1281,15 @@ public class AuthorizationTest extends FrontendTestBase { AuthzOk("drop database if exists newdb"); AuthzOk("drop database if exists newdb cascade"); AuthzOk("drop database if exists newdb restrict"); + + // User has DROP privilege on functional_text_lzo database. + AuthzOk("drop database functional_text_lzo"); + AuthzOk("drop database functional_text_lzo cascade"); + AuthzOk("drop database functional_text_lzo restrict"); + AuthzOk("drop database if exists functional_text_lzo"); + AuthzOk("drop database if exists functional_text_lzo cascade"); + AuthzOk("drop database if exists functional_text_lzo restrict"); + // User has permission, database does not exists, IF EXISTS not specified. try { AuthzOk("drop database newdb"); @@ -1294,6 +1340,9 @@ public class AuthorizationTest extends FrontendTestBase { AuthzOk("drop table tpch.lineitem"); AuthzOk("drop table if exists tpch.lineitem"); + // User has DROP privilege on functional.alltypesagg table. + AuthzOk("drop table functional.alltypesagg"); + // Drop table (user does not have permission). AuthzError("drop table functional.alltypes", "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes"); @@ -1330,10 +1379,13 @@ public class AuthorizationTest extends FrontendTestBase { AuthzOk("drop view functional_seq_snap.alltypes_view"); AuthzOk("drop view if exists functional_seq_snap.alltypes_view"); - // Drop view (user does not have permission). - AuthzError("drop view functional.alltypes_view", + // User has DROP privilege on functional.alltypes_view view. + AuthzOk("drop view functional.alltypes_view"); + + // User does not have DROP privilege on functional.alltypes_view_sub view. + AuthzError("drop view functional.alltypes_view_sub", "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes"); - AuthzError("drop view if exists functional.alltypes_view", + AuthzError("drop view if exists functional.alltypes_view_sub", "User '%s' does not have privileges to execute 'DROP' on: functional.alltypes"); // Drop view with unqualified table name. @@ -2412,7 +2464,7 @@ public class AuthorizationTest extends FrontendTestBase { AuthzError(ctx, "create function f() returns int location " + "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'", - "User '%s' does not have privileges to CREATE/DROP functions in: default.f()"); + "User '%s' does not have privileges to CREATE functions in: default.f()"); // User has ALL privilege on tpch database and ALL privilege on // /test-warehouse/libTestUdfs.so URI. @@ -2421,19 +2473,31 @@ public class AuthorizationTest extends FrontendTestBase { AuthzError(ctx, "create function notdb.f() returns int location " + "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'", - "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()"); + "User '%s' does not have privileges to CREATE functions in: notdb.f()"); + + // User has DROP privilege on functional_text_lzo database. + try { + ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional_text_lzo", + "f", new ArrayList(), Type.INT, "/dummy", "dummy.class", null, + null, TFunctionBinaryType.NATIVE)); + AuthzOk("drop function functional_text_lzo.f()"); + } finally { + ctx_.catalog.removeFunction(ScalarFunction.createForTesting("functional_text_lzo", + "f", new ArrayList(), Type.INT, "/dummy", "dummy.class", null, + null, TFunctionBinaryType.NATIVE)); + } AuthzError(ctx, "drop function if exists f()", - "User '%s' does not have privileges to CREATE/DROP functions in: default.f()"); + "User '%s' does not have privileges to DROP functions in: default.f()"); AuthzError(ctx, "drop function notdb.f()", - "User '%s' does not have privileges to CREATE/DROP functions in: notdb.f()"); + "User '%s' does not have privileges to DROP functions in: notdb.f()"); // User does not have ALL privilege on SERVER and tries to create a function with // the same name as the built-in function. AuthzError(ctx, "create function sin(double) returns double location " + "'/test-warehouse/libTestUdfs.so' symbol='NoArgs'", - "User '%s' does not have privileges to CREATE/DROP functions in: " + + "User '%s' does not have privileges to CREATE functions in: " + "default.sin(DOUBLE)"); // User tries to create a function in the system database. AuthzError(ctx, "create function _impala_builtins.sin(double) returns double " + @@ -2446,7 +2510,7 @@ public class AuthorizationTest extends FrontendTestBase { AuthzError(ctx, "drop function _impala_builtins.sin(double)", "Cannot modify system database."); AuthzError(ctx, "drop function sin(double)", - "User '%s' does not have privileges to CREATE/DROP functions in: " + + "User '%s' does not have privileges to DROP functions in: " + "default.sin(DOUBLE)"); // TODO: Add test support for dynamically changing privileges for @@ -2737,6 +2801,42 @@ public class AuthorizationTest extends FrontendTestBase { } } + @Test + public void TestServerLevelDrop() throws ImpalaException { + // TODO: Add test support for dynamically changing privileges for + // file-based policy. + if (ctx_.authzConfig.isFileBasedPolicy()) return; + + SentryPolicyService sentryService = + new SentryPolicyService(ctx_.authzConfig.getSentryConfig()); + + // User has DROP privilege on server. + String roleName = "drop_role"; + try { + sentryService.createRole(USER, roleName, true); + TPrivilege privilege = new TPrivilege("", TPrivilegeLevel.DROP, + TPrivilegeScope.SERVER, false); + privilege.setServer_name("server1"); + sentryService.grantRolePrivilege(USER, roleName, privilege); + sentryService.grantRoleToGroup(USER, roleName, USER.getName()); + ctx_.catalog.reset(); + + AuthzOk("drop database functional"); + AuthzOk("drop table functional.alltypes"); + AuthzOk("drop view functional.alltypes_view_sub"); + ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional", + "f", new ArrayList(), Type.INT, "/dummy", "dummy.class", null, + null, TFunctionBinaryType.NATIVE)); + AuthzOk("drop function functional.f()"); + } finally { + sentryService.dropRole(USER, roleName, true); + ctx_.catalog.reset(); + ctx_.catalog.addFunction(ScalarFunction.createForTesting("functional", + "f", new ArrayList(), Type.INT, "/dummy", "dummy.class", null, + null, TFunctionBinaryType.NATIVE)); + } + } + private void TestWithIncorrectConfig(AuthorizationConfig authzConfig, User user) throws ImpalaException { Frontend fe = new Frontend(authzConfig, ctx_.catalog); diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java index 3eab55eae..ab0eb78c5 100644 --- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java +++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java @@ -3592,6 +3592,12 @@ public class ParserTest extends FrontendTestBase { ParsesOk(String.format("%s ALTER ON DATABASE foo %s myRole", formatStr)); ParsesOk(String.format("%s ALTER ON TABLE foo %s myRole", formatStr)); + // DROP privilege. + ParsesOk(String.format("%s DROP ON SERVER %s myRole", formatStr)); + ParsesOk(String.format("%s DROP ON SERVER foo %s myRole", formatStr)); + ParsesOk(String.format("%s DROP ON DATABASE foo %s myRole", formatStr)); + ParsesOk(String.format("%s DROP ON TABLE foo %s myRole", formatStr)); + // Server scope does not accept a name. ParsesOk(String.format("%s ALL ON SERVER %s myRole", formatStr)); ParsesOk(String.format("%s INSERT ON SERVER %s myRole", formatStr)); diff --git a/fe/src/test/resources/authz-policy.ini.template b/fe/src/test/resources/authz-policy.ini.template index 82b106001..26ed70b8f 100644 --- a/fe/src/test/resources/authz-policy.ini.template +++ b/fe/src/test/resources/authz-policy.ini.template @@ -29,7 +29,8 @@ ${USER} = all_tpch, all_newdb, all_functional_seq_snap, select_tpcds,\ refresh_functional_view_view, insert_functional_text_lzo,\ create_functional_text_lzo, alter_functional_text_lzo,\ alter_functional_alltypeserror, alter_functional_alltypes_view,\ - libtestudfs_uri + libtestudfs_uri, drop_functional_text_lzo, drop_functional_alltypesagg,\ + drop_functional_alltypes_view auth_to_local_group = test_role server_admin = all_server @@ -55,15 +56,20 @@ insert_parquet = server=server1->db=functional_parquet->table=*->action=insert refresh_functional_text_lzo = server=server1->db=functional_text_lzo->action=refresh refresh_functional_alltypesagg =\ server=server1->db=functional->table=alltypesagg->action=refresh +drop_functional_alltypesagg =\ + server=server1->db=functional->table=alltypesagg->action=drop alter_functional_alltypeserror =\ server=server1->db=functional->table=alltypeserror->action=alter refresh_functional_view_view =\ server=server1->db=functional->table=view_view->action=refresh +drop_functional_alltypes_view =\ + server=server1->db=functional->table=alltypes_view->action=drop alter_functional_alltypes_view =\ server=server1->db=functional->table=alltypes_view->action=alter insert_functional_text_lzo = server=server1->db=functional_text_lzo->action=insert create_functional_text_lzo = server=server1->db=functional_text_lzo->action=create alter_functionl_text_lzo = server=server1->db=functional_text_lzo->action=alter +drop_functional_text_lzo = server=server1->db=functional_text_lzo->action=drop select_column_level_functional =\ server=server1->db=functional->table=alltypessmall->column=id->action=select,\ server=server1->db=functional->table=alltypessmall->column=int_col->action=select,\