]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/execQual.c
Improve the recently-added support for properly pluralized error messages
[postgresql] / src / backend / executor / execQual.c
index ed53a62e383a4f2ae4910a9c404d0a3f35710172..c7bfe7c76ca6b926f2dcbe1eee05b3a0b8b6ecc0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.240 2009/01/01 17:23:41 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.247 2009/06/04 18:33:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,7 +45,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
-#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
 #include "pgstat.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -616,8 +616,11 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                                ereport(ERROR,
                                                (errcode(ERRCODE_DATATYPE_MISMATCH),
                                                 errmsg("table row type and query-specified row type do not match"),
-                                                errdetail("Table row contains %d attributes, but query expects %d.",
-                                                                  slot_tupdesc->natts, var_tupdesc->natts)));
+                                                errdetail_plural("Table row contains %d attribute, but query expects %d.",
+                                                                                 "Table row contains %d attributes, but query expects %d.",
+                                                                                 slot_tupdesc->natts,
+                                                                                 slot_tupdesc->natts,
+                                                                                 var_tupdesc->natts)));
                        else if (var_tupdesc->natts < slot_tupdesc->natts)
                                needslow = true;
 
@@ -1041,8 +1044,10 @@ init_fcache(Oid foid, FuncExprState *fcache,
        if (list_length(fcache->args) > FUNC_MAX_ARGS)
                ereport(ERROR,
                                (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
-                                errmsg("cannot pass more than %d arguments to a function",
-                                               FUNC_MAX_ARGS)));
+                                errmsg_plural("cannot pass more than %d argument to a function",
+                                                          "cannot pass more than %d arguments to a function",
+                                                          FUNC_MAX_ARGS,
+                                                          FUNC_MAX_ARGS)));
 
        /* Set up the primary fmgr lookup information */
        fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
