I'm looking at ways to get plpgsql expression evaluation to go faster, and one thing I'm noticing is the rather large overhead of going through ExecEvalParamExtern and plpgsql_param_fetch to get to the useful work (exec_eval_datum). We've ameliorated that for DTYPE_VAR variables by keeping a pre-set-up copy of their values in a ParamListInfo struct, but that's pretty ugly and carries a bunch of costs of its own.
What I'm wondering about, given the v10 redesign of expression evaluation, is whether we couldn't be smarter about this by allowing plpgsql (or other external users) to skip the ParamListInfo representation altogether, and instead compile Param references into calls to evaluation functions that are better tailored to the problem of fetching the desired value. In the existing execution infrastructure, what seems to make sense is to have an ExprEvalStep type that has functionality like EEOP_PARAM_EXTERN, but includes a function pointer to a plpgsql-supplied function having the same signature as ExecEvalParamExtern. So the execution would look more or less like EEO_CASE(EEOP_PARAM_CALLBACK) { op->eval_param(state, op, econtext); EEO_NEXT(); } and there'd need to be some extra fields (at least a void*) in the op struct where plpgsql could keep private data. The JIT stuff you're working on could just compile an equivalent of the above, although in the very long term maybe there would be some advantage to letting add-on modules compile specialized code for such steps. The immediate problem is how can ExecInitExpr generate such a step? It can't itself know what to put into the function ptr or the additional fields. There has to be a way for it to call a plpgsql-supplied support routine that can construct the eval step. (And we have to export ExprEvalPushStep, though that doesn't seem like a problem.) For compiling full-fledged query trees, what I think we could do is add a method (function pointer) to ParamListInfo and have ExecInitExpr invoke plan->state->es_param_list_info->compile_param if that's set. However, that solution doesn't immediately work for compiling simple expressions because we pass a null "parent" pointer when building those. I thought about instantiating a dummy PlanState and EState to use just for carrying this info, but that seems pretty ugly. Another way we could do it is to invent ExecInitExprWithParams() that takes an additional ParamListInfo pointer, and use that. Rather than adding yet one more parameter that has to be passed down through ExecInitExprRec, I suggest that we could waste a bit of space in struct ExprState and store that value there. Maybe do the same with the parent pointer so as to reduce the number of recursive parameters. I've not written any code around this idea yet, and am not sure if it conflicts with what you're trying to do for JIT or further out. Comments, better ideas? regards, tom lane