]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/execQual.c
Get rid of the separate EState for subplans, and just let them share the
[postgresql] / src / backend / executor / execQual.c
index 1dbef5f15c99628ea625028c801a1d2cb52b1d48..234441c0f6c80cce5e2fccf430062b9647197d58 100644 (file)
@@ -3,12 +3,12 @@
  * execQual.c
  *       Routines to evaluate qualification and targetlist expressions
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.199 2006/11/17 16:46:27 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.214 2007/02/27 01:11:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,6 +52,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/typcache.h"
+#include "utils/xml.h"
 
 
 /* static function decls */
@@ -63,6 +64,8 @@ static Datum ExecEvalAggref(AggrefExprState *aggref,
                           bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                        bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
+                       bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
                                        bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
@@ -116,6 +119,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 ExecEvalNullIf(FuncExprState *nullIfExpr,
                           ExprContext *econtext,
                           bool *isNull, ExprDoneCond *isDone);
@@ -422,6 +427,10 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
  *
  *             Returns a Datum whose value is the value of a range
  *             variable with respect to given expression context.
+ *
+ * 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.
  * ----------------------------------------------------------------
  */
 static Datum
@@ -436,7 +445,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                *isDone = ExprSingleResult;
 
        /*
-        * Get the slot and attribute number we want
+        * Get the input slot and attribute number we want
         *
         * The asserts check that references to system attributes only appear at
         * the level of a relation scan; at higher levels, system attributes must
@@ -463,35 +472,171 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
                        break;
        }
 
-#ifdef USE_ASSERT_CHECKING
-
-       /*
-        * Some checks that are only applied for user attribute numbers (bogus
-        * system attnums will be caught inside slot_getattr).
-        */
-       if (attnum > 0)
+       if (attnum != InvalidAttrNumber)
        {
-               TupleDesc       tuple_type = slot->tts_tupleDescriptor;
-
                /*
-                * This assert checks that the attnum is valid.
+                * 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.
+                *
+                * 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.
                 */
-               Assert(attnum <= tuple_type->natts);
+               if (attnum > 0)
+               {
+                       TupleDesc       slot_tupdesc = slot->tts_tupleDescriptor;
+                       Form_pg_attribute attr;
+
+                       if (attnum > slot_tupdesc->natts)       /* should never happen */
+                               elog(ERROR, "attribute number %d exceeds number of columns %d",
+                                        attnum, slot_tupdesc->natts);
+
+                       attr = slot_tupdesc->attrs[attnum - 1];
+
+                       /* can't check type if dropped, since atttypid is probably 0 */
+                       if (!attr->attisdropped)
+                       {
+                               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))));
+                       }
+               }
 
+               /* Skip the checking on future executions of node */
+               exprstate->evalfunc = ExecEvalScalarVar;
+
+               /* Fetch the value from the slot */
+               return slot_getattr(slot, attnum, isNull);
+       }
+       else
+       {
                /*
-                * This assert checks that the datatype the plan expects to get (as
-                * told by our "variable" argument) is in fact the datatype of the
-                * attribute being fetched (as seen in the current context, identified
-                * by our "econtext" argument).  Otherwise crashes are likely.
+                * Whole-row variable.
                 *
-                * Note that we can't check dropped columns, since their atttypid has
-                * been zeroed.
+                * If it's a RECORD Var, we'll use the slot's type ID info.  It's
+                * likely that the slot's type is also RECORD; if so, make sure it's
+                * been "blessed", so that the Datum can be interpreted later.
+                *
+                * If the Var identifies a named composite type, we must check that
+                * the actual tuple type is compatible with it.
                 */
-               Assert(variable->vartype == tuple_type->attrs[attnum - 1]->atttypid ||
-                          tuple_type->attrs[attnum - 1]->attisdropped);
+               TupleDesc       slot_tupdesc = slot->tts_tupleDescriptor;
+
+               if (variable->vartype == RECORDOID)
+               {
+                       if (slot_tupdesc->tdtypeid == RECORDOID &&
+                               slot_tupdesc->tdtypmod < 0)
+                               assign_record_type_typmod(slot_tupdesc);
+               }
+               else
+               {
+                       TupleDesc       var_tupdesc;
+                       int                     i;
+
+                       /*
+                        * We really only care about number of attributes and data type.
+                        * 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.
+                        */
+                       var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
+
+                       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)));
+
+                       for (i = 0; i < var_tupdesc->natts; i++)
+                       {
+                               Form_pg_attribute vattr = var_tupdesc->attrs[i];
+                               Form_pg_attribute sattr = slot_tupdesc->attrs[i];
+
+                               if (vattr->atttypid == sattr->atttypid)
+                                       continue;                       /* no worries */
+                               if (!vattr->attisdropped)
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                        errmsg("table row type and query-specified row type do not match"),
+                                                        errdetail("Table has type %s at ordinal position %d, but query expects %s.",
+                                                                          format_type_be(sattr->atttypid),
+                                                                          i + 1,
+                                                                          format_type_be(vattr->atttypid))));
+
+                               if (vattr->attlen != sattr->attlen ||
+                                       vattr->attalign != sattr->attalign)
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                        errmsg("table row type and query-specified row type do not match"),
+                                                        errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
+                                                                          i + 1)));
+                       }
+
+                       ReleaseTupleDesc(var_tupdesc);
+               }
+
+               /* Skip the checking on future executions of node */
+               exprstate->evalfunc = ExecEvalWholeRowVar;
+
+               /* Fetch the value */
+               return ExecEvalWholeRowVar(exprstate, econtext, isNull, isDone);
        }
