Skip to content

Commit 5cf0e28

Browse files
committed
Add DROP access control statement support in EXPLAIN output
Added proper parsing and EXPLAIN output for: - DROP ROLE - DROP QUOTA - DROP POLICY - DROP ROW POLICY - DROP SETTINGS PROFILE These statements now output their expected EXPLAIN format like "DROP ROLE query" instead of being treated as table drops.
1 parent 21f020a commit 5cf0e28

4 files changed

Lines changed: 80 additions & 18 deletions

File tree

ast/ast.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -468,19 +468,24 @@ func (t *TTLClause) End() token.Position { return t.Position }
468468

469469
// DropQuery represents a DROP statement.
470470
type DropQuery struct {
471-
Position token.Position `json:"-"`
472-
IfExists bool `json:"if_exists,omitempty"`
473-
Database string `json:"database,omitempty"`
474-
Table string `json:"table,omitempty"`
475-
Tables []*TableIdentifier `json:"tables,omitempty"` // For DROP TABLE t1, t2, t3
476-
View string `json:"view,omitempty"`
477-
User string `json:"user,omitempty"`
478-
Function string `json:"function,omitempty"` // For DROP FUNCTION
479-
Dictionary string `json:"-"` // For DROP DICTIONARY (format only, not in AST JSON)
480-
Temporary bool `json:"temporary,omitempty"`
481-
OnCluster string `json:"on_cluster,omitempty"`
482-
DropDatabase bool `json:"drop_database,omitempty"`
483-
Sync bool `json:"sync,omitempty"`
471+
Position token.Position `json:"-"`
472+
IfExists bool `json:"if_exists,omitempty"`
473+
Database string `json:"database,omitempty"`
474+
Table string `json:"table,omitempty"`
475+
Tables []*TableIdentifier `json:"tables,omitempty"` // For DROP TABLE t1, t2, t3
476+
View string `json:"view,omitempty"`
477+
User string `json:"user,omitempty"`
478+
Function string `json:"function,omitempty"` // For DROP FUNCTION
479+
Dictionary string `json:"-"` // For DROP DICTIONARY (format only, not in AST JSON)
480+
Role string `json:"role,omitempty"` // For DROP ROLE
481+
Quota string `json:"quota,omitempty"` // For DROP QUOTA
482+
Policy string `json:"policy,omitempty"` // For DROP POLICY
483+
RowPolicy string `json:"row_policy,omitempty"` // For DROP ROW POLICY
484+
SettingsProfile string `json:"settings_profile,omitempty"` // For DROP SETTINGS PROFILE
485+
Temporary bool `json:"temporary,omitempty"`
486+
OnCluster string `json:"on_cluster,omitempty"`
487+
DropDatabase bool `json:"drop_database,omitempty"`
488+
Sync bool `json:"sync,omitempty"`
484489
}
485490

486491
func (d *DropQuery) Pos() token.Position { return d.Position }

internal/explain/statements.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,36 @@ func explainDropQuery(sb *strings.Builder, n *ast.DropQuery, indent string, dept
415415
return
416416
}
417417

418+
// DROP ROLE
419+
if n.Role != "" {
420+
fmt.Fprintf(sb, "%sDROP ROLE query\n", indent)
421+
return
422+
}
423+
424+
// DROP QUOTA
425+
if n.Quota != "" {
426+
fmt.Fprintf(sb, "%sDROP QUOTA query\n", indent)
427+
return
428+
}
429+
430+
// DROP POLICY
431+
if n.Policy != "" {
432+
fmt.Fprintf(sb, "%sDROP POLICY query\n", indent)
433+
return
434+
}
435+
436+
// DROP ROW POLICY
437+
if n.RowPolicy != "" {
438+
fmt.Fprintf(sb, "%sDROP ROW POLICY query\n", indent)
439+
return
440+
}
441+
442+
// DROP SETTINGS PROFILE
443+
if n.SettingsProfile != "" {
444+
fmt.Fprintf(sb, "%sDROP SETTINGS PROFILE query\n", indent)
445+
return
446+
}
447+
418448
// Handle multiple tables: DROP TABLE t1, t2, t3
419449
if len(n.Tables) > 1 {
420450
fmt.Fprintf(sb, "%sDropQuery (children %d)\n", indent, 1)

parser/parser.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3268,6 +3268,7 @@ func (p *Parser) parseDrop() *ast.DropQuery {
32683268
if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "PROFILE" {
32693269
p.nextToken()
32703270
}
3271+
drop.SettingsProfile = "_pending_"
32713272
default:
32723273
// Handle multi-word DROP types: ROW POLICY, NAMED COLLECTION, DICTIONARY
32733274
if p.currentIs(token.IDENT) {
@@ -3276,8 +3277,26 @@ func (p *Parser) parseDrop() *ast.DropQuery {
32763277
case "DICTIONARY":
32773278
dropDictionary = true
32783279
p.nextToken()
3279-
case "ROW", "NAMED", "POLICY", "QUOTA", "ROLE":
3280-
// Skip the DROP type tokens
3280+
case "ROW":
3281+
// DROP ROW POLICY
3282+
p.nextToken() // skip ROW
3283+
if p.currentIs(token.IDENT) && strings.ToUpper(p.current.Value) == "POLICY" {
3284+
p.nextToken() // skip POLICY
3285+
}
3286+
// Mark as row policy drop - name will be set later
3287+
drop.RowPolicy = "_pending_"
3288+
case "POLICY":
3289+
// DROP POLICY
3290+
p.nextToken()
3291+
drop.Policy = "_pending_"
3292+
case "QUOTA":
3293+
p.nextToken()
3294+
drop.Quota = "_pending_"
3295+
case "ROLE":
3296+
p.nextToken()
3297+
drop.Role = "_pending_"
3298+
case "NAMED":
3299+
// DROP NAMED COLLECTION - skip tokens
32813300
for p.currentIs(token.IDENT) || p.current.Token.IsKeyword() {
32823301
if p.currentIs(token.IF) {
32833302
break // Hit IF EXISTS
@@ -3326,6 +3345,16 @@ func (p *Parser) parseDrop() *ast.DropQuery {
33263345
}
33273346
} else if dropFunction {
33283347
drop.Function = tableName
3348+
} else if drop.Role == "_pending_" {
3349+
drop.Role = tableName
3350+
} else if drop.Quota == "_pending_" {
3351+
drop.Quota = tableName
3352+
} else if drop.Policy == "_pending_" {
3353+
drop.Policy = tableName
3354+
} else if drop.RowPolicy == "_pending_" {
3355+
drop.RowPolicy = tableName
3356+
} else if drop.SettingsProfile == "_pending_" {
3357+
drop.SettingsProfile = tableName
33293358
} else if dropDictionary {
33303359
drop.Dictionary = tableName
33313360
// Also set Table/Tables for backward compatibility with AST JSON

parser/testdata/01702_system_query_log/metadata.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
"stmt60": true,
3838
"stmt68": true,
3939
"stmt69": true,
40-
"stmt74": true,
41-
"stmt8": true,
42-
"stmt86": true
40+
"stmt74": true
4341
}
4442
}

0 commit comments

Comments
 (0)