@@ -270,6 +270,9 @@ func (u *sqlSymUnion) auditMode() tree.AuditMode {
270
270
func (u *sqlSymUnion) bool() bool {
271
271
return u.val.(bool)
272
272
}
273
+ func (u *sqlSymUnion) viewOptions() *tree.ViewOptions {
274
+ return u.val.(*tree.ViewOptions)
275
+ }
273
276
func (u *sqlSymUnion) strPtr() *string {
274
277
return u.val.(*string)
275
278
}
@@ -1056,7 +1059,7 @@ func (u *sqlSymUnion) doBlockOption() tree.DoBlockOption {
1056
1059
%token <str> REVOKE RIGHT ROLE ROLES ROLLBACK ROLLUP ROUTINES ROW ROWS RSHIFT RULE RUNNING
1057
1060
1058
1061
%token <str> SAVEPOINT SCANS SCATTER SCHEDULE SCHEDULES SCROLL SCHEMA SCHEMA_ONLY SCHEMAS SCRUB
1059
- %token <str> SEARCH SECOND SECONDARY SECURITY SELECT SEQUENCE SEQUENCES
1062
+ %token <str> SEARCH SECOND SECONDARY SECURITY SECURITY_INVOKER SELECT SEQUENCE SEQUENCES
1060
1063
%token <str> SERIALIZABLE SERVER SERVICE SESSION SESSIONS SESSION_USER SET SETOF SETS SETTING SETTINGS
1061
1064
%token <str> SHARE SHARED SHOW SIMILAR SIMPLE SIZE SKIP SKIP_LOCALITIES_CHECK SKIP_MISSING_FOREIGN_KEYS
1062
1065
%token <str> SKIP_MISSING_SEQUENCES SKIP_MISSING_SEQUENCE_OWNERS SKIP_MISSING_VIEWS SKIP_MISSING_UDFS SMALLINT SMALLSERIAL
@@ -1206,6 +1209,7 @@ func (u *sqlSymUnion) doBlockOption() tree.DoBlockOption {
1206
1209
%type <tree.Statement> alter_rename_view_stmt
1207
1210
%type <tree.Statement> alter_view_set_schema_stmt
1208
1211
%type <tree.Statement> alter_view_owner_stmt
1212
+ %type <tree.Statement> alter_view_set_options_stmt
1209
1213
1210
1214
// ALTER SEQUENCE
1211
1215
%type <tree.Statement> alter_rename_sequence_stmt
@@ -1801,6 +1805,7 @@ func (u *sqlSymUnion) doBlockOption() tree.DoBlockOption {
1801
1805
%type <*tree.TriggerTransition> trigger_transition
1802
1806
%type <[]*tree.TriggerTransition> trigger_transition_list opt_trigger_transition_list
1803
1807
%type <bool> transition_is_new transition_is_row
1808
+ %type <*tree.ViewOptions> opt_view_with
1804
1809
%type <tree.TriggerForEach> trigger_for_each trigger_for_type
1805
1810
%type <tree.Expr> trigger_when
1806
1811
%type <str> trigger_func_arg opt_as function_or_procedure
@@ -2055,6 +2060,7 @@ alter_view_stmt:
2055
2060
alter_rename_view_stmt
2056
2061
| alter_view_set_schema_stmt
2057
2062
| alter_view_owner_stmt
2063
+ | alter_view_set_options_stmt
2058
2064
// ALTER VIEW has its error help token here because the ALTER VIEW
2059
2065
// prefix is spread over multiple non-terminals.
2060
2066
| ALTER VIEW error // SHOW HELP: ALTER VIEW
@@ -11901,44 +11907,50 @@ role_or_group_or_user:
11901
11907
// %Help: CREATE VIEW - create a new view
11902
11908
// %Category: DDL
11903
11909
// %Text:
11904
- // CREATE [TEMPORARY | TEMP] VIEW [IF NOT EXISTS] <viewname> [( <colnames...> )] AS <source>
11910
+ // CREATE [TEMPORARY | TEMP] VIEW [IF NOT EXISTS] <viewname> [( <colnames...> )] [WITH ( <option> [= <value>] [, ....] )] AS <source>
11905
11911
// CREATE [TEMPORARY | TEMP] MATERIALIZED VIEW [IF NOT EXISTS] <viewname> [( <colnames...> )] AS <source> [WITH [NO] DATA]
11912
+ //
11913
+ // Options:
11914
+ // security_invoker [= { true | false | 1 | 0 }]: controls view permissions (defaults to true if specified without value)
11906
11915
// %SeeAlso: CREATE TABLE, SHOW CREATE, WEBDOCS/create-view.html
11907
11916
create_view_stmt:
11908
- CREATE opt_temp opt_view_recursive VIEW view_name opt_column_list AS select_stmt
11917
+ CREATE opt_temp opt_view_recursive VIEW view_name opt_column_list opt_view_with AS select_stmt
11909
11918
{
11910
11919
name := $5.unresolvedObjectName().ToTableName()
11911
11920
$$.val = &tree.CreateView{
11912
11921
Name: name,
11913
11922
ColumnNames: $6.nameList(),
11914
- AsSource: $8 .slct(),
11923
+ AsSource: $9 .slct(),
11915
11924
Persistence: $2.persistence(),
11925
+ Options: $7.viewOptions(),
11916
11926
IfNotExists: false,
11917
11927
Replace: false,
11918
11928
}
11919
11929
}
11920
11930
// We cannot use a rule like opt_or_replace here as that would cause a conflict
11921
11931
// with the opt_temp rule.
11922
- | CREATE OR REPLACE opt_temp opt_view_recursive VIEW view_name opt_column_list AS select_stmt
11932
+ | CREATE OR REPLACE opt_temp opt_view_recursive VIEW view_name opt_column_list opt_view_with AS select_stmt
11923
11933
{
11924
11934
name := $7.unresolvedObjectName().ToTableName()
11925
11935
$$.val = &tree.CreateView{
11926
11936
Name: name,
11927
11937
ColumnNames: $8.nameList(),
11928
- AsSource: $10 .slct(),
11938
+ AsSource: $11 .slct(),
11929
11939
Persistence: $4.persistence(),
11940
+ Options: $9.viewOptions(),
11930
11941
IfNotExists: false,
11931
11942
Replace: true,
11932
11943
}
11933
11944
}
11934
- | CREATE opt_temp opt_view_recursive VIEW IF NOT EXISTS view_name opt_column_list AS select_stmt
11945
+ | CREATE opt_temp opt_view_recursive VIEW IF NOT EXISTS view_name opt_column_list opt_view_with AS select_stmt
11935
11946
{
11936
11947
name := $8.unresolvedObjectName().ToTableName()
11937
11948
$$.val = &tree.CreateView{
11938
11949
Name: name,
11939
11950
ColumnNames: $9.nameList(),
11940
- AsSource: $11 .slct(),
11951
+ AsSource: $12 .slct(),
11941
11952
Persistence: $2.persistence(),
11953
+ Options: $10.viewOptions(),
11942
11954
IfNotExists: true,
11943
11955
Replace: false,
11944
11956
}
@@ -12154,6 +12166,44 @@ opt_view_recursive:
12154
12166
/* EMPTY */ { /* no error */ }
12155
12167
| RECURSIVE { return unimplemented(sqllex, "create recursive view") }
12156
12168
12169
+ // View-specific WITH clause that only accepts security_invoker
12170
+ opt_view_with:
12171
+ /* EMPTY */
12172
+ {
12173
+ $$.val = (*tree.ViewOptions)(nil)
12174
+ }
12175
+ | WITH '(' SECURITY_INVOKER ')'
12176
+ {
12177
+ /* SKIP DOC */
12178
+ // security_invoker without value defaults to true
12179
+ $$.val = &tree.ViewOptions{SecurityInvoker: true}
12180
+ }
12181
+ | WITH '(' SECURITY_INVOKER '=' TRUE ')'
12182
+ {
12183
+ /* SKIP DOC */
12184
+ $$.val = &tree.ViewOptions{SecurityInvoker: true}
12185
+ }
12186
+ | WITH '(' SECURITY_INVOKER '=' FALSE ')'
12187
+ {
12188
+ /* SKIP DOC */
12189
+ $$.val = &tree.ViewOptions{SecurityInvoker: false}
12190
+ }
12191
+ | WITH '(' SECURITY_INVOKER '=' ICONST ')'
12192
+ {
12193
+ /* SKIP DOC */
12194
+ // Handle integer values: 1 = true, 0 = false
12195
+ val, err := $5.numVal().AsInt64()
12196
+ if err != nil {
12197
+ return setErr(sqllex, err)
12198
+ }
12199
+ if val == 1 {
12200
+ $$.val = &tree.ViewOptions{SecurityInvoker: true}
12201
+ } else if val == 0 {
12202
+ $$.val = &tree.ViewOptions{SecurityInvoker: false}
12203
+ } else {
12204
+ return setErr(sqllex, errors.New("security_invoker accepts only true/false or 1/0"))
12205
+ }
12206
+ }
12157
12207
12158
12208
// %Help: CREATE TYPE - create a type
12159
12209
// %Category: DDL
@@ -12768,6 +12818,16 @@ alter_view_owner_stmt:
12768
12818
}
12769
12819
}
12770
12820
12821
+ alter_view_set_options_stmt:
12822
+ ALTER VIEW relation_expr SET '(' SECURITY_INVOKER '=' var_value ')'
12823
+ {
12824
+ return unimplemented(sqllex, "ALTER VIEW ... SET (security_invoker = ...) is not yet implemented.")
12825
+ }
12826
+ | ALTER VIEW IF EXISTS relation_expr SET '(' SECURITY_INVOKER '=' var_value ')'
12827
+ {
12828
+ return unimplemented(sqllex, "ALTER VIEW ... IF EXISTS SET (security_invoker = ...) is not yet implemented.")
12829
+ }
12830
+
12771
12831
alter_sequence_set_schema_stmt:
12772
12832
ALTER SEQUENCE relation_expr SET SCHEMA schema_name
12773
12833
{
@@ -18493,6 +18553,7 @@ unreserved_keyword:
18493
18553
| SEARCH
18494
18554
| SECOND
18495
18555
| SECURITY
18556
+ | SECURITY_INVOKER
18496
18557
| SECONDARY
18497
18558
| SERIALIZABLE
18498
18559
| SEQUENCE
@@ -19074,6 +19135,7 @@ bare_label_keywords:
19074
19135
| SEARCH
19075
19136
| SECONDARY
19076
19137
| SECURITY
19138
+ | SECURITY_INVOKER
19077
19139
| SELECT
19078
19140
| SEQUENCE
19079
19141
| SEQUENCES
0 commit comments