diff --git a/fe/fe-core/src/main/java/com/starrocks/alter/AlterJobExecutor.java b/fe/fe-core/src/main/java/com/starrocks/alter/AlterJobExecutor.java
index b363d7e5abd1cf..126271f8f8f974 100644
--- a/fe/fe-core/src/main/java/com/starrocks/alter/AlterJobExecutor.java
+++ b/fe/fe-core/src/main/java/com/starrocks/alter/AlterJobExecutor.java
@@ -35,6 +35,7 @@
import com.starrocks.catalog.RangePartitionInfo;
import com.starrocks.catalog.Table;
import com.starrocks.catalog.Type;
+import com.starrocks.catalog.View;
import com.starrocks.common.AnalysisException;
import com.starrocks.common.DdlException;
import com.starrocks.common.ErrorCode;
@@ -205,6 +206,12 @@ public Void visitAlterViewStatement(AlterViewStmt statement, ConnectContext cont
this.db = db;
this.table = table;
+
+ if (statement.getAlterClause() == null) {
+ ((View) table).setSecurity(statement.isSecurity());
+ return null;
+ }
+
AlterViewClause alterViewClause = (AlterViewClause) statement.getAlterClause();
visit(alterViewClause, context);
return null;
diff --git a/fe/fe-core/src/main/java/com/starrocks/authorization/ColumnPrivilege.java b/fe/fe-core/src/main/java/com/starrocks/authorization/ColumnPrivilege.java
index b65adafde6335d..4b3c8a949e79b7 100644
--- a/fe/fe-core/src/main/java/com/starrocks/authorization/ColumnPrivilege.java
+++ b/fe/fe-core/src/main/java/com/starrocks/authorization/ColumnPrivilege.java
@@ -16,6 +16,7 @@
import com.google.common.collect.Maps;
import com.starrocks.analysis.TableName;
+import com.starrocks.catalog.BasicTable;
import com.starrocks.catalog.Column;
import com.starrocks.catalog.InternalCatalog;
import com.starrocks.catalog.Table;
@@ -23,6 +24,7 @@
import com.starrocks.catalog.system.SystemTable;
import com.starrocks.connector.metadata.MetadataTable;
import com.starrocks.qe.ConnectContext;
+import com.starrocks.server.GlobalStateMgr;
import com.starrocks.sql.StatementPlanner;
import com.starrocks.sql.analyzer.Authorizer;
import com.starrocks.sql.ast.AstTraverser;
@@ -147,6 +149,18 @@ public static void check(ConnectContext context, QueryStatement stmt, List
allTables = view.getTableRefs();
+ for (TableName t : allTables) {
+ BasicTable basicTable = GlobalStateMgr.getCurrentState().getMetadataMgr().getBasicTable(
+ InternalCatalog.DEFAULT_INTERNAL_CATALOG_NAME, t.getDb(), t.getTbl());
+
+ Authorizer.checkAnyActionOnTableLikeObject(context.getCurrentUserIdentity(),
+ null, t.getDb(), basicTable);
+ }
+ }
+
Authorizer.checkViewAction(context.getCurrentUserIdentity(), context.getCurrentRoleIds(),
tableName, PrivilegeType.SELECT);
}
diff --git a/fe/fe-core/src/main/java/com/starrocks/catalog/View.java b/fe/fe-core/src/main/java/com/starrocks/catalog/View.java
index 61793a78aeb3eb..a7caf904ac0c14 100644
--- a/fe/fe-core/src/main/java/com/starrocks/catalog/View.java
+++ b/fe/fe-core/src/main/java/com/starrocks/catalog/View.java
@@ -86,6 +86,9 @@ public class View extends Table {
@SerializedName(value = "m")
private long sqlMode = 0L;
+ @SerializedName(value = "s")
+ private boolean security = false;
+
// cache used table names
private List tableRefsCache = Lists.newArrayList();
@@ -136,6 +139,14 @@ public long getSqlMode() {
return sqlMode;
}
+ public void setSecurity(boolean security) {
+ this.security = security;
+ }
+
+ public boolean isSecurity() {
+ return security;
+ }
+
/**
* Initializes the originalViewDef, inlineViewDef, and queryStmt members
* by parsing the expanded view definition SQL-string.
diff --git a/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java b/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java
index 4eedb8163b7222..f8f9e11c338256 100644
--- a/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java
+++ b/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java
@@ -4242,6 +4242,11 @@ public void createView(CreateViewStmt stmt) throws DdlException {
view.setInlineViewDefWithSqlMode(stmt.getInlineViewDef(),
ConnectContext.get().getSessionVariable().getSqlMode());
// init here in case the stmt string from view.toSql() has some syntax error.
+
+ if (stmt.isSecurity()) {
+ view.setSecurity(stmt.isSecurity());
+ }
+
try {
view.init();
} catch (StarRocksException e) {
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/analyzer/ViewAnalyzer.java b/fe/fe-core/src/main/java/com/starrocks/sql/analyzer/ViewAnalyzer.java
index 1d1df0f360a3d5..6725d700eca829 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/analyzer/ViewAnalyzer.java
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/analyzer/ViewAnalyzer.java
@@ -80,6 +80,10 @@ public Void visitAlterViewStatement(AlterViewStmt stmt, ConnectContext context)
throw new SemanticException("The specified table [" + tableName + "] is not a view");
}
+ if (stmt.getAlterClause() == null) {
+ return null;
+ }
+
AlterClause alterClause = stmt.getAlterClause();
AlterViewClause alterViewClause = (AlterViewClause) alterClause;
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/ast/AlterViewStmt.java b/fe/fe-core/src/main/java/com/starrocks/sql/ast/AlterViewStmt.java
index 80def814b45011..eaee17cd61c853 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/ast/AlterViewStmt.java
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/ast/AlterViewStmt.java
@@ -20,11 +20,13 @@
// Alter view statement
public class AlterViewStmt extends DdlStmt {
private final TableName tableName;
+ private final boolean security;
private final AlterClause alterClause;
- public AlterViewStmt(TableName tableName, AlterClause alterClause, NodePosition pos) {
+ public AlterViewStmt(TableName tableName, boolean security, AlterClause alterClause, NodePosition pos) {
super(pos);
this.tableName = tableName;
+ this.security = security;
this.alterClause = alterClause;
}
@@ -34,13 +36,17 @@ public static AlterViewStmt fromReplaceStmt(CreateViewStmt stmt) {
alterViewClause.setInlineViewDef(stmt.getInlineViewDef());
alterViewClause.setColumns(stmt.getColumns());
alterViewClause.setComment(stmt.getComment());
- return new AlterViewStmt(stmt.getTableName(), alterViewClause, NodePosition.ZERO);
+ return new AlterViewStmt(stmt.getTableName(), stmt.isSecurity(), alterViewClause, NodePosition.ZERO);
}
public TableName getTableName() {
return tableName;
}
+ public boolean isSecurity() {
+ return security;
+ }
+
public AlterClause getAlterClause() {
return alterClause;
}
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/ast/CreateViewStmt.java b/fe/fe-core/src/main/java/com/starrocks/sql/ast/CreateViewStmt.java
index a8fd68fb1a4914..5cb67743871dde 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/ast/CreateViewStmt.java
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/ast/CreateViewStmt.java
@@ -27,15 +27,19 @@ public class CreateViewStmt extends DdlStmt {
private final boolean ifNotExists;
private final boolean replace;
private final String comment;
+ private final boolean security;
protected QueryStatement queryStatement;
//Resolved by Analyzer
protected List columns;
private String inlineViewDef;
- public CreateViewStmt(boolean ifNotExists, boolean replace,
- TableName tableName, List colWithComments,
+ public CreateViewStmt(boolean ifNotExists,
+ boolean replace,
+ TableName tableName,
+ List colWithComments,
String comment,
+ boolean security,
QueryStatement queryStmt,
NodePosition pos) {
super(pos);
@@ -44,6 +48,7 @@ public CreateViewStmt(boolean ifNotExists, boolean replace,
this.tableName = tableName;
this.colWithComments = colWithComments;
this.comment = Strings.nullToEmpty(comment);
+ this.security = security;
this.queryStatement = queryStmt;
}
@@ -79,6 +84,10 @@ public String getComment() {
return comment;
}
+ public boolean isSecurity() {
+ return security;
+ }
+
public QueryStatement getQueryStatement() {
return queryStatement;
}
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/parser/AstBuilder.java b/fe/fe-core/src/main/java/com/starrocks/sql/parser/AstBuilder.java
index 1d7ebd2304ff80..281df72d0b80e1 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/parser/AstBuilder.java
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/parser/AstBuilder.java
@@ -1616,12 +1616,23 @@ public ParseNode visitCreateViewStatement(StarRocksParser.CreateViewStatementCon
throw new ParsingException(PARSER_ERROR_MSG.conflictedOptions("if not exists", "or replace"),
createPos(context));
}
+
+ boolean isSecurity = false;
+ if (context.SECURITY() != null) {
+ if (context.NONE() != null) {
+ isSecurity = false;
+ } else if (context.INVOKER() != null) {
+ isSecurity = true;
+ }
+ }
+
return new CreateViewStmt(
context.IF() != null,
context.REPLACE() != null,
targetTableName,
colWithComments,
context.comment() == null ? null : ((StringLiteral) visit(context.comment())).getStringValue(),
+ isSecurity,
(QueryStatement) visit(context.queryStatement()), createPos(context));
}
@@ -1631,13 +1642,25 @@ public ParseNode visitAlterViewStatement(StarRocksParser.AlterViewStatementConte
TableName targetTableName = qualifiedNameToTableName(qualifiedName);
List colWithComments = null;
- if (context.columnNameWithComment().size() > 0) {
+ if (!context.columnNameWithComment().isEmpty()) {
colWithComments = visit(context.columnNameWithComment(), ColWithComment.class);
}
- QueryStatement queryStatement = (QueryStatement) visit(context.queryStatement());
- AlterClause alterClause = new AlterViewClause(colWithComments, queryStatement, createPos(context));
- return new AlterViewStmt(targetTableName, alterClause, createPos(context));
+ boolean isSecurity = false;
+ if (context.SECURITY() != null) {
+ if (context.NONE() != null) {
+ isSecurity = false;
+ } else if (context.INVOKER() != null) {
+ isSecurity = true;
+ }
+
+ return new AlterViewStmt(targetTableName, isSecurity, null, createPos(context));
+ } else {
+ QueryStatement queryStatement = (QueryStatement) visit(context.queryStatement());
+ AlterClause alterClause = new AlterViewClause(colWithComments, queryStatement, createPos(context));
+
+ return new AlterViewStmt(targetTableName, isSecurity, alterClause, createPos(context));
+ }
}
@Override
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocks.g4 b/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocks.g4
index cd736caedf390f..07ba111c159cfe 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocks.g4
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocks.g4
@@ -607,12 +607,15 @@ recoverPartitionStatement
createViewStatement
: CREATE (OR REPLACE)? VIEW (IF NOT EXISTS)? qualifiedName
- ('(' columnNameWithComment (',' columnNameWithComment)* ')')?
- comment? AS queryStatement
+ ('(' columnNameWithComment (',' columnNameWithComment)* ')')?
+ comment?
+ (SECURITY (NONE | INVOKER))?
+ AS queryStatement
;
alterViewStatement
- : ALTER VIEW qualifiedName ('(' columnNameWithComment (',' columnNameWithComment)* ')')? AS queryStatement
+ : ALTER VIEW qualifiedName ('(' columnNameWithComment (',' columnNameWithComment)* ')')? AS queryStatement
+ | ALTER VIEW qualifiedName SET SECURITY (NONE | INVOKER)
;
dropViewStatement
diff --git a/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocksLex.g4 b/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocksLex.g4
index 3bebb0ca736e75..a6ed05a1e28dca 100644
--- a/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocksLex.g4
+++ b/fe/fe-core/src/main/java/com/starrocks/sql/parser/StarRocksLex.g4
@@ -226,6 +226,7 @@ INTERMEDIATE: 'INTERMEDIATE';
INTERSECT: 'INTERSECT';
INTERVAL: 'INTERVAL';
INTO: 'INTO';
+INVOKER: 'INVOKER';
GIN: 'GIN';
OVERWRITE: 'OVERWRITE';
IS: 'IS';
diff --git a/fe/fe-core/src/test/java/com/starrocks/connector/iceberg/IcebergMetadataTest.java b/fe/fe-core/src/test/java/com/starrocks/connector/iceberg/IcebergMetadataTest.java
index 43fd2434fc0da9..49358b31f711d9 100644
--- a/fe/fe-core/src/test/java/com/starrocks/connector/iceberg/IcebergMetadataTest.java
+++ b/fe/fe-core/src/test/java/com/starrocks/connector/iceberg/IcebergMetadataTest.java
@@ -1491,7 +1491,7 @@ public void testCreateView(@Mocked RESTCatalog restCatalog, @Mocked BaseView bas
};
CreateViewStmt stmt = new CreateViewStmt(false, false, new TableName("catalog", "db", "table"),
- Lists.newArrayList(new ColWithComment("k1", "", NodePosition.ZERO)), "", null, NodePosition.ZERO);
+ Lists.newArrayList(new ColWithComment("k1", "", NodePosition.ZERO)), "", false, null, NodePosition.ZERO);
stmt.setColumns(Lists.newArrayList(new Column("k1", INT)));
metadata.createView(stmt);
diff --git a/test/sql/test_alter_view/R/test_alter_view b/test/sql/test_view/R/test_alter_view
similarity index 100%
rename from test/sql/test_alter_view/R/test_alter_view
rename to test/sql/test_view/R/test_alter_view
diff --git a/test/sql/test_view/R/test_security_view b/test/sql/test_view/R/test_security_view
new file mode 100644
index 00000000000000..9372eddbf9b256
--- /dev/null
+++ b/test/sql/test_view/R/test_security_view
@@ -0,0 +1,105 @@
+-- name: test_security_view
+create table t1(c1 bigint, c2 bigint);
+-- result:
+-- !result
+create table t2(c3 bigint, c4 bigint);
+-- result:
+-- !result
+create view v1 as select * from t1, t2;
+-- result:
+-- !result
+create view v2 security invoker as select * from t1, t2;
+-- result:
+-- !result
+create user if not exists u1;
+-- result:
+-- !result
+grant impersonate on user root to u1;
+-- result:
+-- !result
+grant select on view v1 to user u1;
+-- result:
+-- !result
+grant select on view v2 to user u1;
+-- result:
+-- !result
+create user if not exists u2;
+-- result:
+-- !result
+grant impersonate on user root to u2;
+-- result:
+-- !result
+grant select on table t1 to user u2;
+-- result:
+-- !result
+grant select on table t2 to user u2;
+-- result:
+-- !result
+grant select on view v1 to user u2;
+-- result:
+-- !result
+grant select on view v2 to user u2;
+-- result:
+-- !result
+execute as u1 with no revert;
+-- result:
+-- !result
+select * from v1;
+-- result:
+-- !result
+select * from v2;
+-- result:
+E: (5203, 'Access denied; you need (at least one of) the SELECT privilege(s) on VIEW v2 for this operation. Please ask the admin to grant permission(s) or try activating existing roles using . Current role(s): NONE. Inactivated role(s): NONE.')
+-- !result
+execute as root with no revert;
+-- result:
+-- !result
+execute as u2 with no revert;
+-- result:
+-- !result
+select * from v1;
+-- result:
+-- !result
+select * from v2;
+-- result:
+-- !result
+execute as root with no revert;
+-- result:
+-- !result
+alter view v1 set security invoker;
+-- result:
+-- !result
+alter view v2 set security none;
+-- result:
+-- !result
+execute as u1 with no revert;
+-- result:
+-- !result
+select * from v1;
+-- result:
+E: (5203, 'Access denied; you need (at least one of) the SELECT privilege(s) on VIEW v1 for this operation. Please ask the admin to grant permission(s) or try activating existing roles using . Current role(s): NONE. Inactivated role(s): NONE.')
+-- !result
+select * from v2;
+-- result:
+-- !result
+execute as root with no revert;
+-- result:
+-- !result
+execute as u2 with no revert;
+-- result:
+-- !result
+select * from v1;
+-- result:
+-- !result
+select * from v2;
+-- result:
+-- !result
+execute as root with no revert;
+-- result:
+-- !result
+drop user u1;
+-- result:
+-- !result
+drop user u2;
+-- result:
+-- !result
\ No newline at end of file
diff --git a/test/sql/test_alter_view/T/test_alter_view b/test/sql/test_view/T/test_alter_view
similarity index 100%
rename from test/sql/test_alter_view/T/test_alter_view
rename to test/sql/test_view/T/test_alter_view
diff --git a/test/sql/test_view/T/test_security_view b/test/sql/test_view/T/test_security_view
new file mode 100644
index 00000000000000..b926495defd4b8
--- /dev/null
+++ b/test/sql/test_view/T/test_security_view
@@ -0,0 +1,45 @@
+-- name: test_security_view
+
+create table t1(c1 bigint, c2 bigint);
+create table t2(c3 bigint, c4 bigint);
+
+create view v1 as select * from t1, t2;
+create view v2 security invoker as select * from t1, t2;
+
+create user if not exists u1;
+grant impersonate on user root to u1;
+grant select on view v1 to user u1;
+grant select on view v2 to user u1;
+
+create user if not exists u2;
+grant impersonate on user root to u2;
+grant select on table t1 to user u2;
+grant select on table t2 to user u2;
+grant select on view v1 to user u2;
+grant select on view v2 to user u2;
+
+execute as u1 with no revert;
+select * from v1;
+select * from v2;
+execute as root with no revert;
+
+execute as u2 with no revert;
+select * from v1;
+select * from v2;
+execute as root with no revert;
+
+alter view v1 set security invoker;
+alter view v2 set security none;
+
+execute as u1 with no revert;
+select * from v1;
+select * from v2;
+execute as root with no revert;
+
+execute as u2 with no revert;
+select * from v1;
+select * from v2;
+execute as root with no revert;
+
+drop user u1;
+drop user u2;
\ No newline at end of file