Skip to content

Commit 52c0a7f

Browse files
committed
Add comprehensive SERVER AUDIT statement support
- Add DropServerAuditStatement type and parsing - Add MaxSizeAuditTargetOption, MaxRolloverFilesAuditTargetOption, OnOffAuditTargetOption types for proper target option representation - Add MODIFY NAME support for ALTER SERVER AUDIT - Update parseAuditTargetOption to return correct option types - Update marshal.go with JSON conversion for new types
1 parent 032aed6 commit 52c0a7f

6 files changed

Lines changed: 200 additions & 37 deletions

File tree

ast/server_audit_statement.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func (s *CreateServerAuditStatement) node() {}
1414
// AlterServerAuditStatement represents an ALTER SERVER AUDIT statement
1515
type AlterServerAuditStatement struct {
1616
AuditName *Identifier
17+
NewName *Identifier
1718
AuditTarget *AuditTarget
1819
Options []AuditOption
1920
PredicateExpression BooleanExpression
@@ -23,6 +24,15 @@ type AlterServerAuditStatement struct {
2324
func (s *AlterServerAuditStatement) statement() {}
2425
func (s *AlterServerAuditStatement) node() {}
2526

27+
// DropServerAuditStatement represents a DROP SERVER AUDIT statement
28+
type DropServerAuditStatement struct {
29+
Name *Identifier
30+
IsIfExists bool
31+
}
32+
33+
func (s *DropServerAuditStatement) statement() {}
34+
func (s *DropServerAuditStatement) node() {}
35+
2636
// AuditTarget represents the target of a server audit
2737
type AuditTarget struct {
2838
TargetKind string // File, ApplicationLog, SecurityLog
@@ -42,6 +52,33 @@ type LiteralAuditTargetOption struct {
4252

4353
func (o *LiteralAuditTargetOption) auditTargetOption() {}
4454

55+
// MaxSizeAuditTargetOption represents the MAXSIZE option
56+
type MaxSizeAuditTargetOption struct {
57+
OptionKind string
58+
Size ScalarExpression
59+
Unit string // MB, GB, TB, Unspecified
60+
IsUnlimited bool
61+
}
62+
63+
func (o *MaxSizeAuditTargetOption) auditTargetOption() {}
64+
65+
// MaxRolloverFilesAuditTargetOption represents the MAX_ROLLOVER_FILES option
66+
type MaxRolloverFilesAuditTargetOption struct {
67+
OptionKind string
68+
Value ScalarExpression
69+
IsUnlimited bool
70+
}
71+
72+
func (o *MaxRolloverFilesAuditTargetOption) auditTargetOption() {}
73+
74+
// OnOffAuditTargetOption represents an ON/OFF target option
75+
type OnOffAuditTargetOption struct {
76+
OptionKind string
77+
Value string // On, Off
78+
}
79+
80+
func (o *OnOffAuditTargetOption) auditTargetOption() {}
81+
4582
// AuditOption is an interface for audit options
4683
type AuditOption interface {
4784
auditOption()

parser/marshal.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ func statementToJSON(stmt ast.Statement) jsonNode {
176176
return dropSearchPropertyListStatementToJSON(s)
177177
case *ast.DropServerRoleStatement:
178178
return dropServerRoleStatementToJSON(s)
179+
case *ast.DropServerAuditStatement:
180+
return dropServerAuditStatementToJSON(s)
179181
case *ast.DropAvailabilityGroupStatement:
180182
return dropAvailabilityGroupStatementToJSON(s)
181183
case *ast.DropFederationStatement:
@@ -6761,6 +6763,9 @@ func alterServerAuditStatementToJSON(s *ast.AlterServerAuditStatement) jsonNode
67616763
"$type": "AlterServerAuditStatement",
67626764
"RemoveWhere": s.RemoveWhere,
67636765
}
6766+
if s.NewName != nil {
6767+
node["NewName"] = identifierToJSON(s.NewName)
6768+
}
67646769
if s.AuditName != nil {
67656770
node["AuditName"] = identifierToJSON(s.AuditName)
67666771
}
@@ -6780,6 +6785,17 @@ func alterServerAuditStatementToJSON(s *ast.AlterServerAuditStatement) jsonNode
67806785
return node
67816786
}
67826787

6788+
func dropServerAuditStatementToJSON(s *ast.DropServerAuditStatement) jsonNode {
6789+
node := jsonNode{
6790+
"$type": "DropServerAuditStatement",
6791+
"IsIfExists": s.IsIfExists,
6792+
}
6793+
if s.Name != nil {
6794+
node["Name"] = identifierToJSON(s.Name)
6795+
}
6796+
return node
6797+
}
6798+
67836799
func auditTargetToJSON(t *ast.AuditTarget) jsonNode {
67846800
node := jsonNode{
67856801
"$type": "AuditTarget",
@@ -6806,6 +6822,33 @@ func auditTargetOptionToJSON(o ast.AuditTargetOption) jsonNode {
68066822
node["Value"] = scalarExpressionToJSON(opt.Value)
68076823
}
68086824
return node
6825+
case *ast.MaxSizeAuditTargetOption:
6826+
node := jsonNode{
6827+
"$type": "MaxSizeAuditTargetOption",
6828+
"IsUnlimited": opt.IsUnlimited,
6829+
"Unit": opt.Unit,
6830+
"OptionKind": opt.OptionKind,
6831+
}
6832+
if opt.Size != nil {
6833+
node["Size"] = scalarExpressionToJSON(opt.Size)
6834+
}
6835+
return node
6836+
case *ast.MaxRolloverFilesAuditTargetOption:
6837+
node := jsonNode{
6838+
"$type": "MaxRolloverFilesAuditTargetOption",
6839+
"IsUnlimited": opt.IsUnlimited,
6840+
"OptionKind": opt.OptionKind,
6841+
}
6842+
if opt.Value != nil {
6843+
node["Value"] = scalarExpressionToJSON(opt.Value)
6844+
}
6845+
return node
6846+
case *ast.OnOffAuditTargetOption:
6847+
return jsonNode{
6848+
"$type": "OnOffAuditTargetOption",
6849+
"Value": opt.Value,
6850+
"OptionKind": opt.OptionKind,
6851+
}
68096852
default:
68106853
return jsonNode{"$type": "UnknownAuditTargetOption"}
68116854
}

parser/parse_ddl.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -892,25 +892,33 @@ func (p *Parser) parseDropSearchPropertyListStatement() (*ast.DropSearchProperty
892892
return stmt, nil
893893
}
894894

895-
func (p *Parser) parseDropServerRoleStatement() (*ast.DropServerRoleStatement, error) {
895+
func (p *Parser) parseDropServerRoleStatement() (ast.Statement, error) {
896896
// Consume SERVER
897897
p.nextToken()
898898

899-
// Expect ROLE
900-
if strings.ToUpper(p.curTok.Literal) != "ROLE" {
901-
return nil, fmt.Errorf("expected ROLE after SERVER, got %s", p.curTok.Literal)
902-
}
903-
p.nextToken()
904-
905-
stmt := &ast.DropServerRoleStatement{}
906-
stmt.Name = p.parseIdentifier()
907-
908-
// Skip optional semicolon
909-
if p.curTok.Type == TokenSemicolon {
899+
// Check if it's ROLE or AUDIT
900+
switch strings.ToUpper(p.curTok.Literal) {
901+
case "ROLE":
910902
p.nextToken()
903+
stmt := &ast.DropServerRoleStatement{}
904+
stmt.Name = p.parseIdentifier()
905+
// Skip optional semicolon
906+
if p.curTok.Type == TokenSemicolon {
907+
p.nextToken()
908+
}
909+
return stmt, nil
910+
case "AUDIT":
911+
p.nextToken()
912+
stmt := &ast.DropServerAuditStatement{}
913+
stmt.Name = p.parseIdentifier()
914+
// Skip optional semicolon
915+
if p.curTok.Type == TokenSemicolon {
916+
p.nextToken()
917+
}
918+
return stmt, nil
919+
default:
920+
return nil, fmt.Errorf("expected ROLE or AUDIT after SERVER, got %s", p.curTok.Literal)
911921
}
912-
913-
return stmt, nil
914922
}
915923

916924
func (p *Parser) parseDropAvailabilityGroupStatement() (*ast.DropAvailabilityGroupStatement, error) {
@@ -4064,6 +4072,24 @@ func (p *Parser) parseAlterServerAuditStatement() (*ast.AlterServerAuditStatemen
40644072
// Parse audit name
40654073
stmt.AuditName = p.parseIdentifier()
40664074

4075+
// Check for MODIFY NAME
4076+
if strings.ToUpper(p.curTok.Literal) == "MODIFY" {
4077+
p.nextToken() // consume MODIFY
4078+
if strings.ToUpper(p.curTok.Literal) == "NAME" {
4079+
p.nextToken() // consume NAME
4080+
if p.curTok.Type == TokenEquals {
4081+
p.nextToken() // consume =
4082+
}
4083+
stmt.NewName = p.parseIdentifier()
4084+
// Skip optional semicolon
4085+
if p.curTok.Type == TokenSemicolon {
4086+
p.nextToken()
4087+
}
4088+
return stmt, nil
4089+
}
4090+
return nil, fmt.Errorf("expected NAME after MODIFY, got %s", p.curTok.Literal)
4091+
}
4092+
40674093
// Check for REMOVE WHERE
40684094
if strings.ToUpper(p.curTok.Literal) == "REMOVE" {
40694095
p.nextToken() // consume REMOVE

parser/parse_statements.go

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,32 +2605,89 @@ func (p *Parser) parseAuditTargetOption() (ast.AuditTargetOption, error) {
26052605
}
26062606
p.nextToken()
26072607

2608-
// Parse value
2609-
val, err := p.parseScalarExpression()
2610-
if err != nil {
2611-
return nil, err
2612-
}
2613-
2614-
optKind := ""
26152608
switch optName {
2616-
case "FILEPATH":
2617-
optKind = "FilePath"
2618-
case "MAX_FILES":
2619-
optKind = "MaxFiles"
2620-
case "MAX_ROLLOVER_FILES":
2621-
optKind = "MaxRolloverFiles"
26222609
case "MAXSIZE":
2623-
optKind = "MaxSize"
2610+
// Check for UNLIMITED
2611+
if strings.ToUpper(p.curTok.Literal) == "UNLIMITED" {
2612+
p.nextToken()
2613+
return &ast.MaxSizeAuditTargetOption{
2614+
OptionKind: "MaxSize",
2615+
IsUnlimited: true,
2616+
Unit: "Unspecified",
2617+
}, nil
2618+
}
2619+
// Parse size value
2620+
size, err := p.parseScalarExpression()
2621+
if err != nil {
2622+
return nil, err
2623+
}
2624+
// Parse unit (MB, GB, TB)
2625+
unit := "Unspecified"
2626+
unitUpper := strings.ToUpper(p.curTok.Literal)
2627+
if unitUpper == "MB" || unitUpper == "GB" || unitUpper == "TB" {
2628+
unit = unitUpper
2629+
p.nextToken()
2630+
}
2631+
return &ast.MaxSizeAuditTargetOption{
2632+
OptionKind: "MaxSize",
2633+
Size: size,
2634+
Unit: unit,
2635+
IsUnlimited: false,
2636+
}, nil
2637+
2638+
case "MAX_ROLLOVER_FILES":
2639+
// Check for UNLIMITED
2640+
if strings.ToUpper(p.curTok.Literal) == "UNLIMITED" {
2641+
p.nextToken()
2642+
return &ast.MaxRolloverFilesAuditTargetOption{
2643+
OptionKind: "MaxRolloverFiles",
2644+
IsUnlimited: true,
2645+
}, nil
2646+
}
2647+
// Parse value
2648+
val, err := p.parseScalarExpression()
2649+
if err != nil {
2650+
return nil, err
2651+
}
2652+
return &ast.MaxRolloverFilesAuditTargetOption{
2653+
OptionKind: "MaxRolloverFiles",
2654+
Value: val,
2655+
IsUnlimited: false,
2656+
}, nil
2657+
26242658
case "RESERVE_DISK_SPACE":
2625-
optKind = "ReserveDiskSpace"
2659+
// Parse ON/OFF
2660+
value := "Off"
2661+
valUpper := strings.ToUpper(p.curTok.Literal)
2662+
if valUpper == "ON" || p.curTok.Type == TokenOn {
2663+
value = "On"
2664+
}
2665+
p.nextToken()
2666+
return &ast.OnOffAuditTargetOption{
2667+
OptionKind: "ReserveDiskSpace",
2668+
Value: value,
2669+
}, nil
2670+
26262671
default:
2627-
optKind = capitalizeFirst(strings.ToLower(optName))
2672+
// Parse literal value (FILEPATH, etc.)
2673+
val, err := p.parseScalarExpression()
2674+
if err != nil {
2675+
return nil, err
2676+
}
2677+
optKind := ""
2678+
switch optName {
2679+
case "FILEPATH":
2680+
optKind = "FilePath"
2681+
case "MAX_FILES":
2682+
optKind = "MaxFiles"
2683+
default:
2684+
optKind = capitalizeFirst(strings.ToLower(optName))
2685+
}
2686+
return &ast.LiteralAuditTargetOption{
2687+
OptionKind: optKind,
2688+
Value: val,
2689+
}, nil
26282690
}
2629-
2630-
return &ast.LiteralAuditTargetOption{
2631-
OptionKind: optKind,
2632-
Value: val,
2633-
}, nil
26342691
}
26352692

26362693
func (p *Parser) parseAuditOption() (ast.AuditOption, error) {
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)