-#endif   /* USE_ASSERT_CHECKING */
+}
 
+/* ----------------------------------------------------------------
+ *             ExecEvalScalarVar
+ *
+ *             Returns a Datum for a scalar variable.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
+                                 bool *isNull, ExprDoneCond *isDone)
+{
+       Var                *variable = (Var *) exprstate->expr;
+       TupleTableSlot *slot;
+       AttrNumber      attnum;
+
+       if (isDone)
+               *isDone = ExprSingleResult;
+
+       /* Get the input slot and attribute number we want */
+       switch (variable->varno)
+       {
+               case INNER:                             /* get the tuple from the inner node */
+                       slot = econtext->ecxt_innertuple;
+                       break;
+
+               case OUTER:                             /* get the tuple from the outer node */
+                       slot = econtext->ecxt_outertuple;
+                       break;
+
+               default:                                /* get the tuple from the relation being
+                                                                * scanned */
+                       slot = econtext->ecxt_scantuple;
+                       break;
+       }
+
+       attnum = variable->varattno;
+
+       /* Fetch the value from the slot */
        return slot_getattr(slot, attnum, isNull);
 }
 
@@ -499,10 +644,6 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
  *             ExecEvalWholeRowVar
  *
  *             Returns a Datum for a whole-row variable.
- *
- *             This could be folded into ExecEvalVar, but we make it a separate
- *             routine so as not to slow down ExecEvalVar with tests for this
- *             uncommon case.
  * ----------------------------------------------------------------
  */
 static Datum
@@ -510,7 +651,7 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
                                        bool *isNull, ExprDoneCond *isDone)
 {
        Var                *variable = (Var *) exprstate->expr;
-       TupleTableSlot *slot;
+       TupleTableSlot *slot = econtext->ecxt_scantuple;
        HeapTuple       tuple;
        TupleDesc       tupleDesc;
        HeapTupleHeader dtuple;
@@ -519,16 +660,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
                *isDone = ExprSingleResult;
        *isNull = false;
 
-       Assert(variable->varattno == InvalidAttrNumber);
-
-       /*
-        * Whole-row Vars can only appear at the level of a relation scan, never
-        * in a join.
-        */
-       Assert(variable->varno != INNER);
-       Assert(variable->varno != OUTER);
-       slot = econtext->ecxt_scantuple;
-
        tuple = ExecFetchSlotTuple(slot);
        tupleDesc = slot->tts_tupleDescriptor;
 
@@ -544,9 +675,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
        /*
         * If the Var identifies a named composite type, label the tuple with that
         * type; otherwise use what is in the tupleDesc.
-        *
-        * It's likely that the slot's tupleDesc is a record type; if so, make
-        * sure it's been "blessed", so that the Datum can be interpreted later.
         */
        if (variable->vartype != RECORDOID)
        {
@@ -555,9 +683,6 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
        }
        else
        {
-               if (tupleDesc->tdtypeid == RECORDOID &&
-                       tupleDesc->tdtypmod < 0)
-                       assign_record_type_typmod(tupleDesc);
                HeapTupleHeaderSetTypeId(dtuple, tupleDesc->tdtypeid);
                HeapTupleHeaderSetTypMod(dtuple, tupleDesc->tdtypmod);
        }
@@ -2635,6 +2760,221 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
        return result;
 }
 