@@ -1310,8 +1315,10 @@ tupledesc_match(TupleDesc dst_tupdesc, TupleDesc src_tupdesc)
                ereport(ERROR,
                                (errcode(ERRCODE_DATATYPE_MISMATCH),
                                 errmsg("function return row and query-specified return row do not match"),
-                                errdetail("Returned row contains %d attributes, but query expects %d.",
-                                                  src_tupdesc->natts, dst_tupdesc->natts)));
+                                errdetail_plural("Returned row contains %d attribute, but query expects %d.",
+                                                                 "Returned row contains %d attributes, but query expects %d.",
+                                                                 src_tupdesc->natts,
+                                                                 src_tupdesc->natts, dst_tupdesc->natts)));
 
        for (i = 0; i < dst_tupdesc->natts; i++)
        {
@@ -1379,7 +1386,7 @@ restart:
        if (fcache->funcResultStore)
        {
                Assert(isDone);                         /* it was provided before ... */
-               if (tuplestore_gettupleslot(fcache->funcResultStore, true,
+               if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
                                                                        fcache->funcResultSlot))
                {
                        *isDone = ExprMultipleResult;
@@ -4320,7 +4327,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                sstate = ExecInitSubPlan(subplan, parent);
 
                                /* Add SubPlanState nodes to parent->subPlan */
-                               parent->subPlan = lcons(sstate, parent->subPlan);
+                               parent->subPlan = lappend(parent->subPlan, sstate);
 
                                state = (ExprState *) sstate;
                        }
@@ -4665,27 +4672,16 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                XmlExprState *xstate = makeNode(XmlExprState);
                                List       *outlist;
                                ListCell   *arg;
-                               int                     i;
 
                                xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
-                               xstate->named_outfuncs = (FmgrInfo *)
-                                       palloc0(list_length(xexpr->named_args) * sizeof(FmgrInfo));
                                outlist = NIL;
-                               i = 0;
                                foreach(arg, xexpr->named_args)
                                {
                                        Expr       *e = (Expr *) lfirst(arg);
                                        ExprState  *estate;
-                                       Oid                     typOutFunc;
-                                       bool            typIsVarlena;
 
                                        estate = ExecInitExpr(e, parent);
                                        outlist = lappend(outlist, estate);
-
-                                       getTypeOutputInfo(exprType((Node *) e),
-                                                                         &typOutFunc, &typIsVarlena);
-                                       fmgr_info(typOutFunc, &xstate->named_outfuncs[i]);
-                                       i++;
                                }
                                xstate->named_args = outlist;
 
@@ -4794,10 +4790,11 @@ ExecInitExpr(Expr *node, PlanState *parent)
  * Plan tree context.
  *
  * This differs from ExecInitExpr in that we don't assume the caller is
- * already running in the EState's per-query context.  Also, we apply
- * fix_opfuncids() to the passed expression tree to be sure it is ready
- * to run.     (In ordinary Plan trees the planner will have fixed opfuncids,
- * but callers outside the executor will not have done this.)
+ * already running in the EState's per-query context.  Also, we run the
+ * passed expression tree through expression_planner() to prepare it for
+ * execution.  (In ordinary Plan trees the regular planning process will have
+ * made the appropriate transformations on expressions, but for standalone
+ * expressions this won't have happened.)
  */
 ExprState *
 ExecPrepareExpr(Expr *node, EState *estate)
@@ -4805,10 +4802,10 @@ ExecPrepareExpr(Expr *node, EState *estate)
        ExprState  *result;
        MemoryContext oldcontext;
 
-       fix_opfuncids((Node *) node);
-
        oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
 
+       node = expression_planner(node);
+
        result = ExecInitExpr(node, NULL);
 
        MemoryContextSwitchTo(oldcontext);
@@ -4959,6 +4956,7 @@ ExecCleanTargetListLength(List *targetlist)
  * prepared to deal with sets of result tuples.  Otherwise, a return
  * of *isDone = ExprMultipleResult signifies a set element, and a return
  * of *isDone = ExprEndResult signifies end of the set of tuple.
+ * We assume that *isDone has been initialized to ExprSingleResult by caller.
  */
 static bool
 ExecTargetList(List *targetlist,
@@ -4980,9 +4978,6 @@ ExecTargetList(List *targetlist,
        /*
         * evaluate all the expressions in the target list
         */
-       if (isDone)
-               *isDone = ExprSingleResult;             /* until proven otherwise */
-
        haveDoneSets = false;           /* any exhausted set exprs in tlist? */
 
        foreach(tl, targetlist)
@@ -5097,50 +5092,6 @@ ExecTargetList(List *targetlist,
        return true;
 }
 
-/*
- * ExecVariableList
- *             Evaluates a simple-Variable-list projection.
- *
- * Results are stored into the passed values and isnull arrays.
- */
-static void
-ExecVariableList(ProjectionInfo *projInfo,
-                                Datum *values,
-                                bool *isnull)
-{
-       ExprContext *econtext = projInfo->pi_exprContext;
-       int                *varSlotOffsets = projInfo->pi_varSlotOffsets;
-       int                *varNumbers = projInfo->pi_varNumbers;
-       int                     i;
-
-       /*
-        * Force extraction of all input values that we need.
-        */
-       if (projInfo->pi_lastInnerVar > 0)
-               slot_getsomeattrs(econtext->ecxt_innertuple,
-                                                 projInfo->pi_lastInnerVar);
-       if (projInfo->pi_lastOuterVar > 0)
-               slot_getsomeattrs(econtext->ecxt_outertuple,
-                                                 projInfo->pi_lastOuterVar);
-       if (projInfo->pi_lastScanVar > 0)
-               slot_getsomeattrs(econtext->ecxt_scantuple,
-                                                 projInfo->pi_lastScanVar);
-
-       /*
-        * Assign to result by direct extraction of fields from source slots ... a
-        * mite ugly, but fast ...
-        */
-       for (i = list_length(projInfo->pi_targetlist) - 1; i >= 0; i--)
-       {
-               char       *slotptr = ((char *) econtext) + varSlotOffsets[i];
-               TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
-               int                     varNumber = varNumbers[i] - 1;
-
-               values[i] = varSlot->tts_values[varNumber];
-               isnull[i] = varSlot->tts_isnull[varNumber];
-       }
-}
-
 /*
  * ExecProject
  *
@@ -5158,6 +5109,8 @@ TupleTableSlot *
 ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
 {
        TupleTableSlot *slot;
+       ExprContext *econtext;
+       int                     numSimpleVars;
 
        /*
         * sanity checks
@@ -5168,6 +5121,11 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
         * get the projection info we want
         */
        slot = projInfo->pi_slot;
+       econtext = projInfo->pi_exprContext;
+
+       /* Assume single result row until proven otherwise */
+       if (isDone)
+               *isDone = ExprSingleResult;
 
        /*
         * Clear any former contents of the result slot.  This makes it safe for
@@ -5177,29 +5135,84 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
        ExecClearTuple(slot);
 
        /*
-        * form a new result tuple (if possible); if successful, mark the result
-        * slot as containing a valid virtual tuple
+        * Force extraction of all input values that we'll need.  The
+        * Var-extraction loops below depend on this, and we are also prefetching
+        * all attributes that will be referenced in the generic expressions.
+        */
+       if (projInfo->pi_lastInnerVar > 0)
+               slot_getsomeattrs(econtext->ecxt_innertuple,
+                                                 projInfo->pi_lastInnerVar);
+       if (projInfo->pi_lastOuterVar > 0)
+               slot_getsomeattrs(econtext->ecxt_outertuple,
+                                                 projInfo->pi_lastOuterVar);
+       if (projInfo->pi_lastScanVar > 0)
+               slot_getsomeattrs(econtext->ecxt_scantuple,
+                                                 projInfo->pi_lastScanVar);
+
+       /*
+        * Assign simple Vars to result by direct extraction of fields from source
+        * slots ... a mite ugly, but fast ...
         */
-       if (projInfo->pi_isVarList)
+       numSimpleVars = projInfo->pi_numSimpleVars;
+       if (numSimpleVars > 0)
        {
-               /* simple Var list: this always succeeds with one result row */
-               if (isDone)
-                       *isDone = ExprSingleResult;
-               ExecVariableList(projInfo,
-                                                slot->tts_values,
-                                                slot->tts_isnull);
-               ExecStoreVirtualTuple(slot);
+               Datum  *values = slot->tts_values;
+               bool   *isnull = slot->tts_isnull;
+               int        *varSlotOffsets = projInfo->pi_varSlotOffsets;
+               int        *varNumbers = projInfo->pi_varNumbers;
+               int             i;
+
+               if (projInfo->pi_directMap)
+               {
+                       /* especially simple case where vars go to output in order */
+                       for (i = 0; i < numSimpleVars; i++)
+                       {
+                               char       *slotptr = ((char *) econtext) + varSlotOffsets[i];
+                               TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
+                               int                     varNumber = varNumbers[i] - 1;
+
+                               values[i] = varSlot->tts_values[varNumber];
+                               isnull[i] = varSlot->tts_isnull[varNumber];
+                       }
+               }
+               else
+               {
+                       /* we have to pay attention to varOutputCols[] */
+                       int        *varOutputCols = projInfo->pi_varOutputCols;
+
+                       for (i = 0; i < numSimpleVars; i++)
+                       {
+                               char       *slotptr = ((char *) econtext) + varSlotOffsets[i];
+                               TupleTableSlot *varSlot = *((TupleTableSlot **) slotptr);
+                               int                     varNumber = varNumbers[i] - 1;
+                               int                     varOutputCol = varOutputCols[i] - 1;
+
+                               values[varOutputCol] = varSlot->tts_values[varNumber];
+                               isnull[varOutputCol] = varSlot->tts_isnull[varNumber];
+                       }
+               }
        }
-       else
+
+       /*
+        * If there are any generic expressions, evaluate them.  It's possible
+        * that there are set-returning functions in such expressions; if so
+        * and we have reached the end of the set, we return the result slot,
+        * which we already marked empty.
+        */
+       if (projInfo->pi_targetlist)
        {
-               if (ExecTargetList(projInfo->pi_targetlist,
-                                                  projInfo->pi_exprContext,
-                                                  slot->tts_values,
-                                                  slot->tts_isnull,
-                                                  projInfo->pi_itemIsDone,
-                                                  isDone))
-                       ExecStoreVirtualTuple(slot);
+               if (!ExecTargetList(projInfo->pi_targetlist,
+                                                       econtext,
+                                                       slot->tts_values,
+                                                       slot->tts_isnull,
+                                                       projInfo->pi_itemIsDone,
+                                                       isDone))
+                       return slot;            /* no more result rows, return empty slot */
        }
 
-       return slot;
+       /*
+        * Successfully formed a result row.  Mark the result slot as containing a
+        * valid virtual tuple.
+        */
+       return ExecStoreVirtualTuple(slot);
 }