Letting plpgsql in on the fun with the new expression eval stuff

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Andres Freund <andres(at)anarazel(dot)de>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Letting plpgsql in on the fun with the new expression eval stuff
Date: 2017-12-19 18:00:41
Message-ID: 32589.1513706441@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

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

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Robert Haas 2017-12-19 18:07:47 Re: explain analyze output with parallel workers - question about meaning of information for explain.depesz.com
Previous Message Peter Eisentraut 2017-12-19 17:31:44 update portal-related memory context names and API