Skip to content

Commit e4d8294

Browse files
committed
Add ApplicationRoleOption support and enable 2 tests
- Add ApplicationRoleOption type with OptionKind and Value fields - Parse CREATE APPLICATION ROLE ... WITH PASSWORD/DEFAULT_SCHEMA/NAME/LOGIN - Parse ALTER APPLICATION ROLE ... WITH options - Strip quotes from password string literal values Enable tests: - ApplicationRoleStatementTests - Baselines90_ApplicationRoleStatementTests
1 parent 987dad7 commit e4d8294

7 files changed

Lines changed: 140 additions & 8 deletions

File tree

ast/alter_simple_statements.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ func (s *AlterCertificateStatement) statement() {}
4848

4949
// AlterApplicationRoleStatement represents an ALTER APPLICATION ROLE statement.
5050
type AlterApplicationRoleStatement struct {
51-
Name *Identifier `json:"Name,omitempty"`
51+
Name *Identifier `json:"Name,omitempty"`
52+
ApplicationRoleOptions []*ApplicationRoleOption `json:"ApplicationRoleOptions,omitempty"`
5253
}
5354

5455
func (s *AlterApplicationRoleStatement) node() {}

ast/create_simple_statements.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,21 @@ func (s *CreateRemoteServiceBindingStatement) statement() {}
101101

102102
// CreateApplicationRoleStatement represents a CREATE APPLICATION ROLE statement.
103103
type CreateApplicationRoleStatement struct {
104-
Name *Identifier `json:"Name,omitempty"`
104+
Name *Identifier `json:"Name,omitempty"`
105+
ApplicationRoleOptions []*ApplicationRoleOption `json:"ApplicationRoleOptions,omitempty"`
105106
}
106107

107108
func (s *CreateApplicationRoleStatement) node() {}
108109
func (s *CreateApplicationRoleStatement) statement() {}
109110

111+
// ApplicationRoleOption represents an option in CREATE/ALTER APPLICATION ROLE
112+
type ApplicationRoleOption struct {
113+
OptionKind string `json:"OptionKind,omitempty"`
114+
Value *IdentifierOrValueExpression `json:"Value,omitempty"`
115+
}
116+
117+
func (o *ApplicationRoleOption) node() {}
118+
110119
// CreateFulltextCatalogStatement represents a CREATE FULLTEXT CATALOG statement.
111120
type CreateFulltextCatalogStatement struct {
112121
Name *Identifier `json:"Name,omitempty"`

parser/marshal.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5912,6 +5912,13 @@ func alterApplicationRoleStatementToJSON(s *ast.AlterApplicationRoleStatement) j
59125912
if s.Name != nil {
59135913
node["Name"] = identifierToJSON(s.Name)
59145914
}
5915+
if len(s.ApplicationRoleOptions) > 0 {
5916+
opts := make([]jsonNode, len(s.ApplicationRoleOptions))
5917+
for i, opt := range s.ApplicationRoleOptions {
5918+
opts[i] = applicationRoleOptionToJSON(opt)
5919+
}
5920+
node["ApplicationRoleOptions"] = opts
5921+
}
59155922
return node
59165923
}
59175924

@@ -6188,6 +6195,24 @@ func createApplicationRoleStatementToJSON(s *ast.CreateApplicationRoleStatement)
61886195
if s.Name != nil {
61896196
node["Name"] = identifierToJSON(s.Name)
61906197
}
6198+
if len(s.ApplicationRoleOptions) > 0 {
6199+
opts := make([]jsonNode, len(s.ApplicationRoleOptions))
6200+
for i, opt := range s.ApplicationRoleOptions {
6201+
opts[i] = applicationRoleOptionToJSON(opt)
6202+
}
6203+
node["ApplicationRoleOptions"] = opts
6204+
}
6205+
return node
6206+
}
6207+
6208+
func applicationRoleOptionToJSON(opt *ast.ApplicationRoleOption) jsonNode {
6209+
node := jsonNode{
6210+
"$type": "ApplicationRoleOption",
6211+
"OptionKind": opt.OptionKind,
6212+
}
6213+
if opt.Value != nil {
6214+
node["Value"] = identifierOrValueExpressionToJSON(opt.Value)
6215+
}
61916216
return node
61926217
}
61936218