+/* ----------------------------------------------------------------
+ *             ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+static Datum
+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;
+       ListCell   *narg;
+       int                     i;
+
+       if (isDone)
+               *isDone = ExprSingleResult;
+       *isNull = true;                         /* until we get a result */
+
+       switch (xexpr->op)
+       {
+               case IS_XMLCONCAT:
+                       {
+                               List *values = NIL;
+
+                               foreach(arg, xmlExpr->args)
+                               {
+                                       ExprState       *e = (ExprState *) lfirst(arg);
+
+                                       value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                                       if (!isnull)
+                                               values = lappend(values, DatumGetPointer(value));
+                               }
+
+                               if (list_length(values) > 0)
+                               {
+                                       *isNull = false;
+                                       return PointerGetDatum(xmlconcat(values));
+                               }
+                       }
+                       break;
+
+               case IS_XMLFOREST:
+                       initStringInfo(&buf);
+                       i = 0;
+                       forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+                       {
+                               ExprState       *e = (ExprState *) lfirst(arg);
+                               char    *argname = strVal(lfirst(narg));
+
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (!isnull)
+                               {
+                                       appendStringInfo(&buf, "<%s>%s</%s>",
+                                                                        argname,
+                                                                        map_sql_value_to_xml_value(value, exprType((Node *) e->expr)),
+                                                                        argname);
+                                       *isNull = false;
+                               }
+                               i++;
+                       }
+                       break;
+
+                       /* The remaining cases don't need to set up buf */
+               case IS_XMLELEMENT:
+                       *isNull = false;
+                       return PointerGetDatum(xmlelement(xmlExpr, econtext));
+                       break;
+
+               case IS_XMLPARSE:
+                       {
+                               ExprState       *e;
+                               text        *data;
+                               bool            preserve_whitespace;
+
+                               /* arguments are known to be text, bool */
+                               Assert(list_length(xmlExpr->args) == 2);
+
+                               e = (ExprState *) linitial(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)
+                                       return (Datum) 0;
+                               data = DatumGetTextP(value);
+
+                               e = (ExprState *) lsecond(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)             /* probably can't happen */
+                                       return (Datum) 0;
+                               preserve_whitespace = DatumGetBool(value);
+
+                               *isNull = false;
+
+                               return PointerGetDatum(xmlparse(data,
+                                                                                               xexpr->xmloption,
+                                                                                               preserve_whitespace));
+                       }
+                       break;
+
+               case IS_XMLPI:
+                       {
+                               ExprState       *e;
+                               text        *arg;
+
+                               /* optional argument is known to be text */
+                               Assert(list_length(xmlExpr->args) <= 1);
+
+                               if (xmlExpr->args)
+                               {
+                                       e = (ExprState *) linitial(xmlExpr->args);
+                                       value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                                       if (isnull)
+                                               arg = NULL;
+                                       else
+                                               arg = DatumGetTextP(value);
+                               }
+                               else
+                               {
+                                       arg = NULL;
+                                       isnull = false;
+                               }
+
+                               return PointerGetDatum(xmlpi(xexpr->name, arg, isnull, isNull));
+                       }
+                       break;
+
+               case IS_XMLROOT:
+                       {
+                               ExprState       *e;
+                               xmltype         *data;
+                               text            *version;
+                               int                     standalone;
+
+                               /* arguments are known to be xml, text, int */
+                               Assert(list_length(xmlExpr->args) == 3);
+
+                               e = (ExprState *) linitial(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)
+                                       return (Datum) 0;
+                               data = DatumGetXmlP(value);
+
+                               e = (ExprState *) lsecond(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)
+                                       version = NULL;
+                               else
+                                       version = DatumGetTextP(value);
+
+                               e = (ExprState *) lthird(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               standalone = DatumGetInt32(value);
+
+                               *isNull = false;
+
+                               return PointerGetDatum(xmlroot(data,
+                                                                                          version,
+                                                                                          standalone));
+                       }
+                       break;
+
+               case IS_XMLSERIALIZE:
+                       {
+                               ExprState       *e;
+
+                               /* argument type is known to be xml */
+                               Assert(list_length(xmlExpr->args) == 1);
+
+                               e = (ExprState *) linitial(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)
+                                       return (Datum) 0;
+
+                               *isNull = false;
+
+                               return PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value), xexpr->xmloption));
+                       }
+                       break;
+
+               case IS_DOCUMENT:
+                       {
+                               ExprState       *e;
+
+                               /* optional argument is known to be xml */
+                               Assert(list_length(xmlExpr->args) == 1);
+
+                               e = (ExprState *) linitial(xmlExpr->args);
+                               value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                               if (isnull)
+                                       return (Datum) 0;
+                               else
+                               {
+                                       *isNull = false;
+                                       return BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
+                               }
+                       }
+                       break;
+       }
+
+       if (*isNull)
+               result = NULL;
+       else
+       {
+               int             len = buf.len + VARHDRSZ;
+
+               result = palloc(len);
+               VARATT_SIZEP(result) = len;
+               memcpy(VARDATA(result), buf.data, buf.len);
+       }
+
+       pfree(buf.data);
+       return PointerGetDatum(result);
+}
+
 /* ----------------------------------------------------------------
  *             ExecEvalNullIf
  *
@@ -2985,12 +3325,14 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
                                        ExprDoneCond *isDone)
 {
        FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr;
+       AttrNumber      fieldnum = fselect->fieldnum;
        Datum           result;
        Datum           tupDatum;
        HeapTupleHeader tuple;
        Oid                     tupType;
        int32           tupTypmod;
        TupleDesc       tupDesc;
+       Form_pg_attribute attr;
        HeapTupleData tmptup;
 
        tupDatum = ExecEvalExpr(fstate->arg, econtext, isNull, isDone);
@@ -3008,6 +3350,27 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
        tupDesc = get_cached_rowtype(tupType, tupTypmod,
                                                                 &fstate->argdesc, econtext);
 
+       /* 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);
+       attr = tupDesc->attrs[fieldnum - 1];
+       if (attr->attisdropped)
+       {
+               *isNull = true;
+               return (Datum) 0;
+       }
+
+       /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
+       /* As in ExecEvalVar, we should but can't check typmod */
+       if (fselect->resulttype != attr->atttypid)
+               ereport(ERROR,
+                               (errmsg("attribute %d has wrong type", fieldnum),
+                                errdetail("Table has type %s, but query expects %s.",
+                                                  format_type_be(attr->atttypid),
+                                                  format_type_be(fselect->resulttype))));
+
        /*
         * heap_getattr needs a HeapTuple not a bare HeapTupleHeader.  We set all
         * the fields in the struct just in case user tries to inspect system
@@ -3019,7 +3382,7 @@ ExecEvalFieldSelect(FieldSelectState *fstate,
        tmptup.t_data = tuple;
 
        result = heap_getattr(&tmptup,
-                                                 fselect->fieldnum,
+                                                 fieldnum,
                                                  tupDesc,
                                                  isNull);
        return result;
@@ -3206,15 +3569,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
        switch (nodeTag(node))
        {
                case T_Var:
-                       {
-                               Var                *var = (Var *) node;
-
-                               state = (ExprState *) makeNode(ExprState);
-                               if (var->varattno != InvalidAttrNumber)
-                                       state->evalfunc = ExecEvalVar;
-                               else
-                                       state->evalfunc = ExecEvalWholeRowVar;
-                       }
+                       state = (ExprState *) makeNode(ExprState);
+                       state->evalfunc = ExecEvalVar;
                        break;
                case T_Const:
                        state = (ExprState *) makeNode(ExprState);
@@ -3258,7 +3614,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                        if (naggs != aggstate->numaggs)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_GROUPING_ERROR),
-                                                                errmsg("aggregate function calls may not be nested")));
+                                                                errmsg("aggregate function calls cannot be nested")));
                                }
                                else
                                {
@@ -3367,27 +3723,16 @@ ExecInitExpr(Expr *node, PlanState *parent)
                        break;
                case T_SubPlan:
                        {
-                               /* Keep this in sync with ExecInitExprInitPlan, below */
                                SubPlan    *subplan = (SubPlan *) node;
