Skip to content

Commit 468530b

Browse files
committed
Add CREATE/ALTER/DROP LOGIN statement support
Add parsing for: - CREATE LOGIN with PASSWORD, WINDOWS, CERTIFICATE, ASYMMETRIC KEY sources - ALTER LOGIN ENABLE/DISABLE statements - ALTER LOGIN WITH options (PASSWORD, NO CREDENTIAL, etc.) - DROP LOGIN statement Add new AST types: - PasswordCreateLoginSource, WindowsCreateLoginSource - CertificateCreateLoginSource, AsymmetricKeyCreateLoginSource - AlterLoginEnableDisableStatement, AlterLoginOptionsStatement - DropLoginStatement, OnOffPrincipalOption, PrincipalOptionSimple Update PasswordAlterPrincipalOption to support both String and Binary passwords.
1 parent b07e1ae commit 468530b

File tree

5 files changed

+585
-29
lines changed

5 files changed

+585
-29
lines changed

ast/create_simple_statements.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,32 @@ type CreateLoginStatement struct {
3434
func (s *CreateLoginStatement) node() {}
3535
func (s *CreateLoginStatement) statement() {}
3636

37+
// AlterLoginEnableDisableStatement represents ALTER LOGIN name ENABLE/DISABLE
38+
type AlterLoginEnableDisableStatement struct {
39+
Name *Identifier `json:"Name,omitempty"`
40+
IsEnable bool `json:"IsEnable"`
41+
}
42+
43+
func (s *AlterLoginEnableDisableStatement) node() {}
44+
func (s *AlterLoginEnableDisableStatement) statement() {}
45+
46+
// AlterLoginOptionsStatement represents ALTER LOGIN name WITH options
47+
type AlterLoginOptionsStatement struct {
48+
Name *Identifier `json:"Name,omitempty"`
49+
Options []PrincipalOption `json:"Options,omitempty"`
50+
}
51+
52+
func (s *AlterLoginOptionsStatement) node() {}
53+
func (s *AlterLoginOptionsStatement) statement() {}
54+
55+
// DropLoginStatement represents DROP LOGIN name
56+
type DropLoginStatement struct {
57+
Name *Identifier `json:"Name,omitempty"`
58+
}
59+
60+
func (s *DropLoginStatement) node() {}
61+
func (s *DropLoginStatement) statement() {}
62+
3763
// CreateLoginSource is an interface for login sources
3864
type CreateLoginSource interface {
3965
createLoginSource()
@@ -46,6 +72,39 @@ type ExternalCreateLoginSource struct {
4672

4773
func (s *ExternalCreateLoginSource) createLoginSource() {}
4874

75+
// PasswordCreateLoginSource represents WITH PASSWORD = '...' source
76+
type PasswordCreateLoginSource struct {
77+
Password ScalarExpression `json:"Password,omitempty"`
78+
Hashed bool `json:"Hashed"`
79+
MustChange bool `json:"MustChange"`
80+
Options []PrincipalOption `json:"Options,omitempty"`
81+
}
82+
83+
func (s *PasswordCreateLoginSource) createLoginSource() {}
84+
85+
// WindowsCreateLoginSource represents FROM WINDOWS source
86+
type WindowsCreateLoginSource struct {
87+
Options []PrincipalOption `json:"Options,omitempty"`
88+
}
89+
90+
func (s *WindowsCreateLoginSource) createLoginSource() {}
91+
92+
// CertificateCreateLoginSource represents FROM CERTIFICATE source
93+
type CertificateCreateLoginSource struct {
94+
Certificate *Identifier `json:"Certificate,omitempty"`
95+
Credential *Identifier `json:"Credential,omitempty"`
96+
}
97+
98+
func (s *CertificateCreateLoginSource) createLoginSource() {}
99+
100+
// AsymmetricKeyCreateLoginSource represents FROM ASYMMETRIC KEY source
101+
type AsymmetricKeyCreateLoginSource struct {
102+
Key *Identifier `json:"Key,omitempty"`
103+
Credential *Identifier `json:"Credential,omitempty"`
104+
}
105+
106+
func (s *AsymmetricKeyCreateLoginSource) createLoginSource() {}
107+
49108
// PrincipalOption is an interface for principal options (SID, TYPE, etc.)
50109
type PrincipalOption interface {
51110
principalOptionNode()

ast/create_user_statement.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,23 @@ type IdentifierPrincipalOption struct {
3939
func (o *IdentifierPrincipalOption) userOptionNode() {}
4040
func (o *IdentifierPrincipalOption) principalOptionNode() {}
4141

42+
// OnOffPrincipalOption represents an ON/OFF principal option
43+
type OnOffPrincipalOption struct {
44+
OptionKind string
45+
OptionState string // "On" or "Off"
46+
}
47+
48+
func (o *OnOffPrincipalOption) userOptionNode() {}
49+
func (o *OnOffPrincipalOption) principalOptionNode() {}
50+
51+
// PrincipalOptionSimple represents a simple principal option with just an option kind
52+
type PrincipalOptionSimple struct {
53+
OptionKind string
54+
}
55+
56+
func (o *PrincipalOptionSimple) userOptionNode() {}
57+
func (o *PrincipalOptionSimple) principalOptionNode() {}
58+
4259
// DefaultSchemaPrincipalOption represents a default schema option
4360
type DefaultSchemaPrincipalOption struct {
4461
OptionKind string
@@ -47,14 +64,15 @@ type DefaultSchemaPrincipalOption struct {
4764

4865
func (o *DefaultSchemaPrincipalOption) userOptionNode() {}
4966

50-
// PasswordAlterPrincipalOption represents a password option for ALTER USER
67+
// PasswordAlterPrincipalOption represents a password option for ALTER USER/LOGIN
5168
type PasswordAlterPrincipalOption struct {
52-
Password *StringLiteral
69+
Password ScalarExpression
5370
OldPassword *StringLiteral
5471
MustChange bool
5572
Unlock bool
5673
Hashed bool
5774
OptionKind string
5875
}
5976

60-
func (o *PasswordAlterPrincipalOption) userOptionNode() {}
77+
func (o *PasswordAlterPrincipalOption) userOptionNode() {}
78+
func (o *PasswordAlterPrincipalOption) principalOptionNode() {}

parser/marshal.go

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,12 @@ func statementToJSON(stmt ast.Statement) jsonNode {
446446
return dropDatabaseEncryptionKeyStatementToJSON(s)
447447
case *ast.CreateLoginStatement:
448448
return createLoginStatementToJSON(s)
449+
case *ast.AlterLoginEnableDisableStatement:
450+
return alterLoginEnableDisableStatementToJSON(s)
451+
case *ast.AlterLoginOptionsStatement:
452+
return alterLoginOptionsStatementToJSON(s)
453+
case *ast.DropLoginStatement:
454+
return dropLoginStatementToJSON(s)
449455
case *ast.CreateIndexStatement:
450456
return createIndexStatementToJSON(s)
451457
case *ast.CreateSpatialIndexStatement:
@@ -12370,7 +12376,7 @@ func userOptionToJSON(o ast.UserOption) jsonNode {
1237012376
"Hashed": opt.Hashed,
1237112377
}
1237212378
if opt.Password != nil {
12373-
node["Password"] = stringLiteralToJSON(opt.Password)
12379+
node["Password"] = scalarExpressionToJSON(opt.Password)
1237412380
}
1237512381
if opt.OldPassword != nil {
1237612382
node["OldPassword"] = stringLiteralToJSON(opt.OldPassword)
@@ -15555,6 +15561,57 @@ func createLoginSourceToJSON(s ast.CreateLoginSource) jsonNode {
1555515561
node["Options"] = opts
1555615562
}
1555715563
return node
15564+
case *ast.PasswordCreateLoginSource:
15565+
node := jsonNode{
15566+
"$type": "PasswordCreateLoginSource",
15567+
"Hashed": src.Hashed,
15568+
"MustChange": src.MustChange,
15569+
}
15570+
if src.Password != nil {
15571+
node["Password"] = scalarExpressionToJSON(src.Password)
15572+
}
15573+
if len(src.Options) > 0 {
15574+
opts := make([]jsonNode, len(src.Options))
15575+
for i, opt := range src.Options {
15576+
opts[i] = principalOptionToJSON(opt)
15577+
}
15578+
node["Options"] = opts
15579+
}
15580+
return node
15581+
case *ast.WindowsCreateLoginSource:
15582+
node := jsonNode{
15583+
"$type": "WindowsCreateLoginSource",
15584+
}
15585+
if len(src.Options) > 0 {
15586+
opts := make([]jsonNode, len(src.Options))
15587+
for i, opt := range src.Options {
15588+
opts[i] = principalOptionToJSON(opt)
15589+
}
15590+
node["Options"] = opts
15591+
}
15592+
return node
15593+
case *ast.CertificateCreateLoginSource:
15594+
node := jsonNode{
15595+
"$type": "CertificateCreateLoginSource",
15596+
}
15597+
if src.Certificate != nil {
15598+
node["Certificate"] = identifierToJSON(src.Certificate)
15599+
}
15600+
if src.Credential != nil {
15601+
node["Credential"] = identifierToJSON(src.Credential)
15602+
}
15603+
return node
15604+
case *ast.AsymmetricKeyCreateLoginSource:
15605+
node := jsonNode{
15606+
"$type": "AsymmetricKeyCreateLoginSource",
15607+
}
15608+
if src.Key != nil {
15609+
node["Key"] = identifierToJSON(src.Key)
15610+
}
15611+
if src.Credential != nil {
15612+
node["Credential"] = identifierToJSON(src.Credential)
15613+
}
15614+
return node
1555815615
default:
1555915616
return jsonNode{}
1556015617
}
@@ -15580,11 +15637,75 @@ func principalOptionToJSON(o ast.PrincipalOption) jsonNode {
1558015637
node["Identifier"] = identifierToJSON(opt.Identifier)
1558115638
}
1558215639
return node
15640+
case *ast.OnOffPrincipalOption:
15641+
return jsonNode{
15642+
"$type": "OnOffPrincipalOption",
15643+
"OptionKind": opt.OptionKind,
15644+
"OptionState": opt.OptionState,
15645+
}
15646+
case *ast.PrincipalOptionSimple:
15647+
return jsonNode{
15648+
"$type": "PrincipalOption",
15649+
"OptionKind": opt.OptionKind,
15650+
}
15651+
case *ast.PasswordAlterPrincipalOption:
15652+
node := jsonNode{
15653+
"$type": "PasswordAlterPrincipalOption",
15654+
"OptionKind": opt.OptionKind,
15655+
"MustChange": opt.MustChange,
15656+
"Unlock": opt.Unlock,
15657+
"Hashed": opt.Hashed,
15658+
}
15659+
if opt.Password != nil {
15660+
node["Password"] = scalarExpressionToJSON(opt.Password)
15661+
}
15662+
if opt.OldPassword != nil {
15663+
node["OldPassword"] = stringLiteralToJSON(opt.OldPassword)
15664+
}
15665+
return node
1558315666
default:
1558415667
return jsonNode{}
1558515668
}
1558615669
}
1558715670

15671+
func alterLoginEnableDisableStatementToJSON(s *ast.AlterLoginEnableDisableStatement) jsonNode {
15672+
node := jsonNode{
15673+
"$type": "AlterLoginEnableDisableStatement",
15674+
"IsEnable": s.IsEnable,
15675+
}
15676+
if s.Name != nil {
15677+
node["Name"] = identifierToJSON(s.Name)
15678+
}
15679+
return node
15680+
}
15681+
15682+
func alterLoginOptionsStatementToJSON(s *ast.AlterLoginOptionsStatement) jsonNode {
15683+
node := jsonNode{
15684+
"$type": "AlterLoginOptionsStatement",
15685+
}
15686+
if s.Name != nil {
15687+
node["Name"] = identifierToJSON(s.Name)
15688+
}
15689+
if len(s.Options) > 0 {
15690+
opts := make([]jsonNode, len(s.Options))
15691+
for i, opt := range s.Options {
15692+
opts[i] = principalOptionToJSON(opt)
15693+
}
15694+
node["Options"] = opts
15695+
}
15696+
return node
15697+
}
15698+
15699+
func dropLoginStatementToJSON(s *ast.DropLoginStatement) jsonNode {
15700+
node := jsonNode{
15701+
"$type": "DropLoginStatement",
15702+
}
15703+
if s.Name != nil {
15704+
node["Name"] = identifierToJSON(s.Name)
15705+
}
15706+
return node
15707+
}
15708+
1558815709
func createIndexStatementToJSON(s *ast.CreateIndexStatement) jsonNode {
1558915710
node := jsonNode{
1559015711
"$type": "CreateIndexStatement",

0 commit comments

Comments
 (0)