Skip to content

Commit 3a876eb

Browse files
authored
internal/dinosql: Implement advisory locks (#212)
* internal/dinosql: Implement advisory locks * Support void Postgres type * Add more advisory lock functions
1 parent 4150a80 commit 3a876eb

File tree

6 files changed

+243
-2
lines changed

6 files changed

+243
-2
lines changed

internal/dinosql/gen.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,11 @@ func (r Result) goInnerType(col core.Column) string {
589589
case "inet":
590590
return "net.IP"
591591

592+
case "void":
593+
// A void value always returns NULL. Since there is no built-in NULL
594+
// value into the SQL package, we'll use sql.NullBool
595+
return "sql.NullBool"
596+
592597
case "any":
593598
return "interface{}"
594599

internal/dinosql/parser.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,12 +951,15 @@ type limitOffset struct {
951951
nodeImpl
952952
}
953953

954-
func (p *paramSearch) Visit(node nodes.Node) Visitor {
954+
func (p paramSearch) Visit(node nodes.Node) Visitor {
955955
switch n := node.(type) {
956956

957957
case nodes.A_Expr:
958958
p.parent = node
959959

960+
case nodes.FuncCall:
961+
p.parent = node
962+
960963
case nodes.InsertStmt:
961964
if s, ok := n.SelectStmt.(nodes.SelectStmt); ok {
962965
for i, item := range s.TargetList.Items {
@@ -1044,7 +1047,7 @@ func (p *paramSearch) Visit(node nodes.Node) Visitor {
10441047
}
10451048

10461049
func findParameters(root nodes.Node) []paramRef {
1047-
v := &paramSearch{refs: map[int]paramRef{}}
1050+
v := paramSearch{refs: map[int]paramRef{}}
10481051
Walk(v, root)
10491052
refs := make([]paramRef, 0)
10501053
for _, r := range v.refs {
@@ -1218,6 +1221,45 @@ func resolveCatalogRefs(c core.Catalog, rvs []nodes.RangeVar, args []paramRef) (
12181221
}
12191222
}
12201223

1224+
case nodes.FuncCall:
1225+
fqn, err := catalog.ParseList(n.Funcname)
1226+
if err != nil {
1227+
return nil, err
1228+
}
1229+
fun, err := c.LookupFunctionN(fqn, len(n.Args.Items))
1230+
if err != nil {
1231+
return nil, err
1232+
}
1233+
for i, item := range n.Args.Items {
1234+
pr, ok := item.(nodes.ParamRef)
1235+
if !ok {
1236+
continue
1237+
}
1238+
if pr.Number != ref.ref.Number {
1239+
continue
1240+
}
1241+
if fun.Arguments == nil {
1242+
a = append(a, Parameter{
1243+
Number: ref.ref.Number,
1244+
Column: core.Column{
1245+
Name: fun.Name,
1246+
DataType: "any",
1247+
},
1248+
})
1249+
}
1250+
if i >= len(fun.Arguments) {
1251+
return nil, fmt.Errorf("incorrect number of arguments to %s", fun.Name)
1252+
}
1253+
a = append(a, Parameter{
1254+
Number: ref.ref.Number,
1255+
Column: core.Column{
1256+
Name: fun.Arguments[i].Name,
1257+
DataType: fun.Arguments[i].DataType,
1258+
NotNull: true,
1259+
},
1260+
})
1261+
}
1262+
12211263
case nodes.ResTarget:
12221264
if n.Name == nil {
12231265
return nil, fmt.Errorf("nodes.ResTarget has nil name")

internal/dinosql/query_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,21 @@ func TestQueries(t *testing.T) {
852852
},
853853
},
854854
},
855+
{
856+
"pg_advisory_xact_lock",
857+
`
858+
SELECT pg_advisory_xact_lock($1);
859+
`,
860+
Query{
861+
Columns: []core.Column{
862+
// TODO: NotNull should be false
863+
{Name: "pg_advisory_xact_lock", DataType: "void", NotNull: true},
864+
},
865+
Params: []Parameter{
866+
{1, core.Column{Name: "key", DataType: "bigint", NotNull: true}},
867+
},
868+
},
869+
},
855870
} {
856871
test := tc
857872
t.Run(test.name, func(t *testing.T) {

internal/pg/catalog.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ type Function struct {
129129
Arguments []Argument // not recorded for builtins
130130
ReturnType string
131131
Comment string
132+
Desc string
132133
}
133134

134135
type Argument struct {

internal/pg/functions_admin.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package pg
2+
3+
// Advisory Lock Functions
4+
//
5+
// The functions shown in Table 9.95 manage advisory locks. For details about
6+
// proper use of these functions, see Section 13.3.5.
7+
//
8+
// https://www.postgresql.org/docs/current/functions-admin.html
9+
//
10+
// Table 9.95. Advisory Lock Functions
11+
func advisoryLockFunctions() []Function {
12+
return []Function{
13+
{
14+
Name: "pg_advisory_lock",
15+
Desc: "Obtain exclusive session level advisory lock",
16+
ReturnType: "void",
17+
Arguments: []Argument{
18+
{
19+
Name: "key",
20+
DataType: "bigint",
21+
},
22+
},
23+
},
24+
{
25+
Name: "pg_advisory_lock",
26+
Desc: "Obtain exclusive session level advisory lock",
27+
ReturnType: "void",
28+
Arguments: []Argument{
29+
{
30+
Name: "key1",
31+
DataType: "int",
32+
},
33+
{
34+
Name: "key1",
35+
DataType: "int",
36+
},
37+
},
38+
},
39+
{
40+
Name: "pg_advisory_lock_shared",
41+
Desc: "Obtain shared session level advisory lock",
42+
ReturnType: "void",
43+
Arguments: []Argument{
44+
{
45+
Name: "key",
46+
DataType: "bigint",
47+
},
48+
},
49+
},
50+
{
51+
Name: "pg_advisory_lock_shared",
52+
Desc: "Obtain shared session level advisory lock",
53+
ReturnType: "void",
54+
Arguments: []Argument{
55+
{
56+
Name: "key1",
57+
DataType: "int",
58+
},
59+
{
60+
Name: "key1",
61+
DataType: "int",
62+
},
63+
},
64+
},
65+
{
66+
Name: "pg_advisory_unlock",
67+
Desc: "Release an exclusive session level advisory lock",
68+
ReturnType: "bool",
69+
Arguments: []Argument{
70+
{
71+
Name: "key",
72+
DataType: "bigint",
73+
},
74+
},
75+
},
76+
{
77+
Name: "pg_advisory_unlock",
78+
Desc: "Release an exclusive session level advisory lock",
79+
ReturnType: "bool",
80+
Arguments: []Argument{
81+
{
82+
Name: "key1",
83+
DataType: "int",
84+
},
85+
{
86+
Name: "key1",
87+
DataType: "int",
88+
},
89+
},
90+
},
91+
{
92+
Name: "pg_advisory_unlock_all",
93+
Desc: "Release all session level advisory locks held by the current session",
94+
ReturnType: "void",
95+
},
96+
{
97+
Name: "pg_advisory_unlock_shared",
98+
Desc: "Unlock a shared session level advisory lock",
99+
ReturnType: "bool",
100+
Arguments: []Argument{
101+
{
102+
Name: "key",
103+
DataType: "bigint",
104+
},
105+
},
106+
},
107+
{
108+
Name: "pg_advisory_unlock_shared",
109+
Desc: "Unlock a shared session level advisory lock",
110+
ReturnType: "bool",
111+
Arguments: []Argument{
112+
{
113+
Name: "key1",
114+
DataType: "int",
115+
},
116+
{
117+
Name: "key1",
118+
DataType: "int",
119+
},
120+
},
121+
},
122+
{
123+
Name: "pg_advisory_xact_lock",
124+
Desc: "Obtain exclusive transaction level advisory lock",
125+
ReturnType: "void",
126+
Arguments: []Argument{
127+
{
128+
Name: "key",
129+
DataType: "bigint",
130+
},
131+
},
132+
},
133+
{
134+
Name: "pg_advisory_xact_lock",
135+
Desc: "Obtain exclusive transaction level advisory lock",
136+
ReturnType: "void",
137+
Arguments: []Argument{
138+
{
139+
Name: "key1",
140+
DataType: "int",
141+
},
142+
{
143+
Name: "key1",
144+
DataType: "int",
145+
},
146+
},
147+
},
148+
{
149+
Name: "pg_advisory_xact_lock",
150+
Desc: "Obtain exclusive transaction level advisory lock",
151+
ReturnType: "void",
152+
Arguments: []Argument{
153+
{
154+
Name: "key",
155+
DataType: "bigint",
156+
},
157+
},
158+
},
159+
{
160+
Name: "pg_advisory_xact_lock",
161+
Desc: "Obtain exclusive transaction level advisory lock",
162+
ReturnType: "void",
163+
Arguments: []Argument{
164+
{
165+
Name: "key1",
166+
DataType: "int",
167+
},
168+
{
169+
Name: "key1",
170+
DataType: "int",
171+
},
172+
},
173+
},
174+
}
175+
}

internal/pg/pg_catalog.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ func pgCatalog() Schema {
7676
ReturnType: "bool",
7777
},
7878
}
79+
80+
fs = append(fs, advisoryLockFunctions()...)
81+
7982
s.Funcs = make(map[string][]Function, len(fs))
8083
for _, f := range fs {
8184
s.Funcs[f.Name] = append(s.Funcs[f.Name], f)

0 commit comments

Comments
 (0)