From: Tom Lane Date: Sat, 22 Apr 2006 01:26:01 +0000 (+0000) Subject: Simplify ParamListInfo data structure to support only numbered parameters, X-Git-Tag: REL8_2_BETA1~1121 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2206b498d8240447a9353ce4e994ba41a8e307ac;p=thirdparty%2Fpostgresql.git 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. --- diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index c0fbbabdbaa..0892ab9fbb0 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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 = ¶mLI->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; } diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index fcc7d4b683c..41ea452df58 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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; - - paramInfo = lookupParam(econtext->ecxt_param_list_info, - thisParamKind, - expression->paramname, - thisParamId, - false); - Assert(paramInfo->ptype == expression->paramtype); - *isNull = paramInfo->isnull; - return paramInfo->value; + ParamListInfo paramInfo = econtext->ecxt_param_list_info; + + Assert(expression->paramkind == PARAM_EXTERN); + if (paramInfo && + thisParamId > 0 && thisParamId <= paramInfo->numParams) + { + ParamExternData *prm = ¶mInfo->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 */ } } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 0fc4d7b59b2..92e43c1dc57 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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 = ¶mLI->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; diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 3563ba23d3a..333968676d4 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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 = ¶mLI->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], - ¶mTypLen, ¶mTypByVal); - paramLI[k].value = datumCopy(Values[k], - paramTypByVal, paramTypLen); + get_typlenbyval(prm->ptype, ¶mTypLen, ¶mTypByVal); + 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 = ¶mLI->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; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index cd8ebe1f5d6..b060d38b5ed 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 9aa0b399b7c..94799d0c85f 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 58e800bab2b..314d68d2ef9 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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); } diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c index 618a1c1e816..1d4e1d48e8b 100644 --- a/src/backend/nodes/params.c +++ b/src/backend/nodes/params.c @@ -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; - - /* 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); - } + ParamExternData *prm = &retval->params[i]; + int16 typLen; + bool typByVal; + + 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; -} diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 4e762d3a2ec..9fdf02fd568 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -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(); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 1b64bf1c931..5296bb04359 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -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); } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index aa21dfdac95..10a994bcb3f 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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; - - Assert(paramInfo->ptype == param->paramtype); - get_typlenbyval(param->paramtype, &typLen, &typByVal); - return (Node *) makeConst(param->paramtype, - (int) typLen, - paramInfo->value, - paramInfo->isnull, - typByVal); + ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1]; + + 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); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 39c562b8188..d69c0f17864 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 98393a54aa1..3f5d8563f60 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -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) { /* diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index cae682c9e77..414afe6dfa5 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -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); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 3c24fa532a6..04e432594e3 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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 diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 902af40d9fc..c0db64bf896 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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: diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 6b59dd55fe1..a88d3cfd597 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h index a00ded8e0a6..13eb25876dd 100644 --- a/src/include/nodes/params.h +++ b/src/include/nodes/params.h @@ -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 */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 65d5d8ff0c7..9c1f580fc98 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -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; diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 8a82a42fbe6..ee30902dedb 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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; + + for (i = 0; i < expr->nparams; i++) + { + ParamExternData *prm = ¶mLI->params[i]; + PLpgSQL_datum *datum = estate->datums[expr->params[i]]; - paramLI[i].kind = PARAM_NUM; - paramLI[i].id = i + 1; - exec_eval_datum(estate, datum, expr->plan_argtypes[i], - ¶mLI[i].ptype, - ¶mLI[i].value, ¶mLI[i].isnull); + 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.