Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
174 lines
4.3 KiB
Go
174 lines
4.3 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/sqlc-dev/sqlc/internal/core/catalogdb"
|
|
)
|
|
|
|
type ProcSpec struct {
|
|
Name string
|
|
NamespaceOID int64
|
|
DialectOID int64
|
|
Kind string
|
|
ReturnTypeOID int64
|
|
ReturnSet bool
|
|
ReturnNullable bool
|
|
// NeverNull marks a function whose result is never NULL even when an
|
|
// argument is, in a dialect that otherwise propagates nullability.
|
|
NeverNull bool
|
|
// ReturnTemplate is the result as an expression over the call's
|
|
// arguments, when it depends on their values: Decimal(18, $2) for
|
|
// toDecimal64(x, s).
|
|
ReturnTemplate string
|
|
Strict bool
|
|
VariadicKind string
|
|
Args []ProcArg
|
|
}
|
|
|
|
// The proc table stores nullability as one integer: 0 leaves it to the
|
|
// dialect's rule, 1 is always nullable and 2 is never nullable.
|
|
const (
|
|
nullableDefault int64 = 0
|
|
nullableAlways int64 = 1
|
|
nullableNever int64 = 2
|
|
)
|
|
|
|
type ProcArg struct {
|
|
Name string
|
|
TypeOID int64
|
|
Mode string
|
|
HasDefault bool
|
|
}
|
|
|
|
func (c *Catalog) CreateProc(p ProcSpec) (int64, error) {
|
|
if p.Kind == "" {
|
|
p.Kind = "f"
|
|
}
|
|
if p.VariadicKind == "" {
|
|
p.VariadicKind = "n"
|
|
}
|
|
ctx := context.Background()
|
|
procOID, err := c.q.CreateProc(ctx, catalogdb.CreateProcParams{
|
|
NamespaceOid: nullInt64(p.NamespaceOID),
|
|
DialectOid: nullInt64(p.DialectOID),
|
|
Name: strings.ToLower(p.Name),
|
|
Kind: p.Kind,
|
|
ReturnTypeOid: p.ReturnTypeOID,
|
|
ReturnSet: boolToInt64(p.ReturnSet),
|
|
ReturnNullable: returnNullable(p),
|
|
ReturnTemplate: p.ReturnTemplate,
|
|
Strict: boolToInt64(p.Strict),
|
|
VariadicKind: p.VariadicKind,
|
|
})
|
|
if err != nil {
|
|
return 0, fmt.Errorf("create proc %q: %w", p.Name, err)
|
|
}
|
|
for i, a := range p.Args {
|
|
mode := a.Mode
|
|
if mode == "" {
|
|
mode = "i"
|
|
}
|
|
err := c.q.CreateProcArg(ctx, catalogdb.CreateProcArgParams{
|
|
ProcOid: procOID,
|
|
Ord: int64(i + 1),
|
|
Name: a.Name,
|
|
TypeOid: a.TypeOID,
|
|
Mode: mode,
|
|
HasDefault: boolToInt64(a.HasDefault),
|
|
})
|
|
if err != nil {
|
|
return 0, fmt.Errorf("create proc %q arg %d: %w", p.Name, i+1, err)
|
|
}
|
|
}
|
|
return procOID, nil
|
|
}
|
|
|
|
func returnNullable(p ProcSpec) int64 {
|
|
switch {
|
|
case p.NeverNull:
|
|
return nullableNever
|
|
case p.ReturnNullable:
|
|
return nullableAlways
|
|
}
|
|
return nullableDefault
|
|
}
|
|
|
|
type ProcOverload struct {
|
|
OID int64
|
|
Name string
|
|
Kind string
|
|
ReturnTypeOID int64
|
|
ReturnNullable bool
|
|
NeverNull bool
|
|
ReturnTemplate string
|
|
ArgTypes []int64
|
|
}
|
|
|
|
// FindProcs returns the overloads of name, optionally restricted to the given
|
|
// namespaces.
|
|
func (c *Catalog) FindProcs(name string, namespaceOIDs []int64) ([]ProcOverload, error) {
|
|
ctx := context.Background()
|
|
lname := strings.ToLower(name)
|
|
|
|
var out []ProcOverload
|
|
if len(namespaceOIDs) == 0 {
|
|
rows, err := c.q.FindProcsAnyNamespace(ctx, lname)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("find procs %q: %w", name, err)
|
|
}
|
|
out = make([]ProcOverload, 0, len(rows))
|
|
for _, r := range rows {
|
|
out = append(out, ProcOverload{
|
|
OID: r.Oid,
|
|
Name: r.Name,
|
|
Kind: r.Kind,
|
|
ReturnTypeOID: r.ReturnTypeOid,
|
|
ReturnNullable: r.ReturnNullable == nullableAlways,
|
|
NeverNull: r.ReturnNullable == nullableNever,
|
|
ReturnTemplate: r.ReturnTemplate,
|
|
})
|
|
}
|
|
} else {
|
|
nss := make([]sql.NullInt64, len(namespaceOIDs))
|
|
for i, ns := range namespaceOIDs {
|
|
nss[i] = sql.NullInt64{Int64: ns, Valid: true}
|
|
}
|
|
rows, err := c.q.FindProcsInNamespaces(ctx, catalogdb.FindProcsInNamespacesParams{
|
|
Name: lname,
|
|
NamespaceOids: nss,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("find procs %q: %w", name, err)
|
|
}
|
|
out = make([]ProcOverload, 0, len(rows))
|
|
for _, r := range rows {
|
|
out = append(out, ProcOverload{
|
|
OID: r.Oid,
|
|
Name: r.Name,
|
|
Kind: r.Kind,
|
|
ReturnTypeOID: r.ReturnTypeOid,
|
|
ReturnNullable: r.ReturnNullable == nullableAlways,
|
|
NeverNull: r.ReturnNullable == nullableNever,
|
|
ReturnTemplate: r.ReturnTemplate,
|
|
})
|
|
}
|
|
}
|
|
|
|
for i := range out {
|
|
argTypes, err := c.procArgTypes(out[i].OID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out[i].ArgTypes = argTypes
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (c *Catalog) procArgTypes(procOID int64) ([]int64, error) {
|
|
return c.q.ProcArgTypes(context.Background(), procOID)
|
|
}
|