Skip to content

Commit

Permalink
Add support for CREATE VIEW with SQL SECURITY DEFINER (#75)
Browse files Browse the repository at this point in the history
toga4 authored Oct 22, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent d6176ec commit 8de04c5
Showing 11 changed files with 288 additions and 18 deletions.
9 changes: 5 additions & 4 deletions ast/ast.go
Original file line number Diff line number Diff line change
@@ -1599,17 +1599,18 @@ type RowDeletionPolicy struct {
// CreateView is CREATE VIEW statement node.
//
// CREATE {{if .OrReplace}}OR REPLACE{{end}} VIEW {{.Name | sql}}
// SQL SECURITY INVOKER AS
// SQL SECURITY {{.SecurityType}} AS
// {{.Query | sql}}
type CreateView struct {
// pos = Create
// end = Query.end

Create token.Pos

Name *Ident
OrReplace bool
Query QueryExpr
Name *Ident
OrReplace bool
SecurityType SecurityType
Query QueryExpr
}

// AlterTable is ALTER TABLE statement node.
7 changes: 7 additions & 0 deletions ast/const.go
Original file line number Diff line number Diff line change
@@ -115,3 +115,10 @@ const (
OnDeleteCascade OnDeleteAction = "ON DELETE CASCADE"
OnDeleteNoAction OnDeleteAction = "ON DELETE NO ACTION"
)

type SecurityType string

const (
SecurityTypeInvoker SecurityType = "INVOKER"
SecurityTypeDefiner SecurityType = "DEFINER"
)
2 changes: 1 addition & 1 deletion ast/sql.go
Original file line number Diff line number Diff line change
@@ -771,7 +771,7 @@ func (c *CreateView) SQL() string {
if c.OrReplace {
sql += " OR REPLACE"
}
sql += " VIEW " + c.Name.SQL() + " SQL SECURITY INVOKER AS " + c.Query.SQL()
sql += " VIEW " + c.Name.SQL() + " SQL SECURITY " + string(c.SecurityType) + " AS " + c.Query.SQL()
return sql
}

22 changes: 17 additions & 5 deletions parser.go
Original file line number Diff line number Diff line change
@@ -2164,16 +2164,28 @@ func (p *Parser) parseCreateView(pos token.Pos) *ast.CreateView {

p.expectKeywordLike("SQL")
p.expectKeywordLike("SECURITY")
p.expectKeywordLike("INVOKER")

id := p.expect(token.TokenIdent)
var securityType ast.SecurityType
switch {
case id.IsIdent("INVOKER"):
securityType = ast.SecurityTypeInvoker
case id.IsIdent("DEFINER"):
securityType = ast.SecurityTypeDefiner
default:
p.panicfAtToken(id, "expected identifier: INVOKER, DEFINER, but: %s", id.Raw)
}

p.expect("AS")

query := p.parseQueryExpr()

return &ast.CreateView{
Create: pos,
Name: name,
OrReplace: orReplace,
Query: query,
Create: pos,
Name: name,
OrReplace: orReplace,
SecurityType: securityType,
Query: query,
}
}

6 changes: 6 additions & 0 deletions testdata/input/ddl/create_view_sql_security_definer.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
create view singernames
sql security definer
as select
singers.singerid as singerid,
singers.firstname || ' ' || singers.lastname as name
from singers
5 changes: 3 additions & 2 deletions testdata/result/ddl/create_or_replace_view.sql.txt
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ from singers
NameEnd: 34,
Name: "singernames",
},
OrReplace: true,
Query: &ast.Select{
OrReplace: true,
SecurityType: "INVOKER",
Query: &ast.Select{
Select: 59,
Distinct: false,
AsStruct: false,
5 changes: 3 additions & 2 deletions testdata/result/ddl/create_view.sql.txt
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ from singers
NameEnd: 23,
Name: "singernames",
},
OrReplace: false,
Query: &ast.Select{
OrReplace: false,
SecurityType: "INVOKER",
Query: &ast.Select{
Select: 48,
Distinct: false,
AsStruct: false,
120 changes: 120 additions & 0 deletions testdata/result/ddl/create_view_sql_security_definer.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
--- create_view_sql_security_definer.sql
create view singernames
sql security definer
as select
singers.singerid as singerid,
singers.firstname || ' ' || singers.lastname as name
from singers

--- AST
&ast.CreateView{
Create: 0,
Name: &ast.Ident{
NamePos: 12,
NameEnd: 23,
Name: "singernames",
},
OrReplace: false,
SecurityType: "DEFINER",
Query: &ast.Select{
Select: 48,
Distinct: false,
AsStruct: false,
Results: []ast.SelectItem{
&ast.Alias{
Expr: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 59,
NameEnd: 66,
Name: "singers",
},
&ast.Ident{
NamePos: 67,
NameEnd: 75,
Name: "singerid",
},
},
},
As: &ast.AsAlias{
As: -1,
Alias: &ast.Ident{
NamePos: 79,
NameEnd: 87,
Name: "singerid",
},
},
},
&ast.Alias{
Expr: &ast.BinaryExpr{
Op: "||",
Left: &ast.BinaryExpr{
Op: "||",
Left: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 93,
NameEnd: 100,
Name: "singers",
},
&ast.Ident{
NamePos: 101,
NameEnd: 110,
Name: "firstname",
},
},
},
Right: &ast.StringLiteral{
ValuePos: 114,
ValueEnd: 117,
Value: " ",
},
},
Right: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 121,
NameEnd: 128,
Name: "singers",
},
&ast.Ident{
NamePos: 129,
NameEnd: 137,
Name: "lastname",
},
},
},
},
As: &ast.AsAlias{
As: -1,
Alias: &ast.Ident{
NamePos: 141,
NameEnd: 145,
Name: "name",
},
},
},
},
From: &ast.From{
From: 146,
Source: &ast.TableName{
Table: &ast.Ident{
NamePos: 151,
NameEnd: 158,
Name: "singers",
},
Hint: (*ast.Hint)(nil),
As: (*ast.AsAlias)(nil),
Sample: (*ast.TableSample)(nil),
},
},
Where: (*ast.Where)(nil),
GroupBy: (*ast.GroupBy)(nil),
Having: (*ast.Having)(nil),
OrderBy: (*ast.OrderBy)(nil),
Limit: (*ast.Limit)(nil),
},
}

