postgresql/src/backend/nodes/params.c

254 lines
6.5 KiB
C

/*-------------------------------------------------------------------------
*
* params.c
* Support for finding the values associated with Param nodes.
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/backend/nodes/params.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "nodes/bitmapset.h"
#include "nodes/params.h"
#include "storage/shmem.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
/*
* Allocate and initialize a new ParamListInfo structure.
*
* To make a new structure for the "dynamic" way (with hooks), pass 0 for
* numParams and set numParams manually.
*/
ParamListInfo
makeParamList(int numParams)
{
ParamListInfo retval;
Size size;
size = offsetof(ParamListInfoData, params) +
numParams * sizeof(ParamExternData);
retval = (ParamListInfo) palloc(size);
retval->paramFetch = NULL;
retval->paramFetchArg = NULL;
retval->paramCompile = NULL;
retval->paramCompileArg = NULL;
retval->parserSetup = NULL;
retval->parserSetupArg = NULL;
retval->numParams = numParams;
return retval;
}
/*
* 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;
if (from == NULL || from->numParams <= 0)
return NULL;
retval = makeParamList(from->numParams);
for (int i = 0; i < from->numParams; i++)
{
ParamExternData *oprm;
ParamExternData *nprm = &retval->params[i];
ParamExternData prmdata;
int16 typLen;
bool typByVal;
/* give hook a chance in case parameter is dynamic */
if (from->paramFetch != NULL)
oprm = from->paramFetch(from, i + 1, false, &prmdata);
else
oprm = &from->params[i];
/* 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;
ParamExternData prmdata;
Oid typeOid;
int16 typLen;
bool typByVal;
/* give hook a chance in case parameter is dynamic */
if (paramLI->paramFetch != NULL)
prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
else
prm = &paramLI->params[i];
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(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;
ParamExternData prmdata;
Oid typeOid;
int16 typLen;
bool typByVal;
/* give hook a chance in case parameter is dynamic */
if (paramLI->paramFetch != NULL)
prm = paramLI->paramFetch(paramLI, i + 1, false, &prmdata);
else
prm = &paramLI->params[i];
typeOid = prm->ptype;
/* Write type OID. */
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. */
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;
int nparams;
memcpy(&nparams, *start_address, sizeof(int));
*start_address += sizeof(int);
paramLI = makeParamList(nparams);
for (int i = 0; i < nparams; i++)
{
ParamExternData *prm = &paramLI->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;
}