Skip to content

Commit a8a51c6

Browse files
committed
Add CREATE/ALTER USER WITH options parsing support
- Add PasswordAlterPrincipalOption type for ALTER USER WITH PASSWORD/OLD_PASSWORD - Update AlterUserStatement to use UserOptions field - Fix convertUserOptionKind mapping for DEFAULT_SCHEMA and DEFAULT_LANGUAGE - Implement parseAlterUserStatement WITH options parsing - Add JSON marshalling for PasswordAlterPrincipalOption Enables tests: - Baselines110_CreateAlterUserStatementTests110 - CreateAlterUserStatementTests110
1 parent 6bacbdf commit a8a51c6

6 files changed

Lines changed: 110 additions & 12 deletions

File tree

ast/alter_user_statement.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package ast
22

33
// AlterUserStatement represents an ALTER USER statement.
44
type AlterUserStatement struct {
5-
Name *Identifier `json:"Name,omitempty"`
6-
Options []UserOption `json:"Options,omitempty"`
5+
Name *Identifier `json:"Name,omitempty"`
6+
UserOptions []UserOption `json:"UserOptions,omitempty"`
77
}
88

99
func (s *AlterUserStatement) node() {}

ast/create_user_statement.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,15 @@ type DefaultSchemaPrincipalOption struct {
4444
}
4545

4646
func (o *DefaultSchemaPrincipalOption) userOptionNode() {}
47+
48+
// PasswordAlterPrincipalOption represents a password option for ALTER USER
49+
type PasswordAlterPrincipalOption struct {
50+
Password *StringLiteral
51+
OldPassword *StringLiteral
52+
MustChange bool
53+
Unlock bool
54+
Hashed bool
55+
OptionKind string
56+
}
57+
58+
func (o *PasswordAlterPrincipalOption) userOptionNode() {}

parser/marshal.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7178,6 +7178,21 @@ func userOptionToJSON(o ast.UserOption) jsonNode {
71787178
node["Identifier"] = identifierToJSON(opt.Identifier)
71797179
}
71807180
return node
7181+
case *ast.PasswordAlterPrincipalOption:
7182+
node := jsonNode{
7183+
"$type": "PasswordAlterPrincipalOption",
7184+
"OptionKind": opt.OptionKind,
7185+
"MustChange": opt.MustChange,
7186+
"Unlock": opt.Unlock,
7187+
"Hashed": opt.Hashed,
7188+
}
7189+
if opt.Password != nil {
7190+
node["Password"] = stringLiteralToJSON(opt.Password)
7191+
}
7192+
if opt.OldPassword != nil {
7193+
node["OldPassword"] = stringLiteralToJSON(opt.OldPassword)
7194+
}
7195+
return node
71817196
default:
71827197
return jsonNode{"$type": "UnknownUserOption"}
71837198
}
@@ -7689,12 +7704,13 @@ func indexOptionToJSON(opt ast.IndexOption) jsonNode {
76897704
func convertUserOptionKind(name string) string {
76907705
// Convert option names to the expected format
76917706
optionMap := map[string]string{
7692-
"OBJECT_ID": "Object_ID",
7693-
"DEFAULT_SCHEMA": "Default_Schema",
7694-
"SID": "Sid",
7695-
"PASSWORD": "Password",
7696-
"NAME": "Name",
7697-
"LOGIN": "Login",
7707+
"OBJECT_ID": "Object_ID",
7708+
"DEFAULT_SCHEMA": "DefaultSchema",
7709+
"DEFAULT_LANGUAGE": "DefaultLanguage",
7710+
"SID": "Sid",
7711+
"PASSWORD": "Password",
7712+
"NAME": "Name",
7713+
"LOGIN": "Login",
76987714
}
76997715
upper := strings.ToUpper(name)
77007716
if mapped, ok := optionMap[upper]; ok {
@@ -8784,6 +8800,13 @@ func alterUserStatementToJSON(s *ast.AlterUserStatement) jsonNode {
87848800
if s.Name != nil {
87858801
node["Name"] = identifierToJSON(s.Name)
87868802
}
8803+
if len(s.UserOptions) > 0 {
8804+
options := make([]jsonNode, len(s.UserOptions))
8805+
for i, o := range s.UserOptions {
8806+
options[i] = userOptionToJSON(o)
8807+
}
8808+
node["UserOptions"] = options
8809+
}
87878810
return node
87888811
}
87898812

parser/parse_ddl.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3754,8 +3754,71 @@ func (p *Parser) parseAlterUserStatement() (*ast.AlterUserStatement, error) {
37543754
// Parse user name
37553755
stmt.Name = p.parseIdentifier()
37563756

3757-
// Skip rest of statement
3758-
p.skipToEndOfStatement()
3757+
// Parse WITH options
3758+
if p.curTok.Type == TokenWith {
3759+
p.nextToken()
3760+
3761+
for {
3762+
optionName := strings.ToUpper(p.curTok.Literal)
3763+
p.nextToken()
3764+
3765+
// Handle PASSWORD specially for ALTER USER (can have OLD_PASSWORD)
3766+
if optionName == "PASSWORD" {
3767+
if p.curTok.Type == TokenEquals {
3768+
p.nextToken()
3769+
}
3770+
passwordOpt := &ast.PasswordAlterPrincipalOption{
3771+
OptionKind: "Password",
3772+
}
3773+
if p.curTok.Type == TokenString {
3774+
passwordOpt.Password = p.parseStringLiteralValue()
3775+
p.nextToken()
3776+
}
3777+
// Check for OLD_PASSWORD
3778+
if strings.ToUpper(p.curTok.Literal) == "OLD_PASSWORD" {
3779+
p.nextToken() // consume OLD_PASSWORD
3780+
if p.curTok.Type == TokenEquals {
3781+
p.nextToken()
3782+
}
3783+
if p.curTok.Type == TokenString {
3784+
passwordOpt.OldPassword = p.parseStringLiteralValue()
3785+
p.nextToken()
3786+
}
3787+
}
3788+
stmt.UserOptions = append(stmt.UserOptions, passwordOpt)
3789+
} else {
3790+
if p.curTok.Type == TokenEquals {
3791+
p.nextToken()
3792+
}
3793+
3794+
value, err := p.parseScalarExpression()
3795+
if err != nil {
3796+
break
3797+
}
3798+
3799+
// Check if value is a simple identifier
3800+
var opt ast.UserOption
3801+
if colRef, ok := value.(*ast.ColumnReferenceExpression); ok && colRef.MultiPartIdentifier != nil && len(colRef.MultiPartIdentifier.Identifiers) == 1 {
3802+
opt = &ast.IdentifierPrincipalOption{
3803+
OptionKind: convertUserOptionKind(optionName),
3804+
Identifier: colRef.MultiPartIdentifier.Identifiers[0],
3805+
}
3806+
} else {
3807+
opt = &ast.LiteralPrincipalOption{
3808+
OptionKind: convertUserOptionKind(optionName),
3809+
Value: value,
3810+
}
3811+
}
3812+
stmt.UserOptions = append(stmt.UserOptions, opt)
3813+
}
3814+
3815+
if p.curTok.Type == TokenComma {
3816+
p.nextToken()
3817+
} else {
3818+
break
3819+
}
3820+
}
3821+
}
37593822

37603823
return stmt, nil
37613824
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"todo": true}
1+
{}

0 commit comments

Comments
 (0)