Simplify ParamListInfo data structure to support only numbered parameters,
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 22 Apr 2006 01:26:01 +0000 (01:26 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 22 Apr 2006 01:26:01 +0000 (01:26 +0000)
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.

20 files changed:
src/backend/commands/prepare.c
src/backend/executor/execQual.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/params.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/clauses.c
src/backend/parser/analyze.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/tcop/postgres.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/nodes/params.h
src/include/nodes/primnodes.h
src/pl/plpgsql/src/pl_exec.c

index c0fbbabdbaa1dd67834d6166c275ac787c080816..0892ab9fbb030e2cee16ffbd943a6dec0282995e 100644 (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;
 }
 
index fcc7d4b683c37fc4b9943b242d524ff66bd0e62b..41ea452df5859c19a99fc29abc3291fba730ccd7 100644 (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;
-
-       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 = &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 */
    }
 }
 
index 0fc4d7b59b2f268f98d5395321e71a507f26f450..92e43c1dc57192cbb25a729d2f09fd9871775d86 100644 (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;
index 3563ba23d3ad2f7cbb8f2fed207402b3714936b9..333968676d4f8c40fd5fe8ae6de1e5689ed5d66a 100644 (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;
index cd8ebe1f5d68b1780217349026fdd34c77f0c7f1..b060d38b5edb0ccb0e1f48c77d2c48bac109ece7 100644 (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;
index 9aa0b399b7c12c39ddfb35f6ab9cff4539bf71b0..94799d0c85f50a2b0129f70b60250911e27a8c41 100644 (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;
 }
 
index 58e800bab2b19fccdd1e3e4cf570f12f18b2308a..314d68d2ef9076a614fa1556d77723412ce8bae4 100644 (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);
 }
 
index 618a1c1e816f4731c383cf00be6350d6e6aacd63..1d4e1d48e8b45a6dd38afb51567cca748b6da97e 100644 (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;
-
-       /* 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;
-}
index 4e762d3a2ecbcff27208ccc75d3dd44e9a6b54ac..9fdf02fd5682c13e3276cd5357d822414b8a1f8d 100644 (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();
index 1b64bf1c93130c58eba2e91655b43ea52e49a7fa..5296bb04359670e97f53a010884f8ed6839dd49d 100644 (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);
        }
index aa21dfdac95406318b4829010c7a028997cf65d5..10a994bcb3fd1bef9daa64211c2c9d2bb1e08d61 100644 (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;
-
-               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);
 
index 39c562b8188f9d6d09e7f9a1eccdc38fc11b591c..d69c0f17864c62a582f89296f9b2f3d1eccdabee 100644 (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;
 
index 98393a54aa11d64564bbc0822a214c35d8e470a2..3f5d8563f60d0e88692cb0df160d42ba27e415af 100644 (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)
    {
        /*
index cae682c9e775ea271255a1205ff8052fa902df14..414afe6dfa536abcf92a97bbb1991a8b11f8da2a 100644 (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);
index 3c24fa532a6bd089e69ce8b1170c7d62b2f9feea..04e432594e352af984a3162ab13769428d0acb31 100644 (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
index 902af40d9fcf199883bec772c8eff589cb60bbad..c0db64bf8960d45c40eb12d6a789f9a351967038 100644 (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:
index 6b59dd55fe1d3753d816625b486a9919d4106cd2..a88d3cfd5971d4427a13376381cbc95ad3098db9 100644 (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
index a00ded8e0a6a8688e6a1410519f451bda6cd57df..13eb25876dd56746be742a22391b793f85a09302 100644 (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 */
index 65d5d8ff0c7e59f066219d9e50c58dd651c7c056..9c1f580fc981b65dbb9ab0c414750ea708a8ab87 100644 (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;
 
index 8a82a42fbe6be756e8ffc0cf06e8ac5a18a226e6..ee30902dedbe01feae731ca034846f8c74e25fbb 100644 (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;
+
+       for (i = 0; i < expr->nparams; i++)
+       {
+           ParamExternData *prm = &paramLI->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],
-                       &paramLI[i].ptype,
-                       &paramLI[i].value, &paramLI[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.