{"record":{"id":"68fb94b227850cd7","repo":"vitessio/vitess","slug":"should-override","errorCode":null,"errorMessage":"should override","messagePattern":"should override","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/evalengine/expr_call.go","lineNumber":32,"sourceCode":"limitations under the License.\n*/\n\npackage evalengine\n\ntype (\n\tcallable interface {\n\t\tIR\n\t\tcallable() []IR\n\t}\n\n\tCallExpr struct {\n\t\tArguments TupleExpr\n\t\tMethod    string\n\t}\n)\n\nfunc (c *CallExpr) eval(*ExpressionEnv) (eval, error) {\n\tpanic(\"should override\")\n}\n\nfunc (c *CallExpr) compile(*compiler) (ctype, error) {\n\tpanic(\"should override\")\n}\n\nfunc (c *CallExpr) callable() []IR {\n\treturn c.Arguments\n}\n\nfunc (c *CallExpr) args(env *ExpressionEnv) ([]eval, error) {\n\targs := make([]eval, 0, len(c.Arguments))\n\tfor _, arg := range c.Arguments {\n\t\te, err := arg.eval(env)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, e)","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/evalengine/expr_call.go#L14-L50","documentation":"CallExpr is an abstract base expression in the evalengine; its eval method is a placeholder that must be overridden by concrete call types (e.g., function calls, stored-procedure-ish nodes). Panicking here means a CallExpr instance that was not subclassed/rewritten into a concrete callable reached the evaluation stage. It signals the expression tree was built or dispatched incorrectly rather than a user-data problem.","triggerScenarios":"Evaluating an expression tree where a bare *CallExpr (not one of its concrete wrappers) is present and ExpressionEnv evaluation reaches CallExpr.eval. This occurs if the plan compiler/rewriter failed to replace CallExpr with a concrete implementation before execution.","commonSituations":"Vitess development where a new builtin/function kind is parsed but not mapped to its concrete evalengine implementation; tests that construct CallExpr directly; inconsistent builds where rewriting rules were skipped.","solutions":["Inspect the query/plan to see which function produced a bare CallExpr and ensure it maps to a concrete evalengine call type","Add the missing mapping/rewrite so the CallExpr is replaced before evaluation","If constructing expressions in tests, instantiate a concrete subclass instead of CallExpr","Report to Vitess maintainers with the query and plan if no local extension exists"],"exampleFix":"// before\ncall := &evalengine.CallExpr{Method: \"my_fn\"}\nv, err := call.eval(env)\n// after\ncall := evalengine.newBuiltinFunc(\"my_fn\", args) // concrete impl overriding eval\nv, err := call.eval(env)","handlingStrategy":"validation","validationCode":"// Ensure the expression is a concrete call before evaluating\nfunc isConcreteCall(e evalengine.IR) bool {\n\t_, isBare := e.(*evalengine.CallExpr)\n\treturn !isBare\n}","typeGuard":"type concreteCall interface { evalengine.IR; callable() []evalengine.IR }\nfunc asConcreteCall(e evalengine.IR) (concreteCall, bool) {\n\tcc, ok := e.(concreteCall)\n\treturn cc, ok && !isBareCallExpr(e)\n}","tryCatchPattern":"func safeEval(e evalengine.IR, env *evalengine.ExpressionEnv) (v evalengine.eval, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"eval panic: %v\", r)\n\t\t}\n\t}()\n\treturn e.eval(env)\n}","preventionTips":["Never instantiate CallExpr directly; use the translation/builtin-dispatch helpers","Ensure every parsed function has a registered evalengine implementation","Add rewrite validation that rejects unresolved CallExpr before execution","Add tests that evaluate all supported SQL functions"],"tags":["evalengine","panic","abstract-method","function-call"],"backgroundTag":"abstract-method-invoked-panic","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}