--- SQL
CREATE VIEW singernames SQL SECURITY DEFINER AS SELECT singers.singerid AS singerid, singers.firstname || " " || singers.lastname AS name FROM singers
5 changes: 3 additions & 2 deletions testdata/result/statement/create_or_replace_view.sql.txt
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ from singers
NameEnd: 34,
Name: "singernames",
},
OrReplace: true,
Query: &ast.Select{
OrReplace: true,
SecurityType: "INVOKER",
Query: &ast.Select{
Select: 59,
Distinct: false,
AsStruct: false,
5 changes: 3 additions & 2 deletions testdata/result/statement/create_view.sql.txt
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ from singers
NameEnd: 23,
Name: "singernames",
},
OrReplace: false,
Query: &ast.Select{
OrReplace: false,
SecurityType: "INVOKER",
Query: &ast.Select{
Select: 48,
Distinct: false,
AsStruct: false,
120 changes: 120 additions & 0 deletions testdata/result/statement/create_view_sql_security_definer.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
--- create_view_sql_security_definer.sql
create view singernames
sql security definer
as select
singers.singerid as singerid,
singers.firstname || ' ' || singers.lastname as name
from singers

--- AST
&ast.CreateView{
Create: 0,
Name: &ast.Ident{
NamePos: 12,
NameEnd: 23,
Name: "singernames",
},
OrReplace: false,
SecurityType: "DEFINER",
Query: &ast.Select{
Select: 48,
Distinct: false,
AsStruct: false,
Results: []ast.SelectItem{
&ast.Alias{
Expr: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 59,
NameEnd: 66,
Name: "singers",
},
&ast.Ident{
NamePos: 67,
NameEnd: 75,
Name: "singerid",
},
},
},
As: &ast.AsAlias{
As: -1,
Alias: &ast.Ident{
NamePos: 79,
NameEnd: 87,
Name: "singerid",
},
},
},
&ast.Alias{
Expr: &ast.BinaryExpr{
Op: "||",
Left: &ast.BinaryExpr{
Op: "||",
Left: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 93,
NameEnd: 100,
Name: "singers",
},
&ast.Ident{
NamePos: 101,
NameEnd: 110,
Name: "firstname",
},
},
},
Right: &ast.StringLiteral{
ValuePos: 114,
ValueEnd: 117,
Value: " ",
},
},
Right: &ast.Path{
Idents: []*ast.Ident{
&ast.Ident{
NamePos: 121,
NameEnd: 128,
Name: "singers",
},
&ast.Ident{
NamePos: 129,
NameEnd: 137,
Name: "lastname",
},
},
},
},
As: &ast.AsAlias{
As: -1,
Alias: &ast.Ident{
NamePos: 141,
NameEnd: 145,
Name: "name",
},
},
},
},
From: &ast.From{
From: 146,
Source: &ast.TableName{
Table: &ast.Ident{
NamePos: 151,
NameEnd: 158,
Name: "singers",
},
Hint: (*ast.Hint)(nil),
As: (*ast.AsAlias)(nil),
Sample: (*ast.TableSample)(nil),
},
},
Where: (*ast.Where)(nil),
GroupBy: (*ast.GroupBy)(nil),
Having: (*ast.Having)(nil),
OrderBy: (*ast.OrderBy)(nil),
Limit: (*ast.Limit)(nil),
},
}

--- SQL
CREATE VIEW singernames SQL SECURITY DEFINER AS SELECT singers.singerid AS singerid, singers.firstname || " " || singers.lastname AS name FROM singers

0 comments on commit 8de04c5

Please sign in to comment.