parser/parse_ddl.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3334,8 +3334,20 @@ func (p *Parser) parseAlterApplicationRoleStatement() (*ast.AlterApplicationRole
33343334
// Parse role name
33353335
stmt.Name = p.parseIdentifier()
33363336

3337-
// Skip rest of statement
3338-
p.skipToEndOfStatement()
3337+
// Optional WITH clause
3338+
if p.curTok.Type == TokenWith {
3339+
p.nextToken()
3340+
opts, err := p.parseApplicationRoleOptions()
3341+
if err != nil {
3342+
return nil, err
3343+
}
3344+
stmt.ApplicationRoleOptions = opts
3345+
}
3346+
3347+
// Skip optional semicolon
3348+
if p.curTok.Type == TokenSemicolon {
3349+
p.nextToken()
3350+
}
33393351

33403352
return stmt, nil
33413353
}

parser/parse_statements.go

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4742,11 +4742,96 @@ func (p *Parser) parseCreateApplicationRoleStatement() (*ast.CreateApplicationRo
47424742
Name: p.parseIdentifier(),
47434743
}
47444744

4745-
// Skip rest of statement
4746-
p.skipToEndOfStatement()
4745+
// Optional WITH clause
4746+
if p.curTok.Type == TokenWith {
4747+
p.nextToken()
4748+
opts, err := p.parseApplicationRoleOptions()
4749+
if err != nil {
4750+
return nil, err
4751+
}
4752+
stmt.ApplicationRoleOptions = opts
4753+
}
4754+
4755+
// Skip optional semicolon
4756+
if p.curTok.Type == TokenSemicolon {
4757+
p.nextToken()
4758+
}
4759+
47474760
return stmt, nil
47484761
}
47494762

4763+
func (p *Parser) parseApplicationRoleOptions() ([]*ast.ApplicationRoleOption, error) {
4764+
var options []*ast.ApplicationRoleOption
4765+
4766+
for {
4767+
optionName := strings.ToUpper(p.curTok.Literal)
4768+
p.nextToken()
4769+
4770+
// Expect =
4771+
if p.curTok.Type != TokenEquals {
4772+
return nil, fmt.Errorf("expected = after %s, got %s", optionName, p.curTok.Literal)
4773+
}
4774+
p.nextToken()
4775+
4776+
opt := &ast.ApplicationRoleOption{}
4777+
4778+
switch optionName {
4779+
case "PASSWORD":
4780+
opt.OptionKind = "Password"
4781+
// Parse string literal
4782+
if p.curTok.Type == TokenString {
4783+
val := p.curTok.Literal
4784+
// Strip quotes from string literal
4785+
if len(val) >= 2 && (val[0] == '\'' && val[len(val)-1] == '\'') {
4786+
val = val[1 : len(val)-1]
4787+
}
4788+
opt.Value = &ast.IdentifierOrValueExpression{
4789+
Value: val,
4790+
ValueExpression: &ast.StringLiteral{
4791+
Value: val,
4792+
LiteralType: "String",
4793+
},
4794+
}
4795+
p.nextToken()
4796+
}
4797+
case "DEFAULT_SCHEMA":
4798+
opt.OptionKind = "DefaultSchema"
4799+
// Parse identifier
4800+
id := p.parseIdentifier()
4801+
opt.Value = &ast.IdentifierOrValueExpression{
4802+
Value: id.Value,
4803+
Identifier: id,
4804+
}
4805+
case "NAME":
4806+
opt.OptionKind = "Name"
4807+
id := p.parseIdentifier()
4808+
opt.Value = &ast.IdentifierOrValueExpression{
4809+
Value: id.Value,
4810+
Identifier: id,
4811+
}
4812+
case "LOGIN":
4813+
opt.OptionKind = "Login"
4814+
id := p.parseIdentifier()
4815+
opt.Value = &ast.IdentifierOrValueExpression{
4816+
Value: id.Value,
4817+
Identifier: id,
4818+
}
4819+
default:
4820+
// Unknown option, skip
4821+
p.nextToken()
4822+
}
4823+
4824+
options = append(options, opt)
4825+
4826+
if p.curTok.Type != TokenComma {
4827+
break
4828+
}
4829+
p.nextToken() // consume comma
4830+
}
4831+
4832+
return options, nil
4833+
}
4834+
47504835
func (p *Parser) parseCreateFulltextStatement() (ast.Statement, error) {
47514836
p.nextToken() // consume FULLTEXT
47524837

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"skip": true}
1+
{"skip": false}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"skip": true}
1+
{"skip": false}

0 commit comments

Comments
 (0)