From: Robert Haas Date: Mon, 12 Oct 2015 15:46:40 +0000 (-0400) Subject: Fix problems with ParamListInfo serialization mechanism. X-Git-Url: http://git.postgresql.org/gitweb/static/maillist.html?a=commitdiff_plain;h=88f1d098644ff69900e2ca62d2695846385d54e9;p=users%2Frhaas%2Fpostgres.git Fix problems with ParamListInfo serialization mechanism. Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism for serializing a ParamListInfo structure to be passed to a parallel worker. However, this mechanism failed to handle external expanded values, as pointed out by Noah Misch. Moreover, plpgsql_param_fetch requires adjustment because the serialization mechanism needs it to skip evaluating unused parameters just as we would do when it is called from copyParamList, but params == estate->paramLI in that case. To fix, do the relevant bms_is_member test unconditionally. --- diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index 3d9e35442d..0d61950455 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -264,6 +264,11 @@ datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen) /* no need to use add_size, can't overflow */ if (typByVal) sz += sizeof(Datum); + else if (VARATT_IS_EXTERNAL_EXPANDED(value)) + { + ExpandedObjectHeader *eoh = DatumGetEOHP(value); + sz += EOH_get_flat_size(eoh); + } else sz += datumGetSize(value, typByVal, typLen); } @@ -292,6 +297,7 @@ void datumSerialize(Datum value, bool isnull, bool typByVal, int typLen, char **start_address) { + ExpandedObjectHeader *eoh = NULL; int header; /* Write header word. */ @@ -299,6 +305,11 @@ datumSerialize(Datum value, bool isnull, bool typByVal, int typLen, header = -2; else if (typByVal) header = -1; + else if (VARATT_IS_EXTERNAL_EXPANDED(value)) + { + eoh = DatumGetEOHP(value); + header = EOH_get_flat_size(eoh); + } else header = datumGetSize(value, typByVal, typLen); memcpy(*start_address, &header, sizeof(int)); @@ -312,6 +323,11 @@ datumSerialize(Datum value, bool isnull, bool typByVal, int typLen, memcpy(*start_address, &value, sizeof(Datum)); *start_address += sizeof(Datum); } + else if (eoh) + { + EOH_flatten_into(eoh, (void *) *start_address, header); + *start_address += header; + } else { memcpy(*start_address, DatumGetPointer(value), header); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index c73f20b725..346e8f851c 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -5696,21 +5696,17 @@ plpgsql_param_fetch(ParamListInfo params, int paramid) /* now we can access the target datum */ datum = estate->datums[dno]; - /* need to behave slightly differently for shared and unshared arrays */ - if (params != estate->paramLI) - { - /* - * We're being called, presumably from copyParamList(), for cursor - * parameters. Since copyParamList() will try to materialize every - * single parameter slot, it's important to do nothing when asked for - * a datum that's not supposed to be used by this SQL expression. - * Otherwise we risk failures in exec_eval_datum(), not to mention - * possibly copying a lot more data than the cursor actually uses. - */ - if (!bms_is_member(dno, expr->paramnos)) - return; - } - else + /* + * Since copyParamList() and SerializeParamList() will try to materialize + * every single parameter slot, it's important to do nothing when asked for + * a datum that's not supposed to be used by this SQL expression. + * Otherwise we risk failures in exec_eval_datum(), not to mention + * possibly copying a lot more data than the cursor actually uses. + */ + if (!bms_is_member(dno, expr->paramnos)) + return; + + if (params == estate->paramLI) { /* * Normal evaluation cases. We don't need to sanity-check dno, but we