-
Notifications
You must be signed in to change notification settings - Fork 0
/
expand.go
84 lines (79 loc) · 2.55 KB
/
expand.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package pgperms
import (
"context"
"strings"
"github.com/Jille/dfr"
"github.com/samber/lo"
)
func expandTables(ctx context.Context, conns *Connections, privs []GenericPrivilege, existingDatabases []string) ([]GenericPrivilege, error) {
return expandTablesOrSequences(ctx, conns, privs, existingDatabases, false)
}
func expandSequences(ctx context.Context, conns *Connections, privs []GenericPrivilege, existingDatabases []string) ([]GenericPrivilege, error) {
return expandTablesOrSequences(ctx, conns, privs, existingDatabases, true)
}
// expandTablesOrSequences resolves all permissions for .* to an actual list of tables.
func expandTablesOrSequences(ctx context.Context, conns *Connections, privs []GenericPrivilege, existingDatabases []string, sequences bool) ([]GenericPrivilege, error) {
var d dfr.D
defer d.Run(nil)
interestingSchemas := map[string]map[string]struct{}{}
for _, p := range privs {
for _, t := range p.untypedTargets() {
if !strings.HasSuffix(t, ".*") {
continue
}
dbname, tgt := splitObjectName(t)
if interestingSchemas[dbname] == nil {
interestingSchemas[dbname] = map[string]struct{}{}
}
interestingSchemas[dbname][strings.TrimSuffix(tgt, ".*")] = struct{}{}
}
}
types := []string{"S"}
if !sequences {
types = []string{"r", "v", "m", "f"}
}
names := map[string]map[string][]string{}
for dbname, schemas := range interestingSchemas {
if !lo.Contains(existingDatabases, dbname) {
continue
}
conn, deref, err := conns.Get(dbname)
if err != nil {
return nil, err
}
derefNow := d.Add(deref)
names[dbname] = map[string][]string{}
rows, err := conn.Query(ctx, "SELECT nspname, relname FROM pg_catalog.pg_class, pg_catalog.pg_namespace WHERE pg_class.relnamespace = pg_namespace.oid AND nspname = ANY($1) AND relkind = ANY($2)", lo.Keys(schemas), types)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var schema, name string
if err := rows.Scan(&schema, &name); err != nil {
return nil, err
}
names[dbname][schema] = append(names[dbname][schema], joinTableName(dbname, schema, name))
}
derefNow(true)
}
for i, p := range privs {
var newTargets []string
for _, t := range p.untypedTargets() {
if !strings.HasSuffix(t, ".*") {
newTargets = append(newTargets, t)
continue
}
dbname, tgt := splitObjectName(t)
schema := strings.TrimSuffix(tgt, ".*")
newTargets = append(newTargets, names[dbname][schema]...)
}
if sequences {
p.Sequences = newTargets
} else {
p.Tables = newTargets
}
privs[i] = p
}
return privs, nil
}