Skip to content

internal/dinosql: Implement advisory locks #212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/dinosql/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@ func (r Result) goInnerType(col core.Column) string {
case "inet":
return "net.IP"

case "void":
// A void value always returns NULL. Since there is no built-in NULL
// value into the SQL package, we'll use sql.NullBool
return "sql.NullBool"

case "any":
return "interface{}"

Expand Down
46 changes: 44 additions & 2 deletions internal/dinosql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -951,12 +951,15 @@ type limitOffset struct {
nodeImpl
}

func (p *paramSearch) Visit(node nodes.Node) Visitor {
func (p paramSearch) Visit(node nodes.Node) Visitor {
switch n := node.(type) {

case nodes.A_Expr:
p.parent = node

case nodes.FuncCall:
p.parent = node

case nodes.InsertStmt:
if s, ok := n.SelectStmt.(nodes.SelectStmt); ok {
for i, item := range s.TargetList.Items {
Expand Down Expand Up @@ -1044,7 +1047,7 @@ func (p *paramSearch) Visit(node nodes.Node) Visitor {
}

func findParameters(root nodes.Node) []paramRef {
v := &paramSearch{refs: map[int]paramRef{}}
v := paramSearch{refs: map[int]paramRef{}}
Walk(v, root)
refs := make([]paramRef, 0)
for _, r := range v.refs {
Expand Down Expand Up @@ -1218,6 +1221,45 @@ func resolveCatalogRefs(c core.Catalog, rvs []nodes.RangeVar, args []paramRef) (
}
}

case nodes.FuncCall:
fqn, err := catalog.ParseList(n.Funcname)
if err != nil {
return nil, err
}
fun, err := c.LookupFunctionN(fqn, len(n.Args.Items))
if err != nil {
return nil, err
}
for i, item := range n.Args.Items {
pr, ok := item.(nodes.ParamRef)
if !ok {
continue
}
if pr.Number != ref.ref.Number {
continue
}
if fun.Arguments == nil {
a = append(a, Parameter{
Number: ref.ref.Number,
Column: core.Column{
Name: fun.Name,
DataType: "any",
},
})
}
if i >= len(fun.Arguments) {
return nil, fmt.Errorf("incorrect number of arguments to %s", fun.Name)
}
a = append(a, Parameter{
Number: ref.ref.Number,
Column: core.Column{
Name: fun.Arguments[i].Name,
DataType: fun.Arguments[i].DataType,
NotNull: true,
},
})
}

case nodes.ResTarget:
if n.Name == nil {
return nil, fmt.Errorf("nodes.ResTarget has nil name")
Expand Down
15 changes: 15 additions & 0 deletions internal/dinosql/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,21 @@ func TestQueries(t *testing.T) {
},
},
},
{
"pg_advisory_xact_lock",
`
SELECT pg_advisory_xact_lock($1);
`,
Query{
Columns: []core.Column{
// TODO: NotNull should be false
{Name: "pg_advisory_xact_lock", DataType: "void", NotNull: true},
},
Params: []Parameter{
{1, core.Column{Name: "key", DataType: "bigint", NotNull: true}},
},
},
},
} {
test := tc
t.Run(test.name, func(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions internal/pg/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ type Function struct {
Arguments []Argument // not recorded for builtins
ReturnType string
Comment string
Desc string
}

type Argument struct {
Expand Down
175 changes: 175 additions & 0 deletions internal/pg/functions_admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package pg

// Advisory Lock Functions
//
// The functions shown in Table 9.95 manage advisory locks. For details about
// proper use of these functions, see Section 13.3.5.
//
// https://www.postgresql.org/docs/current/functions-admin.html
//
// Table 9.95. Advisory Lock Functions
func advisoryLockFunctions() []Function {
return []Function{
{
Name: "pg_advisory_lock",
Desc: "Obtain exclusive session level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_lock",
Desc: "Obtain exclusive session level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
{
Name: "pg_advisory_lock_shared",
Desc: "Obtain shared session level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_lock_shared",
Desc: "Obtain shared session level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
{
Name: "pg_advisory_unlock",
Desc: "Release an exclusive session level advisory lock",
ReturnType: "bool",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_unlock",
Desc: "Release an exclusive session level advisory lock",
ReturnType: "bool",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
{
Name: "pg_advisory_unlock_all",
Desc: "Release all session level advisory locks held by the current session",
ReturnType: "void",
},
{
Name: "pg_advisory_unlock_shared",
Desc: "Unlock a shared session level advisory lock",
ReturnType: "bool",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_unlock_shared",
Desc: "Unlock a shared session level advisory lock",
ReturnType: "bool",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
{
Name: "pg_advisory_xact_lock",
Desc: "Obtain exclusive transaction level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_xact_lock",
Desc: "Obtain exclusive transaction level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
{
Name: "pg_advisory_xact_lock",
Desc: "Obtain exclusive transaction level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key",
DataType: "bigint",
},
},
},
{
Name: "pg_advisory_xact_lock",
Desc: "Obtain exclusive transaction level advisory lock",
ReturnType: "void",
Arguments: []Argument{
{
Name: "key1",
DataType: "int",
},
{
Name: "key1",
DataType: "int",
},
},
},
}
}
3 changes: 3 additions & 0 deletions internal/pg/pg_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ func pgCatalog() Schema {
ReturnType: "bool",
},
}

fs = append(fs, advisoryLockFunctions()...)

s.Funcs = make(map[string][]Function, len(fs))
for _, f := range fs {
s.Funcs[f.Name] = append(s.Funcs[f.Name], f)
Expand Down