Simplify ParamListInfo data structure to support only numbered parameters,

not named ones, and replace linear searches of the list with array indexing.
The named-parameter support has been dead code for many years anyway,
and recent profiling suggests that the searching was costing a noticeable
amount of performance for complex queries.
This commit is contained in:
Tom Lane 2006-04-22 01:26:01 +00:00
parent 0606860a20
commit 2206b498d8
20 changed files with 214 additions and 335 deletions

View File

@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.49 2006/03/05 15:58:24 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.50 2006/04/22 01:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -247,30 +247,30 @@ EvaluateParams(EState *estate, List *params, List *argtypes)
if (list_length(params) != nargs)
elog(ERROR, "wrong number of arguments");
if (nargs == 0)
return NULL;
exprstates = (List *) ExecPrepareExpr((Expr *) params, estate);
paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(nargs - 1) * sizeof(ParamExternData));
paramLI->numParams = nargs;
forboth(le, exprstates, la, argtypes)
{
ExprState *n = lfirst(le);
bool isNull;
ParamExternData *prm = &paramLI->params[i];
paramLI[i].value = ExecEvalExprSwitchContext(n,
GetPerTupleExprContext(estate),
&isNull,
NULL);
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
paramLI[i].ptype = lfirst_oid(la);
paramLI[i].isnull = isNull;
prm->ptype = lfirst_oid(la);
prm->value = ExecEvalExprSwitchContext(n,
GetPerTupleExprContext(estate),
&prm->isnull,
NULL);
i++;
}
paramLI[i].kind = PARAM_INVALID;
return paramLI;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.189 2006/03/10 01:51:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.190 2006/04/22 01:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -605,13 +605,12 @@ ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Param *expression = (Param *) exprstate->expr;
int thisParamKind = expression->paramkind;
AttrNumber thisParamId = expression->paramid;
int thisParamId = expression->paramid;
if (isDone)
*isDone = ExprSingleResult;
if (thisParamKind == PARAM_EXEC)
if (expression->paramkind == PARAM_EXEC)
{
/*
* PARAM_EXEC params (internal executor parameters) are stored in the
@ -633,18 +632,27 @@ ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
else
{
/*
* All other parameter types must be sought in ecxt_param_list_info.
* PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
*/
ParamListInfo paramInfo;
ParamListInfo paramInfo = econtext->ecxt_param_list_info;
paramInfo = lookupParam(econtext->ecxt_param_list_info,
thisParamKind,
expression->paramname,
thisParamId,
false);
Assert(paramInfo->ptype == expression->paramtype);
*isNull = paramInfo->isnull;
return paramInfo->value;
Assert(expression->paramkind == PARAM_EXTERN);
if (paramInfo &&
thisParamId > 0 && thisParamId <= paramInfo->numParams)
{
ParamExternData *prm = &paramInfo->params[thisParamId - 1];
if (OidIsValid(prm->ptype))
{
Assert(prm->ptype == expression->paramtype);
*isNull = prm->isnull;
return prm->value;
}
}
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no value found for parameter %d", thisParamId)));
return (Datum) 0; /* keep compiler quiet */
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.101 2006/03/05 15:58:26 momjian Exp $
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.102 2006/04/22 01:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -431,17 +431,19 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
{
int i;
paramLI = (ParamListInfo) palloc0((nargs + 1) * sizeof(ParamListInfoData));
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(nargs - 1) * sizeof(ParamExternData));
paramLI->numParams = nargs;
for (i = 0; i < nargs; i++)
{
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
paramLI[i].ptype = fcache->argtypes[i];
paramLI[i].value = fcinfo->arg[i];
paramLI[i].isnull = fcinfo->argnull[i];
ParamExternData *prm = &paramLI->params[i];
prm->value = fcinfo->arg[i];
prm->isnull = fcinfo->argnull[i];
prm->ptype = fcache->argtypes[i];
}
paramLI[nargs].kind = PARAM_INVALID;
}
else
paramLI = NULL;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.150 2006/04/04 19:35:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.151 2006/04/22 01:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -885,19 +885,21 @@ SPI_cursor_open(const char *name, void *plan,
/* If the plan has parameters, set them up */
if (spiplan->nargs > 0)
{
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
sizeof(ParamListInfoData));
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(spiplan->nargs - 1) * sizeof(ParamExternData));
paramLI->numParams = spiplan->nargs;
for (k = 0; k < spiplan->nargs; k++)
{
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
paramLI[k].ptype = spiplan->argtypes[k];
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
if (paramLI[k].isnull)
ParamExternData *prm = &paramLI->params[k];
prm->ptype = spiplan->argtypes[k];
prm->isnull = (Nulls && Nulls[k] == 'n');
if (prm->isnull)
{
/* nulls just copy */
paramLI[k].value = Values[k];
prm->value = Values[k];
}
else
{
@ -905,13 +907,11 @@ SPI_cursor_open(const char *name, void *plan,
int16 paramTypLen;
bool paramTypByVal;
get_typlenbyval(spiplan->argtypes[k],
&paramTypLen, &paramTypByVal);
paramLI[k].value = datumCopy(Values[k],
paramTypByVal, paramTypLen);
get_typlenbyval(prm->ptype, &paramTypLen, &paramTypByVal);
prm->value = datumCopy(Values[k],
paramTypByVal, paramTypLen);
}
}
paramLI[k].kind = PARAM_INVALID;
}
else
paramLI = NULL;
@ -1334,18 +1334,19 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
{
int k;
paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(nargs - 1) * sizeof(ParamExternData));
paramLI->numParams = nargs;
for (k = 0; k < nargs; k++)
{
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
paramLI[k].ptype = plan->argtypes[k];
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
paramLI[k].value = Values[k];
ParamExternData *prm = &paramLI->params[k];
prm->value = Values[k];
prm->isnull = (Nulls && Nulls[k] == 'n');
prm->ptype = plan->argtypes[k];
}
paramLI[k].kind = PARAM_INVALID;
}
else
paramLI = NULL;

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.333 2006/04/15 17:45:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.334 2006/04/22 01:25:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -729,7 +729,6 @@ _copyParam(Param *from)
COPY_SCALAR_FIELD(paramkind);
COPY_SCALAR_FIELD(paramid);
COPY_STRING_FIELD(paramname);
COPY_SCALAR_FIELD(paramtype);
return newnode;

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.269 2006/04/15 17:45:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.270 2006/04/22 01:25:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -147,23 +147,9 @@ static bool
_equalParam(Param *a, Param *b)
{
COMPARE_SCALAR_FIELD(paramkind);
COMPARE_SCALAR_FIELD(paramid);
COMPARE_SCALAR_FIELD(paramtype);
switch (a->paramkind)
{
case PARAM_NAMED:
COMPARE_STRING_FIELD(paramname);
break;
case PARAM_NUM:
case PARAM_EXEC:
case PARAM_SUBLINK:
COMPARE_SCALAR_FIELD(paramid);
break;
default:
elog(ERROR, "unrecognized paramkind: %d",
a->paramkind);
}
return true;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.272 2006/03/23 00:19:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.273 2006/04/22 01:25:59 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@ -624,9 +624,8 @@ _outParam(StringInfo str, Param *node)
{
WRITE_NODE_TYPE("PARAM");
WRITE_INT_FIELD(paramkind);
WRITE_ENUM_FIELD(paramkind, ParamKind);
WRITE_INT_FIELD(paramid);
WRITE_STRING_FIELD(paramname);
WRITE_OID_FIELD(paramtype);
}

View File

@ -1,13 +1,14 @@
/*-------------------------------------------------------------------------
*
* params.c
* Support functions for plan parameter lists.
* Support for finding the values associated with Param nodes.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.5 2006/03/05 15:58:28 momjian Exp $
* $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.6 2006/04/22 01:25:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,7 +21,7 @@
/*
* Copy a ParamList.
* Copy a ParamListInfo structure.
*
* The result is allocated in CurrentMemoryContext.
*/
@ -28,97 +29,34 @@ ParamListInfo
copyParamList(ParamListInfo from)
{
ParamListInfo retval;
int i,
size;
Size size;
int i;
if (from == NULL)
if (from == NULL || from->numParams <= 0)
return NULL;
size = 0;
while (from[size].kind != PARAM_INVALID)
size++;
/* sizeof(ParamListInfoData) includes the first array element */
size = sizeof(ParamListInfoData) +
(from->numParams - 1) * sizeof(ParamExternData);
retval = (ParamListInfo) palloc0((size + 1) * sizeof(ParamListInfoData));
retval = (ParamListInfo) palloc(size);
memcpy(retval, from, size);
for (i = 0; i < size; i++)
/*
* Flat-copy is not good enough for pass-by-ref data values, so make
* a pass over the array to copy those.
*/
for (i = 0; i < retval->numParams; i++)
{
/* copy metadata */
retval[i].kind = from[i].kind;
if (from[i].kind == PARAM_NAMED)
retval[i].name = pstrdup(from[i].name);
retval[i].id = from[i].id;
retval[i].ptype = from[i].ptype;
ParamExternData *prm = &retval->params[i];
int16 typLen;
bool typByVal;
/* copy value */
retval[i].isnull = from[i].isnull;
if (from[i].isnull)
{
retval[i].value = from[i].value; /* nulls just copy */
}
else
{
int16 typLen;
bool typByVal;
get_typlenbyval(from[i].ptype, &typLen, &typByVal);
retval[i].value = datumCopy(from[i].value, typByVal, typLen);
}
if (prm->isnull || !OidIsValid(prm->ptype))
continue;
get_typlenbyval(prm->ptype, &typLen, &typByVal);
prm->value = datumCopy(prm->value, typByVal, typLen);
}
retval[size].kind = PARAM_INVALID;
return retval;
}
/*
* Search a ParamList for a given parameter.
*
* On success, returns a pointer to the parameter's entry.
* On failure, returns NULL if noError is true, else ereports the error.
*/
ParamListInfo
lookupParam(ParamListInfo paramList, int thisParamKind,
const char *thisParamName, AttrNumber thisParamId,
bool noError)
{
if (paramList != NULL)
{
while (paramList->kind != PARAM_INVALID)
{
if (thisParamKind == paramList->kind)
{
switch (thisParamKind)
{
case PARAM_NAMED:
if (strcmp(paramList->name, thisParamName) == 0)
return paramList;
break;
case PARAM_NUM:
if (paramList->id == thisParamId)
return paramList;
break;
default:
elog(ERROR, "unrecognized paramkind: %d",
thisParamKind);
}
}
paramList++;
}
}
if (!noError)
{
if (thisParamKind == PARAM_NAMED)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no value found for parameter \"%s\"",
thisParamName)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no value found for parameter %d",
thisParamId)));
}
return NULL;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.187 2006/03/16 00:31:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.188 2006/04/22 01:25:59 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@ -318,9 +318,8 @@ _readParam(void)
{
READ_LOCALS(Param);
READ_INT_FIELD(paramkind);
READ_ENUM_FIELD(paramkind, ParamKind);
READ_INT_FIELD(paramid);
READ_STRING_FIELD(paramname);
READ_OID_FIELD(paramtype);
READ_DONE();

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.104 2006/03/05 15:58:30 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.105 2006/04/22 01:25:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -163,7 +163,7 @@ replace_outer_var(Var *var)
retval = makeNode(Param);
retval->paramkind = PARAM_EXEC;
retval->paramid = (AttrNumber) i;
retval->paramid = i;
retval->paramtype = var->vartype;
return retval;
@ -201,7 +201,7 @@ replace_outer_agg(Aggref *agg)
retval = makeNode(Param);
retval->paramkind = PARAM_EXEC;
retval->paramid = (AttrNumber) i;
retval->paramid = i;
retval->paramtype = agg->aggtype;
return retval;
@ -222,7 +222,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
retval = makeNode(Param);
retval->paramkind = PARAM_EXEC;
retval->paramid = (AttrNumber) list_length(PlannerParamList);
retval->paramid = list_length(PlannerParamList);
retval->paramtype = paramtype;
pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem));
@ -1211,7 +1211,7 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
{
if (((Param *) node)->paramkind == PARAM_EXEC)
{
int paramid = (int) ((Param *) node)->paramid;
int paramid = ((Param *) node)->paramid;
context->paramids = bms_add_member(context->paramids, paramid);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.210 2006/03/14 22:48:19 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.211 2006/04/22 01:25:59 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -1500,36 +1500,35 @@ eval_const_expressions_mutator(Node *node,
Param *param = (Param *) node;
/* OK to try to substitute value? */
if (context->estimate && param->paramkind != PARAM_EXEC &&
if (context->estimate && param->paramkind == PARAM_EXTERN &&
PlannerBoundParamList != NULL)
{
ParamListInfo paramInfo;
/* Search to see if we've been given a value for this Param */
paramInfo = lookupParam(PlannerBoundParamList,
param->paramkind,
param->paramname,
param->paramid,
true);
if (paramInfo)
/* Look to see if we've been given a value for this Param */
if (param->paramid > 0 &&
param->paramid <= PlannerBoundParamList->numParams)
{
/*
* Found it, so return a Const representing the param value.
* Note that we don't copy pass-by-ref datatypes, so the Const
* will only be valid as long as the bound parameter list
* exists. This is okay for intended uses of
* estimate_expression_value().
*/
int16 typLen;
bool typByVal;
ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
Assert(paramInfo->ptype == param->paramtype);
get_typlenbyval(param->paramtype, &typLen, &typByVal);
return (Node *) makeConst(param->paramtype,
(int) typLen,
paramInfo->value,
paramInfo->isnull,
typByVal);
if (OidIsValid(prm->ptype))
{
/*
* Found it, so return a Const representing the param
* value. Note that we don't copy pass-by-ref datatypes,
* so the Const will only be valid as long as the bound
* parameter list exists. This is okay for intended uses
* of estimate_expression_value().
*/
int16 typLen;
bool typByVal;
Assert(prm->ptype == param->paramtype);
get_typlenbyval(param->paramtype, &typLen, &typByVal);
return (Node *) makeConst(param->paramtype,
(int) typLen,
prm->value,
prm->isnull,
typByVal);
}
}
}
/* Not replaceable, so just copy the Param (no need to recurse) */
@ -2810,8 +2809,8 @@ substitute_actual_parameters_mutator(Node *node,
{
Param *param = (Param *) node;
if (param->paramkind != PARAM_NUM)
elog(ERROR, "unexpected paramkind: %d", param->paramkind);
if (param->paramkind != PARAM_EXTERN)
elog(ERROR, "unexpected paramkind: %d", (int) param->paramkind);
if (param->paramid <= 0 || param->paramid > context->nargs)
elog(ERROR, "invalid paramid: %d", param->paramid);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.332 2006/03/23 00:19:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.333 2006/04/22 01:25:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -3205,7 +3205,7 @@ check_parameter_resolution_walker(Node *node,
{
Param *param = (Param *) node;
if (param->paramkind == PARAM_NUM)
if (param->paramkind == PARAM_EXTERN)
{
int paramno = param->paramid;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.137 2006/04/05 22:11:55 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.138 2006/04/22 01:25:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -210,7 +210,7 @@ coerce_type(ParseState *pstate, Node *node,
return result;
}
if (inputTypeId == UNKNOWNOID && IsA(node, Param) &&
((Param *) node)->paramkind == PARAM_NUM &&
((Param *) node)->paramkind == PARAM_EXTERN &&
pstate != NULL && pstate->p_variableparams)
{
/*

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.191 2006/03/14 22:48:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.192 2006/04/22 01:26:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -568,8 +568,8 @@ transformParamRef(ParseState *pstate, ParamRef *pref)
}
param = makeNode(Param);
param->paramkind = PARAM_NUM;
param->paramid = (AttrNumber) paramno;
param->paramkind = PARAM_EXTERN;
param->paramid = paramno;
param->paramtype = toppstate->p_paramtypes[paramno - 1];
return (Node *) param;
@ -1177,7 +1177,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
param = makeNode(Param);
param->paramkind = PARAM_SUBLINK;
param->paramid = (AttrNumber) tent->resno;
param->paramid = tent->resno;
param->paramtype = exprType((Node *) tent->expr);
right_list = lappend(right_list, param);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.484 2006/04/18 00:52:23 momjian Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.485 2006/04/22 01:26:00 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -1479,8 +1479,10 @@ exec_bind_message(StringInfo input_message)
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
params = (ParamListInfo)
palloc0((numParams + 1) * sizeof(ParamListInfoData));
/* sizeof(ParamListInfoData) includes the first array element */
params = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(numParams - 1) * sizeof(ParamExternData));
params->numParams = numParams;
i = 0;
foreach(l, pstmt->argtype_list)
@ -1545,8 +1547,10 @@ exec_bind_message(StringInfo input_message)
else
pstring = pg_client_to_server(pbuf.data, plength);
params[i].value = OidInputFunctionCall(typinput, pstring,
typioparam, -1);
params->params[i].value = OidInputFunctionCall(typinput,
pstring,
typioparam,
-1);
/* Free result of encoding conversion, if any */
if (pstring && pstring != pbuf.data)
pfree(pstring);
@ -1567,8 +1571,10 @@ exec_bind_message(StringInfo input_message)
else
bufptr = &pbuf;
params[i].value = OidReceiveFunctionCall(typreceive, bufptr,
typioparam, -1);
params->params[i].value = OidReceiveFunctionCall(typreceive,
bufptr,
typioparam,
-1);
/* Trouble if it didn't eat the whole buffer */
if (!isNull && pbuf.cursor != pbuf.len)
@ -1589,16 +1595,12 @@ exec_bind_message(StringInfo input_message)
if (!isNull)
pbuf.data[plength] = csave;
params[i].kind = PARAM_NUM;
params[i].id = i + 1;
params[i].ptype = ptype;
params[i].isnull = isNull;
params->params[i].isnull = isNull;
params->params[i].ptype = ptype;
i++;
}
params[i].kind = PARAM_INVALID;
MemoryContextSwitchTo(oldContext);
}
else

View File

@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.219 2006/04/08 18:49:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.220 2006/04/22 01:26:00 tgl Exp $
**********************************************************************/
#include "postgres.h"
@ -3120,24 +3120,7 @@ get_rule_expr(Node *node, deparse_context *context,
break;
case T_Param:
{
Param *param = (Param *) node;
switch (param->paramkind)
{
case PARAM_NAMED:
appendStringInfo(buf, "$%s", param->paramname);
break;
case PARAM_NUM:
case PARAM_EXEC:
case PARAM_SUBLINK:
appendStringInfo(buf, "$%d", param->paramid);
break;
default:
appendStringInfo(buf, "(param)");
break;
}
}
appendStringInfo(buf, "$%d", ((Param *) node)->paramid);
break;
case T_Aggref:

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.322 2006/04/05 22:11:55 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.323 2006/04/22 01:26:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200604051
#define CATALOG_VERSION_NO 200604211
#endif

View File

@ -1,87 +1,47 @@
/*-------------------------------------------------------------------------
*
* params.h
* Declarations of stuff needed to handle parameterized plans.
* Support for finding the values associated with Param nodes.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.30 2006/03/05 15:58:56 momjian Exp $
* $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.31 2006/04/22 01:26:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PARAMS_H
#define PARAMS_H
#include "access/attnum.h"
/* ----------------
* The following are the possible values for the 'paramkind'
* field of a Param node.
*
* PARAM_NAMED: The parameter has a name, i.e. something
* like `$.salary' or `$.foobar'.
* In this case field `paramname' must be a valid name.
*
* PARAM_NUM: The parameter has only a numeric identifier,
* i.e. something like `$1', `$2' etc.
* The number is contained in the `paramid' field.
*
* PARAM_EXEC: The parameter is an internal executor parameter.
* It has a number contained in the `paramid' field.
*
* PARAM_SUBLINK: The parameter represents an output column of a SubLink
* node's sub-select. The column number is contained in the
* `paramid' field. (This type of Param is converted to
* PARAM_EXEC during planning.)
*
* PARAM_INVALID should never appear in a Param node; it's used to mark
* the end of a ParamListInfo array.
*
* NOTE: As of PostgreSQL 7.3, named parameters aren't actually used and
* so the code that handles PARAM_NAMED cases is dead code. We leave it
* in place since it might be resurrected someday.
* ----------------
*/
#define PARAM_NAMED 11
#define PARAM_NUM 12
#define PARAM_EXEC 15
#define PARAM_SUBLINK 16
#define PARAM_INVALID 100
/* ----------------
* ParamListInfo
*
* ParamListInfo entries are used to pass parameters into the executor
* ParamListInfo arrays are used to pass parameters into the executor
* for parameterized plans. Each entry in the array defines the value
* to be substituted for a PARAM_NAMED or PARAM_NUM parameter.
* to be substituted for a PARAM_EXTERN parameter. The "paramid"
* of a PARAM_EXTERN Param can range from 1 to numParams.
*
* kind : the kind of parameter (PARAM_NAMED or PARAM_NUM)
* name : the parameter name (valid if kind == PARAM_NAMED)
* id : the parameter id (valid if kind == PARAM_NUM)
* ptype : the type of the parameter value
* isnull : true if the value is null (if so 'value' is undefined)
* value : the value that has to be substituted in the place
* of the parameter.
* Although parameter numbers are normally consecutive, we allow
* ptype == InvalidOid to signal an unused array entry.
*
* ParamListInfo is to be used as an array of ParamListInfoData
* records. A dummy record with kind == PARAM_INVALID marks the end
* of the array.
* Although the data structure is really an array, not a list, we keep
* the old typedef name to avoid unnecessary code changes.
* ----------------
*/
typedef struct ParamExternData
{
Datum value; /* parameter value */
bool isnull; /* is it NULL? */
Oid ptype; /* parameter's datatype, or 0 */
} ParamExternData;
typedef struct ParamListInfoData
{
int kind;
char *name;
AttrNumber id;
Oid ptype;
bool isnull;
Datum value;
int numParams; /* number of ParamExternDatas following */
ParamExternData params[1]; /* VARIABLE LENGTH ARRAY */
} ParamListInfoData;
typedef ParamListInfoData *ParamListInfo;
@ -114,8 +74,5 @@ typedef struct ParamExecData
/* Functions found in src/backend/nodes/params.c */
extern ParamListInfo copyParamList(ParamListInfo from);
extern ParamListInfo lookupParam(ParamListInfo paramList, int thisParamKind,
const char *thisParamName, AttrNumber thisParamId,
bool noError);
#endif /* PARAMS_H */

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.112 2006/03/05 15:58:57 momjian Exp $
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.113 2006/04/22 01:26:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -146,18 +146,15 @@ typedef struct Const
/* ----------------
* Param
* paramkind - specifies the kind of parameter. The possible values
* for this field are specified in "params.h", and they are:
* for this field are:
*
* PARAM_NAMED: The parameter has a name, i.e. something
* like `$.salary' or `$.foobar'.
* In this case field `paramname' must be a valid name.
* PARAM_EXTERN: The parameter value is supplied from outside the plan.
* Such parameters are numbered from 1 to n.
*
* PARAM_NUM: The parameter has only a numeric identifier,
* i.e. something like `$1', `$2' etc.
* The number is contained in the `paramid' field.
*
* PARAM_EXEC: The parameter is an internal executor parameter.
* It has a number contained in the `paramid' field.
* PARAM_EXEC: The parameter is an internal executor parameter, used
* for passing values into and out of sub-queries.
* For historical reasons, such parameters are numbered from 0.
* These numbers are independent of PARAM_EXTERN numbers.
*
* PARAM_SUBLINK: The parameter represents an output column of a SubLink
* node's sub-select. The column number is contained in the
@ -165,12 +162,18 @@ typedef struct Const
* PARAM_EXEC during planning.)
* ----------------
*/
typedef enum ParamKind
{
PARAM_EXTERN,
PARAM_EXEC,
PARAM_SUBLINK
} ParamKind;
typedef struct Param
{
Expr xpr;
int paramkind; /* kind of parameter. See above */
AttrNumber paramid; /* numeric ID for parameter ("$1") */
char *paramname; /* name for parameter ("$.foo") */
ParamKind paramkind; /* kind of parameter. See above */
int paramid; /* numeric ID for parameter */
Oid paramtype; /* PG_TYPE OID of parameter's datatype */
} Param;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.163 2006/04/04 19:35:37 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.164 2006/04/22 01:26:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -3786,24 +3786,27 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
* back for subscript evaluation, and so there can be a need to have more
* than one active param list.
*/
paramLI = (ParamListInfo)
MemoryContextAlloc(econtext->ecxt_per_tuple_memory,
(expr->nparams + 1) * sizeof(ParamListInfoData));
/*
* Put the parameter values into the parameter list entries.
*/
for (i = 0; i < expr->nparams; i++)
if (expr->nparams > 0)
{
PLpgSQL_datum *datum = estate->datums[expr->params[i]];
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo)
MemoryContextAlloc(econtext->ecxt_per_tuple_memory,
sizeof(ParamListInfoData) +
(expr->nparams - 1) * sizeof(ParamExternData));
paramLI->numParams = expr->nparams;
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
exec_eval_datum(estate, datum, expr->plan_argtypes[i],
&paramLI[i].ptype,
&paramLI[i].value, &paramLI[i].isnull);
for (i = 0; i < expr->nparams; i++)
{
ParamExternData *prm = &paramLI->params[i];
PLpgSQL_datum *datum = estate->datums[expr->params[i]];
exec_eval_datum(estate, datum, expr->plan_argtypes[i],
&prm->ptype,
&prm->value, &prm->isnull);
}
}
paramLI[i].kind = PARAM_INVALID;
else
paramLI = NULL;
/*
* Now we can safely make the econtext point to the param list.