]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/execQual.c
pgindent run for 8.3.
[postgresql] / src / backend / executor / execQual.c
index 69d28e78a4b8336f8ec0f11b66a62b50d844d6a4..8c917c8418978b8406557192c1262348d56507a2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.220 2007/06/11 22:22:40 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.224 2007/11/15 21:14:34 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,9 +65,11 @@ static Datum ExecEvalAggref(AggrefExprState *aggref,
 static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                        bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
-                       bool *isNull, ExprDoneCond *isDone);
+                                 bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
                                        bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
+                                        bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
                          bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
@@ -119,8 +121,8 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
 static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
                           ExprContext *econtext,
                           bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
-                                                bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalXml(XmlExprState * xmlExpr, ExprContext *econtext,
+                       bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
                           ExprContext *econtext,
                           bool *isNull, ExprDoneCond *isDone);
@@ -145,14 +147,14 @@ static Datum ExecEvalFieldStore(FieldStoreState *fstate,
 static Datum ExecEvalRelabelType(GenericExprState *exprstate,
                                        ExprContext *econtext,
                                        bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
-                                                                ExprContext *econtext,
-                                                                bool *isNull, ExprDoneCond *isDone);
-static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
-                                                                        ExprContext *econtext,
-                                                                        bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalCoerceViaIO(CoerceViaIOState * iostate,
+                                       ExprContext *econtext,
+                                       bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState * astate,
+                                               ExprContext *econtext,
+                                               bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
-                       bool *isNull, ExprDoneCond *isDone);
+                                         bool *isNull, ExprDoneCond *isDone);
 
 
 /* ----------------------------------------------------------------
@@ -438,7 +440,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
  *
  * Note: ExecEvalVar is executed only the first time through in a given plan;
  * it changes the ExprState's function pointer to pass control directly to
- * ExecEvalScalarVar or ExecEvalWholeRowVar after making one-time checks.
+ * ExecEvalScalarVar, ExecEvalWholeRowVar, or ExecEvalWholeRowSlow after
+ * making one-time checks.
  * ----------------------------------------------------------------
  */
 static Datum
@@ -486,21 +489,21 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                 * Scalar variable case.
                 *
                 * If it's a user attribute, check validity (bogus system attnums will
-                * be caught inside slot_getattr).  What we have to check for here
-                * is the possibility of an attribute having been changed in type
-                * since the plan tree was created.  Ideally the plan would get
-                * invalidated and not re-used, but until that day arrives, we need
-                * defenses.  Fortunately it's sufficient to check once on the first
-                * time through.
+                * be caught inside slot_getattr).      What we have to check for here is
+                * the possibility of an attribute having been changed in type since
+                * the plan tree was created.  Ideally the plan would get invalidated
+                * and not re-used, but until that day arrives, we need defenses.
+                * Fortunately it's sufficient to check once on the first time
+                * through.
                 *
                 * Note: we allow a reference to a dropped attribute.  slot_getattr
                 * will force a NULL result in such cases.
                 *
                 * Note: ideally we'd check typmod as well as typid, but that seems
-                * impractical at the moment: in many cases the tupdesc will have
-                * been generated by ExecTypeFromTL(), and that can't guarantee to
-                * generate an accurate typmod in all cases, because some expression
-                * node types don't carry typmod.
+                * impractical at the moment: in many cases the tupdesc will have been
+                * generated by ExecTypeFromTL(), and that can't guarantee to generate
+                * an accurate typmod in all cases, because some expression node types
+                * don't carry typmod.
                 */
                if (attnum > 0)
                {
@@ -519,9 +522,9 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                                if (variable->vartype != attr->atttypid)
                                        ereport(ERROR,
                                                        (errmsg("attribute %d has wrong type", attnum),
-                                                        errdetail("Table has type %s, but query expects %s.",
-                                                                          format_type_be(attr->atttypid),
-                                                                          format_type_be(variable->vartype))));
+                                               errdetail("Table has type %s, but query expects %s.",
+                                                                 format_type_be(attr->atttypid),
+                                                                 format_type_be(variable->vartype))));
                        }
                }
 
@@ -544,6 +547,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                 * the actual tuple type is compatible with it.
                 */
                TupleDesc       slot_tupdesc = slot->tts_tupleDescriptor;
