forked from pgpkg/pgpkg
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobject.go
More file actions
210 lines (171 loc) · 6.38 KB
/
object.go
File metadata and controls
210 lines (171 loc) · 6.38 KB
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package pgpkg
import (
"fmt"
pg_query "github.com/pganalyze/pg_query_go/v5"
"strings"
)
// ManagedObject refers to a managed database object, with a schema name,
// object name and object type.
type ManagedObject struct {
ObjectSchema string
ObjectType string
ObjectName string
ObjectArgs []string
}
func getTypeName(name *pg_query.TypeName) string {
typeName := QualifiedName(name.Names)
if name.ArrayBounds != nil {
for range name.ArrayBounds {
typeName = typeName + "[]"
}
}
return typeName
}
func getParamType(fp *pg_query.FunctionParameter) string {
return getTypeName(fp.ArgType)
}
// Convert the identifier to a quoted string. If the string contains ", these are replaced with "".
func quote(v string) string {
return "\"" + strings.Replace(v, "\"", "\"\"", -1) + "\""
}
func (s *Statement) getFunctionObject() (*ManagedObject, error) {
createFunctionStmt := s.Tree.Stmt.GetCreateFunctionStmt()
pkg := s.Unit.Bundle.Package
var args []string
for _, arg := range createFunctionStmt.Parameters {
fp := arg.GetFunctionParameter()
if fp.Mode == pg_query.FunctionParameterMode_FUNC_PARAM_IN ||
fp.Mode == pg_query.FunctionParameterMode_FUNC_PARAM_INOUT ||
fp.Mode == pg_query.FunctionParameterMode_FUNC_PARAM_DEFAULT {
args = append(args, fmt.Sprintf("%s %s", fp.Name, getParamType(fp)))
}
}
schema := AsString(createFunctionStmt.Funcname[0])
if schema == "" {
return nil, PKGErrorf(s, nil, "no function schema declared")
}
if !pkg.isValidSchema(schema) {
return nil, PKGErrorf(s, nil, "function schema %s is not declared in package", schema)
}
return &ManagedObject{
ObjectSchema: schema,
ObjectType: "function",
// note that pg_analyze_go doesn't seem to support quoted argument names in functions. To avoid assumptions
// about future pg_analyze_go future behaviour, we won't support them here either.
ObjectName: fmt.Sprintf("%s.%s(%s)", quote(schema), quote(AsString(createFunctionStmt.Funcname[1])), strings.Join(args, ",")),
ObjectArgs: args,
}, nil
}
func (s *Statement) getCastObject() (*ManagedObject, error) {
createCastStmt := s.Tree.Stmt.GetCreateCastStmt()
return &ManagedObject{
ObjectSchema: "public",
ObjectType: "cast",
ObjectName: getTypeName(createCastStmt.Sourcetype) + " as " + getTypeName(createCastStmt.Targettype),
}, nil
}
func (s *Statement) getTriggerObject() (*ManagedObject, error) {
createTrigStmt := s.Tree.Stmt.GetCreateTrigStmt()
pkg := s.Unit.Bundle.Package
name := createTrigStmt.Trigname
schema := createTrigStmt.Relation.Schemaname
table := createTrigStmt.Relation.Relname
if schema == "" {
return nil, PKGErrorf(s, nil, "no schema declared on trigger table")
}
if !pkg.isValidSchema(schema) {
return nil, PKGErrorf(s, nil, "trigger table schema %s is not declared in package", schema)
}
return &ManagedObject{
ObjectSchema: schema,
ObjectType: "trigger",
ObjectName: fmt.Sprintf("%s on %s.%s", quote(name), quote(schema), quote(table)),
}, nil
}
func (s *Statement) getViewObject() (*ManagedObject, error) {
viewStmt := s.Tree.Stmt.GetViewStmt()
pkg := s.Unit.Bundle.Package
schema := viewStmt.View.Schemaname
name := viewStmt.View.Relname
if schema == "" {
return nil, PKGErrorf(s, nil, "no schema declared on view")
}
if !pkg.isValidSchema(schema) {
return nil, PKGErrorf(s, nil, "view schema %s is not declared in package", schema)
}
return &ManagedObject{
ObjectSchema: schema,
ObjectType: "view",
ObjectName: fmt.Sprintf("%s.%s", quote(schema), quote(name))}, nil
}
func (s *Statement) getCommentObject() (*ManagedObject, error) {
commentStmt := s.Tree.Stmt.GetCommentStmt()
ot := commentStmt.Objtype
switch ot {
case pg_query.ObjectType_OBJECT_FUNCTION:
// WARNING: this does not capture the entire function name, which should include parameters.
// Capturing the whole name with parameters will probably require a minor refactor.
funcObject := commentStmt.Object.GetObjectWithArgs()
return &ManagedObject{
ObjectSchema: AsString(funcObject.Objname[0]),
ObjectType: "comment on function",
ObjectName: fmt.Sprintf("%s.%s", quote(AsString(funcObject.Objname[0])), quote(AsString(funcObject.Objname[1]))),
}, nil
case pg_query.ObjectType_OBJECT_COLUMN:
targetName := commentStmt.GetObject().GetList()
return &ManagedObject{
ObjectSchema: AsString(targetName.Items[0]),
ObjectType: "comment on column",
ObjectName: fmt.Sprintf("%s.%s.%s", quote(AsString(targetName.Items[0])), quote(AsString(targetName.Items[1])), quote(AsString(targetName.Items[2]))),
}, nil
case pg_query.ObjectType_OBJECT_VIEW:
targetName := commentStmt.GetObject().GetList()
return &ManagedObject{
ObjectSchema: AsString(targetName.Items[0]),
ObjectType: "comment on view",
ObjectName: fmt.Sprintf("%s.%s", quote(AsString(targetName.Items[0])), quote(AsString(targetName.Items[1]))),
}, nil
default:
return nil, PKGErrorf(s, nil, "Only comments on views, columns and functions are supported in MOBs")
}
}
// GetManagedObject returns identifying information about an object from a CREATE
// statement, such as function, view or trigger. NOTE: This functon
// might not support all object types, but you can add more as needed.
//
// The result is cached since it's used repeatedly during MOB processing.
func (s *Statement) GetManagedObject() (*ManagedObject, error) {
if s.object != nil {
return s.object, nil
}
stmt := s.Tree.Stmt
var err error
switch {
case stmt.GetCreateFunctionStmt() != nil:
s.object, err = s.getFunctionObject()
case stmt.GetCreateTrigStmt() != nil:
s.object, err = s.getTriggerObject()
case stmt.GetViewStmt() != nil:
s.object, err = s.getViewObject()
case stmt.GetCommentStmt() != nil:
s.object, err = s.getCommentObject()
case stmt.GetCreateCastStmt() != nil:
s.object, err = s.getCastObject()
default:
clip := strings.TrimSpace(strings.Replace(s.Source[:20], "\n", " ", -1))
return nil, fmt.Errorf("%s: unknown statement type: %s", s.Location(), clip)
//fmt.Fprintf(os.Stderr, "WARNING: %s: unknown statement type (in '%s...'); will attempt to execute anyway\n", s.Location(), clip)
//s.object = &ManagedObject{
// ObjectSchema: "unknown",
// ObjectType: "unknown",
// ObjectName: s.Location(),
//}
}
if err != nil {
return nil, err
}
if s.object != nil {
return s.object, nil
}
return nil, PKGErrorf(s, nil, "only functions, triggers, views and comments are supported for managed objects")
}