Files
upstream-sqlc/internal/compiler/find_params.go
upstream-mirror 0f4df23290
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
snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
2026-09-16 02:17:34 +05:00

215 lines
4.5 KiB
Go

package compiler
import (
"fmt"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/astutils"
)
func findParameters(root ast.Node) ([]paramRef, []error) {
refs := make([]paramRef, 0)
errors := make([]error, 0)
v := paramSearch{seen: make(map[int]struct{}), refs: &refs, errs: &errors}
astutils.Walk(v, root)
if len(*v.errs) > 0 {
return refs, *v.errs
} else {
return refs, nil
}
}
type paramRef struct {
parent ast.Node
rv *ast.RangeVar
ref *ast.ParamRef
name string // Named parameter support
}
type paramSearch struct {
parent ast.Node
rangeVar *ast.RangeVar
refs *[]paramRef
seen map[int]struct{}
errs *[]error
// XXX: Gross state hack for limit
limitCount ast.Node
limitOffset ast.Node
}
type limitCount struct {
}
func (l *limitCount) Pos() int {
return 0
}
type limitOffset struct {
}
func (l *limitOffset) Pos() int {
return 0
}
func (p paramSearch) Visit(node ast.Node) astutils.Visitor {
switch n := node.(type) {
case *ast.A_Expr:
p.parent = node
case *ast.BetweenExpr:
p.parent = node
case *ast.CallStmt:
p.parent = n.FuncCall
case *ast.DeleteStmt:
if n.LimitCount != nil {
p.limitCount = n.LimitCount
}
case *ast.FuncCall:
p.parent = node
case *ast.InsertStmt:
if s, ok := n.SelectStmt.(*ast.SelectStmt); ok {
for i, item := range s.TargetList.Items {
target, ok := item.(*ast.ResTarget)
if !ok {
continue
}
ref, ok := target.Val.(*ast.ParamRef)
if !ok {
continue
}
if len(n.Cols.Items) <= i {
*p.errs = append(*p.errs, fmt.Errorf("INSERT has more expressions than target columns"))
return p
}
*p.refs = append(*p.refs, paramRef{parent: n.Cols.Items[i], ref: ref, rv: n.Relation})
p.seen[ref.Location] = struct{}{}
}
for _, item := range s.ValuesLists.Items {
vl, ok := item.(*ast.List)
if !ok {
continue
}
for i, v := range vl.Items {
ref, ok := v.(*ast.ParamRef)
if !ok {
continue
}
if len(n.Cols.Items) <= i {
*p.errs = append(*p.errs, fmt.Errorf("INSERT has more expressions than target columns"))
return p
}
*p.refs = append(*p.refs, paramRef{parent: n.Cols.Items[i], ref: ref, rv: n.Relation})
p.seen[ref.Location] = struct{}{}
}
}
}
case *ast.UpdateStmt:
for _, item := range n.TargetList.Items {
target, ok := item.(*ast.ResTarget)
if !ok {
continue
}
ref, ok := target.Val.(*ast.ParamRef)
if !ok {
continue
}
for _, relation := range n.Relations.Items {
rv, ok := relation.(*ast.RangeVar)
if !ok {
continue
}
*p.refs = append(*p.refs, paramRef{parent: target, ref: ref, rv: rv})
}
p.seen[ref.Location] = struct{}{}
}
if n.LimitCount != nil {
p.limitCount = n.LimitCount
}
case *ast.RangeVar:
p.rangeVar = n
case *ast.ResTarget:
p.parent = node
case *ast.SelectStmt:
if n.LimitCount != nil {
p.limitCount = n.LimitCount
}
if n.LimitOffset != nil {
p.limitOffset = n.LimitOffset
}
case *ast.TypeCast:
p.parent = node
case *ast.ParamRef:
parent := p.parent
if count, ok := p.limitCount.(*ast.ParamRef); ok {
if n.Number == count.Number {
parent = &limitCount{}
}
}
if offset, ok := p.limitOffset.(*ast.ParamRef); ok {
if n.Number == offset.Number {
parent = &limitOffset{}
}
}
if _, found := p.seen[n.Location]; found {
break
}
// Special, terrible case for *ast.MultiAssignRef
set := true
if res, ok := parent.(*ast.ResTarget); ok {
if multi, ok := res.Val.(*ast.MultiAssignRef); ok {
set = false
if row, ok := multi.Source.(*ast.RowExpr); ok {
for i, arg := range row.Args.Items {
if ref, ok := arg.(*ast.ParamRef); ok {
if multi.Colno == i+1 && ref.Number == n.Number {
set = true
}
}
}
}
}
}
if set {
*p.refs = append(*p.refs, paramRef{parent: parent, ref: n, rv: p.rangeVar})
p.seen[n.Location] = struct{}{}
}
return nil
case *ast.In:
if n.Sel == nil {
p.parent = node
} else {
if sel, ok := n.Sel.(*ast.SelectStmt); ok && sel.FromClause != nil && len(sel.FromClause.Items) > 0 {
from := sel.FromClause
if schema, ok := from.Items[0].(*ast.RangeVar); ok && schema != nil {
p.rangeVar = &ast.RangeVar{
Catalogname: schema.Catalogname,
Schemaname: schema.Schemaname,
Relname: schema.Relname,
}
}
}
}
if _, ok := n.Expr.(*ast.ParamRef); ok {
p.Visit(n.Expr)
}
}
return p
}