|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* params.c
|
|
|
|
* Support for finding the values associated with Param nodes.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/nodes/params.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
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.
10 years ago
|
|
|
#include "nodes/bitmapset.h"
|
|
|
|
#include "nodes/params.h"
|
|
|
|
#include "storage/shmem.h"
|
|
|
|
#include "utils/datum.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a ParamListInfo structure.
|
|
|
|
*
|
|
|
|
* The result is allocated in CurrentMemoryContext.
|
|
|
|
*
|
|
|
|
* Note: the intent of this function is to make a static, self-contained
|
|
|
|
* set of parameter values. If dynamic parameter hooks are present, we
|
|
|
|
* intentionally do not copy them into the result. Rather, we forcibly
|
|
|
|
* instantiate all available parameter values and copy the datum values.
|
|
|
|
*/
|
|
|
|
ParamListInfo
|
|
|
|
copyParamList(ParamListInfo from)
|
|
|
|
{
|
|
|
|
ParamListInfo retval;
|
|
|
|
Size size;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (from == NULL || from->numParams <= 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
size = offsetof(ParamListInfoData, params) +
|
|
|
|
from->numParams * sizeof(ParamExternData);
|
|
|
|
|
|
|
|
retval = (ParamListInfo) palloc(size);
|
|
|
|
retval->paramFetch = NULL;
|
|
|
|
retval->paramFetchArg = NULL;
|
|
|
|
retval->parserSetup = NULL;
|
|
|
|
retval->parserSetupArg = NULL;
|
|
|
|
retval->numParams = from->numParams;
|
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.
10 years ago
|
|
|
retval->paramMask = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < from->numParams; i++)
|
|
|
|
{
|
|
|
|
ParamExternData *oprm = &from->params[i];
|
|
|
|
ParamExternData *nprm = &retval->params[i];
|
|
|
|
int16 typLen;
|
|
|
|
bool typByVal;
|
|
|
|
|
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.
10 years ago
|
|
|
/* Ignore parameters we don't need, to save cycles and space. */
|
|
|
|
if (from->paramMask != NULL &&
|
|
|
|
!bms_is_member(i, from->paramMask))
|
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.
10 years ago
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* flat-copy the parameter info */
|
|
|
|
*nprm = *oprm;
|
|
|
|
|
|
|
|
/* need datumCopy in case it's a pass-by-reference datatype */
|
|
|
|
if (nprm->isnull || !OidIsValid(nprm->ptype))
|
|
|
|
continue;
|
|
|
|
get_typlenbyval(nprm->ptype, &typLen, &typByVal);
|
|
|
|
nprm->value = datumCopy(nprm->value, typByVal, typLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Estimate the amount of space required to serialize a ParamListInfo.
|
|
|
|
*/
|
|
|
|
Size
|
|
|
|
EstimateParamListSpace(ParamListInfo paramLI)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Size sz = sizeof(int);
|
|
|
|
|
|
|
|
if (paramLI == NULL || paramLI->numParams <= 0)
|
|
|
|
return sz;
|
|
|
|
|
|
|
|
for (i = 0; i < paramLI->numParams; i++)
|
|
|
|
{
|
|
|
|
ParamExternData *prm = ¶mLI->params[i];
|
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.
10 years ago
|
|
|
Oid typeOid;
|
|
|
|
int16 typLen;
|
|
|
|
bool typByVal;
|
|
|
|
|
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.
10 years ago
|
|
|
/* 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 */
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
8 years ago
|
|
|
sz = add_size(sz, sizeof(uint16)); /* space for pflags */
|
|
|
|
|
|
|
|
/* space for datum/isnull */
|
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.
10 years ago
|
|
|
if (OidIsValid(typeOid))
|
|
|
|
get_typlenbyval(typeOid, &typLen, &typByVal);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If no type OID, assume by-value, like copyParamList does. */
|
|
|
|
typLen = sizeof(Datum);
|
|
|
|
typByVal = true;
|
|
|
|
}
|
|
|
|
sz = add_size(sz,
|
|
|
|
datumEstimateSpace(prm->value, prm->isnull, typByVal, typLen));
|
|
|
|
}
|
|
|
|
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Serialize a paramListInfo structure into caller-provided storage.
|
|
|
|
*
|
|
|
|
* We write the number of parameters first, as a 4-byte integer, and then
|
|
|
|
* write details for each parameter in turn. The details for each parameter
|
|
|
|
* consist of a 4-byte type OID, 2 bytes of flags, and then the datum as
|
|
|
|
* serialized by datumSerialize(). The caller is responsible for ensuring
|
|
|
|
* that there is enough storage to store the number of bytes that will be
|
|
|
|
* written; use EstimateParamListSpace to find out how many will be needed.
|
|
|
|
* *start_address is updated to point to the byte immediately following those
|
|
|
|
* written.
|
|
|
|
*
|
|
|
|
* RestoreParamList can be used to recreate a ParamListInfo based on the
|
|
|
|
* serialized representation; this will be a static, self-contained copy
|
|
|
|
* just as copyParamList would create.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SerializeParamList(ParamListInfo paramLI, char **start_address)
|
|
|
|
{
|
|
|
|
int nparams;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Write number of parameters. */
|
|
|
|
if (paramLI == NULL || paramLI->numParams <= 0)
|
|
|
|
nparams = 0;
|
|
|
|
else
|
|
|
|
nparams = paramLI->numParams;
|
|
|
|
memcpy(*start_address, &nparams, sizeof(int));
|
|
|
|
*start_address += sizeof(int);
|
|
|
|
|
|
|
|
/* Write each parameter in turn. */
|
|
|
|
for (i = 0; i < nparams; i++)
|
|
|
|
{
|
|
|
|
ParamExternData *prm = ¶mLI->params[i];
|
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.
10 years ago
|
|
|
Oid typeOid;
|
|
|
|
int16 typLen;
|
|
|
|
bool typByVal;
|
|
|
|
|
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.
10 years ago
|
|
|
/* 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. */
|
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.
10 years ago
|
|
|
memcpy(*start_address, &typeOid, sizeof(Oid));
|
|
|
|
*start_address += sizeof(Oid);
|
|
|
|
|
|
|
|
/* Write flags. */
|
|
|
|
memcpy(*start_address, &prm->pflags, sizeof(uint16));
|
|
|
|
*start_address += sizeof(uint16);
|
|
|
|
|
|
|
|
/* Write datum/isnull. */
|
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.
10 years ago
|
|
|
if (OidIsValid(typeOid))
|
|
|
|
get_typlenbyval(typeOid, &typLen, &typByVal);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If no type OID, assume by-value, like copyParamList does. */
|
|
|
|
typLen = sizeof(Datum);
|
|
|
|
typByVal = true;
|
|
|
|
}
|
|
|
|
datumSerialize(prm->value, prm->isnull, typByVal, typLen,
|
|
|
|
start_address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy a ParamListInfo structure.
|
|
|
|
*
|
|
|
|
* The result is allocated in CurrentMemoryContext.
|
|
|
|
*
|
|
|
|
* Note: the intent of this function is to make a static, self-contained
|
|
|
|
* set of parameter values. If dynamic parameter hooks are present, we
|
|
|
|
* intentionally do not copy them into the result. Rather, we forcibly
|
|
|
|
* instantiate all available parameter values and copy the datum values.
|
|
|
|
*/
|
|
|
|
ParamListInfo
|
|
|
|
RestoreParamList(char **start_address)
|
|
|
|
{
|
|
|
|
ParamListInfo paramLI;
|
|
|
|
Size size;
|
|
|
|
int i;
|
|
|
|
int nparams;
|
|
|
|
|
|
|
|
memcpy(&nparams, *start_address, sizeof(int));
|
|
|
|
*start_address += sizeof(int);
|
|
|
|
|
|
|
|
size = offsetof(ParamListInfoData, params) +
|
|
|
|
nparams * sizeof(ParamExternData);
|
|
|
|
|
|
|
|
paramLI = (ParamListInfo) palloc(size);
|
|
|
|
paramLI->paramFetch = NULL;
|
|
|
|
paramLI->paramFetchArg = NULL;
|
|
|
|
paramLI->parserSetup = NULL;
|
|
|
|
paramLI->parserSetupArg = NULL;
|
|
|
|
paramLI->numParams = nparams;
|
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.
10 years ago
|
|
|
paramLI->paramMask = NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++)
|
|
|
|
{
|
|
|
|
ParamExternData *prm = ¶mLI->params[i];
|
|
|
|
|
|
|
|
/* Read type OID. */
|
|
|
|
memcpy(&prm->ptype, *start_address, sizeof(Oid));
|
|
|
|
*start_address += sizeof(Oid);
|
|
|
|
|
|
|
|
/* Read flags. */
|
|
|
|
memcpy(&prm->pflags, *start_address, sizeof(uint16));
|
|
|
|
*start_address += sizeof(uint16);
|
|
|
|
|
|
|
|
/* Read datum/isnull. */
|
|
|
|
prm->value = datumRestore(start_address, &prm->isnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
return paramLI;
|
|
|
|
}
|