-                               SubPlanState *sstate = makeNode(SubPlanState);
-
-                               sstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecSubPlan;
+                               SubPlanState *sstate;
 
                                if (!parent)
                                        elog(ERROR, "SubPlan found with no parent plan");
 
-                               /*
-                                * Here we just add the SubPlanState nodes to parent->subPlan.
-                                * The subplans will be initialized later.
-                                */
-                               parent->subPlan = lcons(sstate, parent->subPlan);
-                               sstate->sub_estate = NULL;
-                               sstate->planstate = NULL;
+                               sstate = ExecInitSubPlan(subplan, parent);
 
-                               sstate->testexpr =
-                                       ExecInitExpr((Expr *) subplan->testexpr, parent);
-                               sstate->args = (List *)
-                                       ExecInitExpr((Expr *) subplan->args, parent);
+                               /* Add SubPlanState nodes to parent->subPlan */
+                               parent->subPlan = lcons(sstate, parent->subPlan);
 
                                state = (ExprState *) sstate;
                        }
@@ -3583,21 +3928,28 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                        outlist = lappend(outlist, estate);
                                }
                                rstate->rargs = outlist;
-                               Assert(list_length(rcexpr->opclasses) == nopers);
+                               Assert(list_length(rcexpr->opfamilies) == nopers);
                                rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
                                i = 0;
