提交 c417d2b0 编写于 作者: J Jesse Zhang and Melanie Plageman 提交者: Melanie

Correctly detoast const datum during translation to array expr

For a PL/pgSQL function like the following:

set optimizer_trace_fallback to on;
CREATE OR REPLACE FUNCTION boom()
RETURNS bool AS $$
DECLARE
	mel bool;
	sesh int[];
BEGIN
	sesh := '{42,1}'::int[]; -- query 1
	select c = ANY (sesh) INTO mel FROM (values (42), (0)) nums(c); -- query 2
	return mel;
END
$$
LANGUAGE plpgsql VOLATILE;

SELECT boom();

With Orca enabled, the database crashes.  Starting in 9.2, PL/pgSQL
supplies bound param values in more statement types to enable planner to
fold constants in more cases. This is in contrast to leaving the param
intact and waiting until execution to substitute it with its values.
Previously, only dynamic execution ("EXECUTE 'SELECT $1' USING sesh")
gets this treatment.  This revealed the bug because Orca would not have
been able to plan queries whose query trees included params that were
not in subplans (external params) and would just fall back.

When query 1 is planned, it is translated into select '{42,1}'::int[];
For uninteresting reasons, the planner-produced plan for query 1 is
considered "simple", and the ORCA-produced plan is considered regular
(not simple). PL/pgSQL has a fast-path for "simple" plans, minimally
starting the executor via `ExecEvalExpr`. Regular plans are executed
through SPI. During execution, SPI will pack (as part of
`heap_form_tuple`) the 4-byte header datum into a 1-byte header datum.

While planning query 2, we will attempt to substitute the param "sesh"
with the actual const value during pre-processing.  Since Orca doesn't
recognize const arrays as arrays, the translator will take the
additional step of translating the const into an array expression.  When
accessing the array-typed const, we need to "unpack"
(`DatumGetArrayTypeP`) the datum.  This commit does that.
Co-authored-by: NMelanie Plageman <mplageman@pivotal.io>
上级 bcf1345c
......@@ -2323,7 +2323,7 @@ transform_array_Const_to_ArrayExpr(Const *c)
if (elemtype == InvalidOid)
return (Expr *) c; /* not an array */
ac = (ArrayType *) c->constvalue;
ac = DatumGetArrayTypeP(c->constvalue);
nelems = ArrayGetNItems(ARR_NDIM(ac), ARR_DIMS(ac));
/* All set, extract the elements, and an ArrayExpr to hold them. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册