+               bool            needslow = false;
 
                if (variable->vartype == RECORDOID)
                {
@@ -561,16 +565,26 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                         * Also, we can ignore type mismatch on columns that are dropped
                         * in the destination type, so long as the physical storage
                         * matches.  This is helpful in some cases involving out-of-date
-                        * cached plans.
+                        * cached plans.  Also, we have to allow the case that the slot
+                        * has more columns than the Var's type, because we might be
+                        * looking at the output of a subplan that includes resjunk
+                        * columns.  (XXX it would be nice to verify that the extra
+                        * columns are all marked resjunk, but we haven't got access to
+                        * the subplan targetlist here...)      Resjunk columns should always
+                        * be at the end of a targetlist, so it's sufficient to ignore
+                        * them here; but we need to use ExecEvalWholeRowSlow to get rid
+                        * of them in the eventual output tuples.
                         */
                        var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
 
-                       if (var_tupdesc->natts != slot_tupdesc->natts)
+                       if (var_tupdesc->natts > slot_tupdesc->natts)
                                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)));
+                       else if (var_tupdesc->natts < slot_tupdesc->natts)
+                               needslow = true;
 
                        for (i = 0; i < var_tupdesc->natts; i++)
                        {
@@ -578,7 +592,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                                Form_pg_attribute sattr = slot_tupdesc->attrs[i];
 
                                if (vattr->atttypid == sattr->atttypid)
-                                       continue;                       /* no worries */
+                                       continue;       /* no worries */
                                if (!vattr->attisdropped)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -601,7 +615,10 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                }
 
                /* Skip the checking on future executions of node */
-               exprstate->evalfunc = ExecEvalWholeRowVar;
+               if (needslow)
+                       exprstate->evalfunc = ExecEvalWholeRowSlow;
+               else
+                       exprstate->evalfunc = ExecEvalWholeRowVar;
 
                /* Fetch the value */
                return ExecEvalWholeRowVar(exprstate, econtext, isNull, isDone);
@@ -698,6 +715,60 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
        return PointerGetDatum(dtuple);
 }
 
