(call *ast.FuncCall)
| 33 | } |
| 34 | |
| 35 | func (c *Catalog) ResolveFuncCall(call *ast.FuncCall) (*Function, error) { |
| 36 | // Do not validate unknown functions |
| 37 | funs, err := c.ListFuncsByName(call.Func) |
| 38 | if err != nil || len(funs) == 0 { |
| 39 | return nil, sqlerr.FunctionNotFound(call.Func.Name) |
| 40 | } |
| 41 | |
| 42 | // https://www.postgresql.org/docs/current/sql-syntax-calling-funcs.html |
| 43 | var positional []ast.Node |
| 44 | var named []*ast.NamedArgExpr |
| 45 | |
| 46 | if call.Args != nil { |
| 47 | for _, arg := range call.Args.Items { |
| 48 | if narg, ok := arg.(*ast.NamedArgExpr); ok { |
| 49 | named = append(named, narg) |
| 50 | } else { |
| 51 | // The mixed notation combines positional and named notation. |
| 52 | // However, as already mentioned, named arguments cannot precede |
| 53 | // positional arguments. |
| 54 | if len(named) > 0 { |
| 55 | return nil, &sqlerr.Error{ |
| 56 | Code: "", |
| 57 | Message: "positional argument cannot follow named argument", |
| 58 | Location: call.Pos(), |
| 59 | } |
| 60 | } |
| 61 | positional = append(positional, arg) |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | for _, fun := range funs { |
| 67 | args := fun.InArgs() |
| 68 | var defaults int |
| 69 | var variadic bool |
| 70 | known := map[string]struct{}{} |
| 71 | for _, arg := range args { |
| 72 | if arg.HasDefault { |
| 73 | defaults += 1 |
| 74 | } |
| 75 | if arg.Mode == ast.FuncParamVariadic { |
| 76 | variadic = true |
| 77 | defaults += 1 |
| 78 | } |
| 79 | if arg.Name != "" { |
| 80 | known[arg.Name] = struct{}{} |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | if variadic { |
| 85 | if (len(named) + len(positional)) < (len(args) - defaults) { |
| 86 | continue |
| 87 | } |
| 88 | } else { |
| 89 | if (len(named) + len(positional)) > len(args) { |
| 90 | continue |
| 91 | } |
| 92 | if (len(named) + len(positional)) < (len(args) - defaults) { |
no test coverage detected