-                               forboth(l, rcexpr->opnos, l2, rcexpr->opclasses)
+                               forboth(l, rcexpr->opnos, l2, rcexpr->opfamilies)
                                {
                                        Oid                     opno = lfirst_oid(l);
-                                       Oid                     opclass = lfirst_oid(l2);
+                                       Oid                     opfamily = lfirst_oid(l2);
                                        int                     strategy;
-                                       Oid                     subtype;
+                                       Oid                     lefttype;
+                                       Oid                     righttype;
                                        bool            recheck;
                                        Oid                     proc;
 
-                                       get_op_opclass_properties(opno, opclass,
-                                                                                         &strategy, &subtype, &recheck);
-                                       proc = get_opclass_proc(opclass, subtype, BTORDER_PROC);
+                                       get_op_opfamily_properties(opno, opfamily,
+                                                                                          &strategy,
+                                                                                          &lefttype,
+                                                                                          &righttype,
+                                                                                          &recheck);
+                                       proc = get_opfamily_proc(opfamily,
+                                                                                        lefttype,
+                                                                                        righttype,
+                                                                                        BTORDER_PROC);
 
                                        /*
                                         * If we enforced permissions checks on index support
@@ -3668,6 +4020,50 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                state = (ExprState *) mstate;
                        }
                        break;
+               case T_XmlExpr:
+                       {
+                               XmlExpr                 *xexpr = (XmlExpr *) node;
+                               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;
+
+                               outlist = NIL;
+                               foreach(arg, xexpr->args)
+                               {
+                                       Expr            *e = (Expr *) lfirst(arg);
+                                       ExprState       *estate;
+
+                                       estate = ExecInitExpr(e, parent);
+                                       outlist = lappend(outlist, estate);
+                               }
+                               xstate->args = outlist;
+
+                               state = (ExprState *) xstate;
+                       }
+                       break;
                case T_NullIfExpr:
                        {
                                NullIfExpr *nullifexpr = (NullIfExpr *) node;
@@ -3750,32 +4146,6 @@ ExecInitExpr(Expr *node, PlanState *parent)
        return state;
 }
 
-/*
- * ExecInitExprInitPlan --- initialize a subplan expr that's being handled
- * as an InitPlan.     This is identical to ExecInitExpr's handling of a regular
- * subplan expr, except we do NOT want to add the node to the parent's
- * subplan list.
- */
-SubPlanState *
-ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
-{
-       SubPlanState *sstate = makeNode(SubPlanState);
-
-       if (!parent)
-               elog(ERROR, "SubPlan found with no parent plan");
-
-       /* The subplan's state will be initialized later */
-       sstate->sub_estate = NULL;
-       sstate->planstate = NULL;
-
-       sstate->testexpr = ExecInitExpr((Expr *) node->testexpr, parent);
-       sstate->args = (List *) ExecInitExpr((Expr *) node->args, parent);
-
-       sstate->xprstate.expr = (Expr *) node;
-
-       return sstate;
-}
-
 /*
  * ExecPrepareExpr --- initialize for expression execution outside a normal
  * Plan tree context.