Run a parsed plpgsql body.
The evaluator has two primitives and everything else is control flow:
SELECT <expr> and take one valueBoth go through the handler this function was called from, which is
what SPI is for PostgreSQL: the nested statement sees the same
transaction, the same temporary tables and the same session. That is
also why pl_exec.c is 9,226 lines and this is not -- most of it is
memory contexts, plan caching and TupleDesc conversion, none of which
we have to reproduce.
A variable reaches an embedded statement as a PARAMETER: the
statement's references to it are rewritten to $n and the values are
bound per call. That is how PostgreSQL does it, and it is what makes
the plan cacheable -- resolving a variable to its VALUE during
translation made the plan specific to that value, so every execution
re-translated and a body reading one variable cost 11ms a call
against 0.3ms for one reading none.
Run a parsed plpgsql body. The evaluator has two primitives and everything else is control flow: - evaluate an expression -- run `SELECT <expr>` and take one value - run a statement -- hand the source to the query handler Both go through the handler this function was called from, which is what SPI is for PostgreSQL: the nested statement sees the same transaction, the same temporary tables and the same session. That is also why `pl_exec.c` is 9,226 lines and this is not -- most of it is memory contexts, plan caching and TupleDesc conversion, none of which we have to reproduce. A variable reaches an embedded statement as a PARAMETER: the statement's references to it are rewritten to `$n` and the values are bound per call. That is how PostgreSQL does it, and it is what makes the plan cacheable -- resolving a variable to its VALUE during translation made the plan specific to that value, so every execution re-translated and a body reading one variable cost 11ms a call against 0.3ms for one reading none.
(run-body handler ast args setof? arg-types)Run a parsed plpgsql body with args bound, and return
{:value v} for a scalar function or {:rows [[…] …]} for a
set-returning one.
args is a seq of [name value] and arg-types the declared type of
each by the same name. An unnamed parameter is reachable as $n,
which is bound under that name too.
The types matter: a statement gives its result back as TEXT, so
without them a := a - 1 turned an integer parameter into the
string "3" and the next comparison against it was nonsense.
Run a parsed plpgsql body with `args` bound, and return
`{:value v}` for a scalar function or `{:rows [[…] …]}` for a
set-returning one.
`args` is a seq of [name value] and `arg-types` the declared type of
each by the same name. An unnamed parameter is reachable as `$n`,
which is bound under that name too.
The types matter: a statement gives its result back as TEXT, so
without them `a := a - 1` turned an integer parameter into the
string "3" and the next comparison against it was nonsense.(run-trigger handler ast {:keys [new old tg types]})Run a trigger function's body for one row.
row is {column value} for NEW and OLD, tg the TG_* variables.
The answer is what the body RETURNED: for a BEFORE ROW trigger that
is the row to write, and nil means suppress it. PostgreSQL ignores
the return value of an AFTER trigger, and the caller does too.
A returned record is recognised by identity -- the body says
RETURN NEW, and NEW is bound to a marker the evaluator maps back
to the row -- so RETURN NULL and RETURN NEW are distinguishable
from a value that merely happens to be nil.
Run a trigger function's body for one row.
`row` is `{column value}` for NEW and OLD, `tg` the `TG_*` variables.
The answer is what the body RETURNED: for a BEFORE ROW trigger that
is the row to write, and nil means suppress it. PostgreSQL ignores
the return value of an AFTER trigger, and the caller does too.
A returned record is recognised by identity -- the body says
`RETURN NEW`, and NEW is bound to a marker the evaluator maps back
to the row -- so `RETURN NULL` and `RETURN NEW` are distinguishable
from a value that merely happens to be nil.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |