diff options
author | Robert Haas <rhaas@postgresql.org> | 2015-11-02 18:11:29 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2015-11-02 18:11:29 -0500 |
commit | 1efc7e538204646fec0f790b683012ed9bd8a99f (patch) | |
tree | 713e9f30769f62ac111606a070ce664e524cee18 /src/backend/nodes/params.c | |
parent | bf25fb2f93c95e946c5e382eb82ad08ae9d95bd9 (diff) | |
download | postgresql-1efc7e538204646fec0f790b683012ed9bd8a99f.tar.gz postgresql-1efc7e538204646fec0f790b683012ed9bd8a99f.zip |
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. Repair.
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, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
Diffstat (limited to 'src/backend/nodes/params.c')
-rw-r--r-- | src/backend/nodes/params.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c index d093263589c..03517749212 100644 --- a/src/backend/nodes/params.c +++ b/src/backend/nodes/params.c @@ -15,6 +15,7 @@ #include "postgres.h" +#include "nodes/bitmapset.h" #include "nodes/params.h" #include "storage/shmem.h" #include "utils/datum.h" @@ -50,6 +51,7 @@ copyParamList(ParamListInfo from) retval->parserSetup = NULL; retval->parserSetupArg = NULL; retval->numParams = from->numParams; + retval->paramMask = NULL; for (i = 0; i < from->numParams; i++) { @@ -58,6 +60,17 @@ copyParamList(ParamListInfo from) int16 typLen; bool typByVal; + /* Ignore parameters we don't need, to save cycles and space. */ + if (retval->paramMask != NULL && + !bms_is_member(i, retval->paramMask)) + { + nprm->value = (Datum) 0; + nprm->isnull = true; + nprm->pflags = 0; + nprm->ptype = InvalidOid; + continue; + } + /* give hook a chance in case parameter is dynamic */ if (!OidIsValid(oprm->ptype) && from->paramFetch != NULL) (*from->paramFetch) (from, i + 1); @@ -90,19 +103,28 @@ EstimateParamListSpace(ParamListInfo paramLI) for (i = 0; i < paramLI->numParams; i++) { ParamExternData *prm = ¶mLI->params[i]; + Oid typeOid; int16 typLen; bool typByVal; - /* give hook a chance in case parameter is dynamic */ - if (!OidIsValid(prm->ptype) && paramLI->paramFetch != NULL) - (*paramLI->paramFetch) (paramLI, i + 1); + /* Ignore parameters we don't need, to save cycles and space. */ + if (paramLI->paramMask != NULL && + !bms_is_member(i, paramLI->paramMask)) + typeOid = InvalidOid; + else + { + /* give hook a chance in case parameter is dynamic */ + if (!OidIsValid(prm->ptype) && paramLI->paramFetch != NULL) + (*paramLI->paramFetch) (paramLI, i + 1); + typeOid = prm->ptype; + } sz = add_size(sz, sizeof(Oid)); /* space for type OID */ sz = add_size(sz, sizeof(uint16)); /* space for pflags */ /* space for datum/isnull */ - if (OidIsValid(prm->ptype)) - get_typlenbyval(prm->ptype, &typLen, &typByVal); + if (OidIsValid(typeOid)) + get_typlenbyval(typeOid, &typLen, &typByVal); else { /* If no type OID, assume by-value, like copyParamList does. */ @@ -150,15 +172,24 @@ SerializeParamList(ParamListInfo paramLI, char **start_address) for (i = 0; i < nparams; i++) { ParamExternData *prm = ¶mLI->params[i]; + Oid typeOid; int16 typLen; bool typByVal; - /* give hook a chance in case parameter is dynamic */ - if (!OidIsValid(prm->ptype) && paramLI->paramFetch != NULL) - (*paramLI->paramFetch) (paramLI, i + 1); + /* Ignore parameters we don't need, to save cycles and space. */ + if (paramLI->paramMask != NULL && + !bms_is_member(i, paramLI->paramMask)) + typeOid = InvalidOid; + else + { + /* give hook a chance in case parameter is dynamic */ + if (!OidIsValid(prm->ptype) && paramLI->paramFetch != NULL) + (*paramLI->paramFetch) (paramLI, i + 1); + typeOid = prm->ptype; + } /* Write type OID. */ - memcpy(*start_address, &prm->ptype, sizeof(Oid)); + memcpy(*start_address, &typeOid, sizeof(Oid)); *start_address += sizeof(Oid); /* Write flags. */ @@ -166,8 +197,8 @@ SerializeParamList(ParamListInfo paramLI, char **start_address) *start_address += sizeof(uint16); /* Write datum/isnull. */ - if (OidIsValid(prm->ptype)) - get_typlenbyval(prm->ptype, &typLen, &typByVal); + if (OidIsValid(typeOid)) + get_typlenbyval(typeOid, &typLen, &typByVal); else { /* If no type OID, assume by-value, like copyParamList does. */ @@ -209,6 +240,7 @@ RestoreParamList(char **start_address) paramLI->parserSetup = NULL; paramLI->parserSetupArg = NULL; paramLI->numParams = nparams; + paramLI->paramMask = NULL; for (i = 0; i < nparams; i++) { |