Eval implements the interface sql.Expression.
(ctx *sql.Context, row sql.Row)
| 297 | |
| 298 | // Eval implements the interface sql.Expression. |
| 299 | func (c *CompiledFunction) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { |
| 300 | // If we have a stashed error, then we should return that now. Errors are stashed when they're supposed to be |
| 301 | // returned during the call to Eval. This helps to ensure consistency with how errors are returned in Postgres. |
| 302 | if c.stashedErr != nil { |
| 303 | return nil, c.stashedErr |
| 304 | } |
| 305 | |
| 306 | // Evaluate all arguments, returning immediately if we encounter a null argument and the function is marked STRICT |
| 307 | var err error |
| 308 | isStrict := c.overload.Function().IsStrict() |
| 309 | args := make([]any, len(c.Arguments)) |
| 310 | exprTypes := make([]*pgtypes.DoltgresType, len(args)) |
| 311 | for i, arg := range c.Arguments { |
| 312 | args[i], err = arg.Eval(ctx, row) |
| 313 | if err != nil { |
| 314 | return nil, err |
| 315 | } |
| 316 | var ok bool |
| 317 | if exprTypes[i], ok = arg.Type(ctx).(*pgtypes.DoltgresType); !ok { |
| 318 | dt, err := pgtypes.FromGmsTypeToDoltgresType(arg.Type(ctx)) |
| 319 | if err != nil { |
| 320 | return nil, err |
| 321 | } |
| 322 | args[i], _, _ = dt.Convert(ctx, args[i]) |
| 323 | exprTypes[i] = dt |
| 324 | } |
| 325 | if args[i] == nil && isStrict { |
| 326 | return nil, nil |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | if len(c.overload.casts) > 0 { |
| 331 | targetParamTypes := c.overload.params.paramTypes |
| 332 | for i, arg := range args { |
| 333 | // For variadic params, we need to identify the corresponding target type |
| 334 | var targetType *pgtypes.DoltgresType |
| 335 | isVariadicArg := c.overload.params.variadic >= 0 && i >= len(c.overload.params.paramTypes)-1 |
| 336 | if isVariadicArg { |
| 337 | targetType = targetParamTypes[c.overload.params.variadic] |
| 338 | if !targetType.IsArrayType() { |
| 339 | // should be impossible, we check this at function compile time |
| 340 | return nil, cerrors.Errorf("variadic arguments must be array types, was %T", targetType) |
| 341 | } |
| 342 | targetType = targetType.ArrayBaseType() |
| 343 | } else { |
| 344 | targetType = targetParamTypes[i] |
| 345 | // When the declared parameter type is anyarray, the implicit cast from an |
| 346 | // unknown/text argument (via UseInOut) would target anyarray.IoInput which |
| 347 | // cannot be loaded as a QuickFunction. Resolve to the concrete array type |
| 348 | // (e.g. _aggtype) so the cast uses the real element-type I/O path instead. |
| 349 | // TODO: If targetType.ID can be resolved to the concrete type earlier in |
| 350 | // processing, then we don't need this check here anymore. |
| 351 | if targetType.ID == pgtypes.AnyArray.ID { |
| 352 | targetType = c.resolvePolymorphicReturnType(targetParamTypes, exprTypes, targetType) |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | if c.overload.casts[i].ID.IsValid() { |
no test coverage detected