+/* ----------------------------------------------------------------
+ *             ExecEvalWholeRowSlow
+ *
+ *             Returns a Datum for a whole-row variable, in the "slow" case where
+ *             we can't just copy the subplan's output.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
+                                        bool *isNull, ExprDoneCond *isDone)
+{
+       Var                *variable = (Var *) exprstate->expr;
+       TupleTableSlot *slot = econtext->ecxt_scantuple;
+       HeapTuple       tuple;
+       TupleDesc       var_tupdesc;
+       HeapTupleHeader dtuple;
+
+       if (isDone)
+               *isDone = ExprSingleResult;
+       *isNull = false;
+
+       /*
+        * Currently, the only case handled here is stripping of trailing resjunk
+        * fields, which we do in a slightly chintzy way by just adjusting the
+        * tuple's natts header field.  Possibly there will someday be a need for
+        * more-extensive rearrangements, in which case it'd be worth
+        * disassembling and reassembling the tuple (perhaps use a JunkFilter for
+        * that?)
+        */
+       Assert(variable->vartype != RECORDOID);
+       var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
+
+       tuple = ExecFetchSlotTuple(slot);
+
+       /*
+        * We have to make a copy of the tuple so we can safely insert the Datum
+        * overhead fields, which are not set in on-disk tuples; not to mention
+        * fooling with its natts field.
+        */
+       dtuple = (HeapTupleHeader) palloc(tuple->t_len);
+       memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
+
+       HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
+       HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
+       HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
+
+       Assert(HeapTupleHeaderGetNatts(dtuple) >= var_tupdesc->natts);
+       HeapTupleHeaderSetNatts(dtuple, var_tupdesc->natts);
+
+       ReleaseTupleDesc(var_tupdesc);
+
+       return PointerGetDatum(dtuple);
+}
+
 /* ----------------------------------------------------------------
  *             ExecEvalConst
  *
@@ -2506,9 +2577,9 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 
                /*
                 * If all items were null or empty arrays, return an empty array;
-                * otherwise, if some were and some weren't, raise error.  (Note:
-                * we must special-case this somehow to avoid trying to generate
-                * a 1-D array formed from empty arrays.  It's not ideal...)
+                * otherwise, if some were and some weren't, raise error.  (Note: we
+                * must special-case this somehow to avoid trying to generate a 1-D
+                * array formed from empty arrays.      It's not ideal...)
                 */
                if (haveempty)
                {
@@ -2773,17 +2844,17 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+ExecEvalXml(XmlExprState * xmlExpr, ExprContext *econtext,
                        bool *isNull, ExprDoneCond *isDone)
 {
-       XmlExpr            *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
-       text               *result;
-       StringInfoData  buf;
-       Datum                   value;
-       bool                    isnull;
-       ListCell           *arg;
+       XmlExpr    *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
+       text       *result;
+       StringInfoData buf;
+       Datum           value;
+       bool            isnull;
+       ListCell   *arg;
        ListCell   *narg;
-       int                     i;
+       int                     i;
 
        if (isDone)
                *isDone = ExprSingleResult;
@@ -2793,11 +2864,11 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
        {
                case IS_XMLCONCAT:
                        {
-                               List *values = NIL;
+                               List       *values = NIL;
 
                                foreach(arg, xmlExpr->args)
                                {
-                                       ExprState       *e = (ExprState *) lfirst(arg);
+                                       ExprState  *e = (ExprState *) lfirst(arg);
 
                                        value = ExecEvalExpr(e, econtext, &isnull, NULL);
                                        if (!isnull)
@@ -2817,8 +2888,8 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
                        i = 0;
                        forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
                        {
-                               ExprState       *e = (ExprState *) lfirst(arg);
-                               char    *argname = strVal(lfirst(narg));
+                               ExprState  *e = (ExprState *) lfirst(arg);
+                               char       *argname = strVal(lfirst(narg));
 
                                value = ExecEvalExpr(e, econtext, &isnull, NULL);
                                if (!isnull)
@@ -2841,8 +2912,8 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                case IS_XMLPARSE:
                        {
-                               ExprState       *e;
-                               text        *data;
+                               ExprState  *e;
+                               text       *data;
                                bool            preserve_whitespace;
 
                                /* arguments are known to be text, bool */
@@ -2870,8 +2941,8 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                case IS_XMLPI:
                        {
-                               ExprState       *e;
-                               text        *arg;
+                               ExprState  *e;
+                               text       *arg;
 
                                /* optional argument is known to be text */
                                Assert(list_length(xmlExpr->args) <= 1);
@@ -2897,9 +2968,9 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                case IS_XMLROOT:
                        {
-                               ExprState       *e;
-                               xmltype         *data;
-                               text            *version;
+                               ExprState  *e;
+                               xmltype    *data;
+                               text       *version;
                                int                     standalone;
 
                                /* arguments are known to be xml, text, int */
@@ -2932,7 +3003,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                case IS_XMLSERIALIZE:
                        {
-                               ExprState       *e;
+                               ExprState  *e;
 
                                /* argument type is known to be xml */
                                Assert(list_length(xmlExpr->args) == 1);
@@ -2950,7 +3021,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                case IS_DOCUMENT:
                        {
-                               ExprState       *e;
+                               ExprState  *e;
 
                                /* optional argument is known to be xml */
                                Assert(list_length(xmlExpr->args) == 1);
@@ -2972,7 +3043,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
                result = NULL;
        else
        {
-               int             len = buf.len + VARHDRSZ;
+               int                     len = buf.len + VARHDRSZ;
 
                result = palloc(len);
                SET_VARSIZE(result, len);
@@ -3360,9 +3431,9 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
 
        /* Check for dropped column, and force a NULL result if so */
        if (fieldnum <= 0 ||
-               fieldnum > tupDesc->natts)      /* should never happen */
-                               elog(ERROR, "attribute number %d exceeds number of columns %d",
-                                        fieldnum, tupDesc->natts);
+               fieldnum > tupDesc->natts)              /* should never happen */
+               elog(ERROR, "attribute number %d exceeds number of columns %d",
+                        fieldnum, tupDesc->natts);
        attr = tupDesc->attrs[fieldnum - 1];
        if (attr->attisdropped)
        {
@@ -3516,7 +3587,7 @@ ExecEvalRelabelType(GenericExprState *exprstate,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
+ExecEvalCoerceViaIO(CoerceViaIOState * iostate,
                                        ExprContext *econtext,
                                        bool *isNull, ExprDoneCond *isDone)
 {
@@ -3550,7 +3621,7 @@ ExecEvalCoerceViaIO(CoerceViaIOState *iostate,
  * ----------------------------------------------------------------
  */
 static Datum
-ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
+ExecEvalArrayCoerceExpr(ArrayCoerceExprState * astate,
                                                ExprContext *econtext,
                                                bool *isNull, ExprDoneCond *isDone)
 {
@@ -3623,45 +3694,17 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
 /* ----------------------------------------------------------------
  *             ExecEvalCurrentOfExpr
  *
- * Normally, the planner will convert CURRENT OF into a TidScan qualification,
- * but we have plain execQual support in case it doesn't.
+ * The planner must convert CURRENT OF into a TidScan qualification.
+ * So, we have to be able to do ExecInitExpr on a CurrentOfExpr,
+ * but we shouldn't ever actually execute it.
  * ----------------------------------------------------------------
  */
 static Datum
 ExecEvalCurrentOfExpr(ExprState *exprstate, ExprContext *econtext,
                                          bool *isNull, ExprDoneCond *isDone)
 {
-       CurrentOfExpr *cexpr = (CurrentOfExpr *) exprstate->expr;
-       bool    result;
-       bool    lisnull;
-       Oid             tableoid;
-       ItemPointer tuple_tid;
-       ItemPointerData cursor_tid;
-
-       if (isDone)
-               *isDone = ExprSingleResult;
-       *isNull = false;
-
-       Assert(cexpr->cvarno != INNER);
-       Assert(cexpr->cvarno != OUTER);
-       Assert(!TupIsNull(econtext->ecxt_scantuple));
-       /* Use slot_getattr to catch any possible mistakes */
-       tableoid = DatumGetObjectId(slot_getattr(econtext->ecxt_scantuple,
-                                                                                        TableOidAttributeNumber,
-                                                                                        &lisnull));
-       Assert(!lisnull);
-       tuple_tid = (ItemPointer)
-               DatumGetPointer(slot_getattr(econtext->ecxt_scantuple,
-                                                                        SelfItemPointerAttributeNumber,
-                                                                        &lisnull));
-       Assert(!lisnull);
-
-       if (execCurrentOf(cexpr, econtext, tableoid, &cursor_tid))
-               result = ItemPointerEquals(&cursor_tid, tuple_tid);
-       else
-               result = false;
-
-       return BoolGetDatum(result);
+       elog(ERROR, "CURRENT OF cannot be executed");
+       return 0;                                       /* keep compiler quiet */
 }
 
 
@@ -3777,7 +3820,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                        if (naggs != aggstate->numaggs)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_GROUPING_ERROR),
-                                                                errmsg("aggregate function calls cannot be nested")));
+                                               errmsg("aggregate function calls cannot be nested")));
                                }
                                else
                                {
@@ -3937,8 +3980,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
                        {
                                CoerceViaIO *iocoerce = (CoerceViaIO *) node;
                                CoerceViaIOState *iostate = makeNode(CoerceViaIOState);
-                               Oid             iofunc;
-                               bool    typisvarlena;
+                               Oid                     iofunc;
+                               bool            typisvarlena;
 
                                iostate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoerceViaIO;
                                iostate->arg = ExecInitExpr(iocoerce->arg, parent);
@@ -4088,7 +4131,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                                 * don't really care what type of NULL it is, so
                                                 * always make an int4 NULL.
                                                 */
-                                               e = (Expr *) makeNullConst(INT4OID);
+                                               e = (Expr *) makeNullConst(INT4OID, -1);
                                        }
                                        estate = ExecInitExpr(e, parent);
                                        outlist = lappend(outlist, estate);
@@ -4225,11 +4268,11 @@ ExecInitExpr(Expr *node, PlanState *parent)
                        break;
                case T_XmlExpr:
                        {
-                               XmlExpr                 *xexpr = (XmlExpr *) node;
-                               XmlExprState    *xstate = makeNode(XmlExprState);
-                               List                    *outlist;
-                               ListCell                *arg;
-                               int                             i;
+                               XmlExpr    *xexpr = (XmlExpr *) node;
+                               XmlExprState *xstate = makeNode(XmlExprState);
+                               List       *outlist;
+                               ListCell   *arg;
+                               int                     i;
 
                                xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
                                xstate->named_outfuncs = (FmgrInfo *)
@@ -4238,8 +4281,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                i = 0;
                                foreach(arg, xexpr->named_args)
                                {
-                                       Expr            *e = (Expr *) lfirst(arg);
-                                       ExprState       *estate;
+                                       Expr       *e = (Expr *) lfirst(arg);
+                                       ExprState  *estate;
                                        Oid                     typOutFunc;
                                        bool            typIsVarlena;
 
@@ -4256,8 +4299,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                outlist = NIL;
                                foreach(arg, xexpr->args)
                                {
-                                       Expr            *e = (Expr *) lfirst(arg);
-                                       ExprState       *estate;
+                                       Expr       *e = (Expr *) lfirst(arg);
+                                       ExprState  *estate;
 
                                        estate = ExecInitExpr(e, parent);
                                        outlist = lappend(outlist, estate);